@agentforge/patterns 0.6.3 → 0.6.4

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
@@ -71,11 +71,14 @@ __export(index_exports, {
71
71
  ToolCallSchema: () => ToolCallSchema,
72
72
  ToolResultSchema: () => ToolResultSchema,
73
73
  WorkerCapabilitiesSchema: () => WorkerCapabilitiesSchema,
74
+ buildDeduplicationMetrics: () => buildDeduplicationMetrics,
75
+ calculateDeduplicationSavings: () => calculateDeduplicationSavings,
74
76
  createAggregatorNode: () => createAggregatorNode,
75
77
  createExecutorNode: () => createExecutorNode,
76
78
  createFinisherNode: () => createFinisherNode,
77
79
  createGeneratorNode: () => createGeneratorNode,
78
80
  createMultiAgentSystem: () => createMultiAgentSystem,
81
+ createPatternLogger: () => createPatternLogger,
79
82
  createPlanExecuteAgent: () => createPlanExecuteAgent,
80
83
  createPlannerNode: () => createPlannerNode,
81
84
  createReActAgent: () => createReActAgent,
@@ -87,6 +90,7 @@ __export(index_exports, {
87
90
  createReviserNode: () => createReviserNode,
88
91
  createSupervisorNode: () => createSupervisorNode,
89
92
  createWorkerNode: () => createWorkerNode,
93
+ generateToolCallCacheKey: () => generateToolCallCacheKey,
90
94
  getRoutingStrategy: () => getRoutingStrategy,
91
95
  llmBasedRouting: () => llmBasedRouting,
92
96
  loadBalancedRouting: () => loadBalancedRouting,
@@ -121,7 +125,9 @@ var ToolResultSchema = import_zod.z.object({
121
125
  toolCallId: import_zod.z.string(),
122
126
  result: import_zod.z.any(),
123
127
  error: import_zod.z.string().optional(),
124
- timestamp: import_zod.z.number().optional()
128
+ timestamp: import_zod.z.number().optional(),
129
+ isDuplicate: import_zod.z.boolean().optional()
130
+ // Flag indicating this was a duplicate tool call
125
131
  });
126
132
  var ScratchpadEntrySchema = import_zod.z.object({
127
133
  step: import_zod.z.number(),
@@ -245,14 +251,50 @@ function formatScratchpad(scratchpad) {
245
251
 
246
252
  // src/react/nodes.ts
247
253
  var import_messages = require("@langchain/core/messages");
254
+ var import_core3 = require("@agentforge/core");
255
+
256
+ // src/shared/deduplication.ts
248
257
  var import_core2 = require("@agentforge/core");
258
+ function generateToolCallCacheKey(toolName, args) {
259
+ const sortedArgs = JSON.stringify(args, Object.keys(args || {}).sort());
260
+ return `${toolName}:${sortedArgs}`;
261
+ }
262
+ function createPatternLogger(name, defaultLevel = "info") {
263
+ const logLevel5 = process.env.LOG_LEVEL?.toLowerCase() || defaultLevel;
264
+ return (0, import_core2.createLogger)(name, { level: logLevel5 });
265
+ }
266
+ function calculateDeduplicationSavings(duplicatesSkipped, toolsExecuted) {
267
+ if (duplicatesSkipped === 0) {
268
+ return "0%";
269
+ }
270
+ const total = toolsExecuted + duplicatesSkipped;
271
+ return `${Math.round(duplicatesSkipped / total * 100)}%`;
272
+ }
273
+ function buildDeduplicationMetrics(toolsExecuted, duplicatesSkipped, totalObservations) {
274
+ return {
275
+ toolsExecuted,
276
+ duplicatesSkipped,
277
+ totalObservations,
278
+ deduplicationSavings: calculateDeduplicationSavings(duplicatesSkipped, toolsExecuted)
279
+ };
280
+ }
281
+
282
+ // src/react/nodes.ts
283
+ var reasoningLogger = createPatternLogger("agentforge:patterns:react:reasoning");
284
+ var actionLogger = createPatternLogger("agentforge:patterns:react:action");
285
+ var observationLogger = createPatternLogger("agentforge:patterns:react:observation");
249
286
  function createReasoningNode(llm, tools, systemPrompt, maxIterations, verbose = false) {
250
- const langchainTools = (0, import_core2.toLangChainTools)(tools);
287
+ const langchainTools = (0, import_core3.toLangChainTools)(tools);
251
288
  const llmWithTools = llm.bindTools ? llm.bindTools(langchainTools) : llm;
252
289
  return async (state) => {
253
- if (verbose) {
254
- console.log(`[reasoning] Iteration ${state.iteration + 1}/${maxIterations}`);
255
- }
290
+ const currentIteration = state.iteration || 0;
291
+ const startTime = Date.now();
292
+ reasoningLogger.debug("Reasoning iteration started", {
293
+ iteration: currentIteration + 1,
294
+ maxIterations,
295
+ observationCount: state.observations?.length || 0,
296
+ hasActions: !!state.actions?.length
297
+ });
256
298
  const stateMessages = state.messages || [];
257
299
  const messages = [
258
300
  new import_messages.SystemMessage(systemPrompt),
@@ -282,8 +324,15 @@ ${scratchpadText}`));
282
324
  });
283
325
  }
284
326
  }
285
- const currentIteration = state.iteration || 0;
286
327
  const shouldContinue = toolCalls.length > 0 && currentIteration + 1 < maxIterations;
328
+ reasoningLogger.info("Reasoning complete", {
329
+ iteration: currentIteration + 1,
330
+ thoughtGenerated: !!thought,
331
+ actionCount: toolCalls.length,
332
+ shouldContinue,
333
+ isFinalResponse: toolCalls.length === 0,
334
+ duration: Date.now() - startTime
335
+ });
287
336
  return {
288
337
  messages: [{ role: "assistant", content: thought }],
289
338
  thoughts: thought ? [{ content: thought, timestamp: Date.now() }] : [],
@@ -296,16 +345,71 @@ ${scratchpadText}`));
296
345
  };
297
346
  };
298
347
  }
299
- function createActionNode(tools, verbose = false) {
348
+ function createActionNode(tools, verbose = false, enableDeduplication = true) {
300
349
  const toolMap = new Map(tools.map((tool) => [tool.metadata.name, tool]));
301
350
  return async (state) => {
302
351
  const actions = state.actions || [];
303
- if (verbose) {
304
- console.log(`[action] Executing ${actions.length} tool calls`);
305
- }
352
+ const allObservations = state.observations || [];
353
+ const iteration = state.iteration || 0;
354
+ const startTime = Date.now();
355
+ actionLogger.debug("Action node started", {
356
+ actionCount: actions.length,
357
+ iteration,
358
+ cacheEnabled: enableDeduplication
359
+ });
306
360
  const recentActions = actions.slice(-10);
307
361
  const observations = [];
362
+ const executionCache = /* @__PURE__ */ new Map();
363
+ let cacheSize = 0;
364
+ if (enableDeduplication) {
365
+ for (const observation of allObservations) {
366
+ const correspondingAction = actions.find((a) => a.id === observation.toolCallId);
367
+ if (correspondingAction) {
368
+ const cacheKey = generateToolCallCacheKey(correspondingAction.name, correspondingAction.arguments);
369
+ executionCache.set(cacheKey, observation);
370
+ cacheSize++;
371
+ }
372
+ }
373
+ if (cacheSize > 0) {
374
+ actionLogger.debug("Deduplication cache built", {
375
+ cacheSize,
376
+ totalObservations: allObservations.length
377
+ });
378
+ }
379
+ }
380
+ let duplicatesSkipped = 0;
381
+ let toolsExecuted = 0;
308
382
  for (const action of recentActions) {
383
+ const existingObservation = allObservations.find((obs) => obs.toolCallId === action.id);
384
+ if (existingObservation) {
385
+ actionLogger.debug("Skipping already-processed action", {
386
+ toolName: action.name,
387
+ toolCallId: action.id,
388
+ iteration
389
+ });
390
+ continue;
391
+ }
392
+ if (enableDeduplication) {
393
+ const cacheKey = generateToolCallCacheKey(action.name, action.arguments);
394
+ const cachedResult = executionCache.get(cacheKey);
395
+ if (cachedResult) {
396
+ duplicatesSkipped++;
397
+ actionLogger.info("Duplicate tool call prevented", {
398
+ toolName: action.name,
399
+ arguments: action.arguments,
400
+ iteration,
401
+ cacheHit: true
402
+ });
403
+ observations.push({
404
+ toolCallId: action.id,
405
+ result: cachedResult.result,
406
+ error: cachedResult.error,
407
+ timestamp: Date.now(),
408
+ isDuplicate: true
409
+ });
410
+ continue;
411
+ }
412
+ }
309
413
  const tool = toolMap.get(action.name);
310
414
  if (!tool) {
311
415
  observations.push({
@@ -317,31 +421,51 @@ function createActionNode(tools, verbose = false) {
317
421
  continue;
318
422
  }
319
423
  try {
424
+ const startTime2 = Date.now();
320
425
  const result = await tool.execute(action.arguments);
321
- observations.push({
426
+ const executionTime = Date.now() - startTime2;
427
+ toolsExecuted++;
428
+ actionLogger.debug("Tool executed successfully", {
429
+ toolName: action.name,
430
+ executionTime,
431
+ iteration
432
+ });
433
+ const observation = {
322
434
  toolCallId: action.id,
323
435
  result,
324
436
  timestamp: Date.now()
325
- });
326
- if (verbose) {
327
- console.log(`[action] Tool '${action.name}' executed successfully`);
437
+ };
438
+ observations.push(observation);
439
+ if (enableDeduplication) {
440
+ const cacheKey = generateToolCallCacheKey(action.name, action.arguments);
441
+ executionCache.set(cacheKey, observation);
328
442
  }
329
443
  } catch (error) {
330
444
  if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
331
445
  throw error;
332
446
  }
333
447
  const errorMessage = error instanceof Error ? error.message : String(error);
448
+ actionLogger.error("Tool execution failed", {
449
+ toolName: action.name,
450
+ error: errorMessage,
451
+ iteration
452
+ });
334
453
  observations.push({
335
454
  toolCallId: action.id,
336
455
  result: null,
337
456
  error: errorMessage,
338
457
  timestamp: Date.now()
339
458
  });
340
- if (verbose) {
341
- console.error(`[action] Tool '${action.name}' failed:`, errorMessage);
342
- }
343
459
  }
344
460
  }
461
+ if (duplicatesSkipped > 0 || toolsExecuted > 0) {
462
+ const metrics = buildDeduplicationMetrics(toolsExecuted, duplicatesSkipped, observations.length);
463
+ actionLogger.info("Action node complete", {
464
+ iteration,
465
+ ...metrics,
466
+ duration: Date.now() - startTime
467
+ });
468
+ }
345
469
  return {
346
470
  observations
347
471
  };
@@ -352,9 +476,11 @@ function createObservationNode(verbose = false) {
352
476
  const observations = state.observations || [];
353
477
  const thoughts = state.thoughts || [];
354
478
  const actions = state.actions || [];
355
- if (verbose) {
356
- console.log(`[observation] Processing ${observations.length} observations`);
357
- }
479
+ const iteration = state.iteration || 0;
480
+ observationLogger.debug("Processing observations", {
481
+ observationCount: observations.length,
482
+ iteration
483
+ });
358
484
  const recentObservations = observations.slice(-10);
359
485
  const currentStep = state.iteration;
360
486
  const latestThought = thoughts[thoughts.length - 1]?.content || "";
@@ -380,6 +506,11 @@ function createObservationNode(verbose = false) {
380
506
  name: latestActions.find((a) => a.id === obs.toolCallId)?.name
381
507
  };
382
508
  });
509
+ observationLogger.debug("Observation node complete", {
510
+ iteration,
511
+ scratchpadUpdated: true,
512
+ messageCount: observationMessages.length
513
+ });
383
514
  return {
384
515
  scratchpad: [scratchpadEntry],
385
516
  messages: observationMessages
@@ -389,7 +520,7 @@ function createObservationNode(verbose = false) {
389
520
 
390
521
  // src/react/agent.ts
391
522
  var import_langgraph = require("@langchain/langgraph");
392
- var import_core3 = require("@agentforge/core");
523
+ var import_core4 = require("@agentforge/core");
393
524
  function createReActAgent(config, options) {
394
525
  const {
395
526
  model,
@@ -398,13 +529,15 @@ function createReActAgent(config, options) {
398
529
  maxIterations = 10,
399
530
  returnIntermediateSteps = false,
400
531
  stopCondition,
401
- checkpointer
532
+ checkpointer,
533
+ enableDeduplication = true
534
+ // Enable by default
402
535
  } = config;
403
536
  const {
404
537
  verbose = false,
405
538
  nodeNames = {}
406
539
  } = options || {};
407
- const toolArray = tools instanceof import_core3.ToolRegistry ? tools.getAll() : tools;
540
+ const toolArray = tools instanceof import_core4.ToolRegistry ? tools.getAll() : tools;
408
541
  const REASONING_NODE = nodeNames.reasoning || "reasoning";
409
542
  const ACTION_NODE = nodeNames.action || "action";
410
543
  const OBSERVATION_NODE = nodeNames.observation || "observation";
@@ -415,7 +548,7 @@ function createReActAgent(config, options) {
415
548
  maxIterations,
416
549
  verbose
417
550
  );
418
- const actionNode = createActionNode(toolArray, verbose);
551
+ const actionNode = createActionNode(toolArray, verbose, enableDeduplication);
419
552
  const observationNode = createObservationNode(verbose);
420
553
  const shouldContinue = (state) => {
421
554
  if (stopCondition && stopCondition(state)) {
@@ -551,7 +684,7 @@ var import_langgraph2 = require("@langchain/langgraph");
551
684
 
552
685
  // src/plan-execute/state.ts
553
686
  var import_zod4 = require("zod");
554
- var import_core4 = require("@agentforge/core");
687
+ var import_core5 = require("@agentforge/core");
555
688
 
556
689
  // src/plan-execute/schemas.ts
557
690
  var import_zod3 = require("zod");
@@ -713,7 +846,7 @@ var PlanExecuteStateConfig = {
713
846
  description: "Maximum number of planning iterations allowed"
714
847
  }
715
848
  };
716
- var PlanExecuteState = (0, import_core4.createStateAnnotation)(PlanExecuteStateConfig);
849
+ var PlanExecuteState = (0, import_core5.createStateAnnotation)(PlanExecuteStateConfig);
717
850
 
718
851
  // src/plan-execute/nodes.ts
719
852
  var import_messages2 = require("@langchain/core/messages");
@@ -778,6 +911,9 @@ var REMAINING_STEP_TEMPLATE = `Step {stepNumber}: {description}
778
911
  {dependencies}`;
779
912
 
780
913
  // src/plan-execute/nodes.ts
914
+ var plannerLogger = createPatternLogger("agentforge:patterns:plan-execute:planner");
915
+ var executorLogger = createPatternLogger("agentforge:patterns:plan-execute:executor");
916
+ var replannerLogger = createPatternLogger("agentforge:patterns:plan-execute:replanner");
781
917
  function createPlannerNode(config) {
782
918
  const {
783
919
  model,
@@ -786,7 +922,13 @@ function createPlannerNode(config) {
786
922
  includeToolDescriptions = false
787
923
  } = config;
788
924
  return async (state) => {
925
+ const startTime = Date.now();
789
926
  try {
927
+ plannerLogger.debug("Planning started", {
928
+ input: state.input?.substring(0, 100),
929
+ maxSteps,
930
+ includeToolDescriptions
931
+ });
790
932
  let toolDescriptions = "";
791
933
  if (includeToolDescriptions) {
792
934
  toolDescriptions = "";
@@ -811,6 +953,12 @@ function createPlannerNode(config) {
811
953
  } catch (parseError) {
812
954
  throw new Error(`Failed to parse plan from LLM response: ${parseError}`);
813
955
  }
956
+ plannerLogger.info("Plan created", {
957
+ stepCount: plan.steps.length,
958
+ goal: plan.goal.substring(0, 100),
959
+ confidence: plan.confidence,
960
+ duration: Date.now() - startTime
961
+ });
814
962
  return {
815
963
  plan,
816
964
  status: "executing",
@@ -818,6 +966,10 @@ function createPlannerNode(config) {
818
966
  iteration: 1
819
967
  };
820
968
  } catch (error) {
969
+ plannerLogger.error("Planning failed", {
970
+ error: error instanceof Error ? error.message : String(error),
971
+ duration: Date.now() - startTime
972
+ });
821
973
  return {
822
974
  status: "failed",
823
975
  error: error instanceof Error ? error.message : "Unknown error in planner"
@@ -830,11 +982,18 @@ function createExecutorNode(config) {
830
982
  tools,
831
983
  model,
832
984
  parallel = false,
833
- stepTimeout = 3e4
985
+ stepTimeout = 3e4,
986
+ enableDeduplication = true
834
987
  } = config;
835
988
  return async (state) => {
989
+ const { plan, currentStepIndex = 0, pastSteps = [], iteration = 0 } = state;
836
990
  try {
837
- const { plan, currentStepIndex = 0, pastSteps = [] } = state;
991
+ executorLogger.debug("Executor node executing", {
992
+ currentStepIndex,
993
+ totalSteps: plan?.steps?.length || 0,
994
+ iteration,
995
+ deduplicationEnabled: enableDeduplication
996
+ });
838
997
  if (!plan || !plan.steps || plan.steps.length === 0) {
839
998
  return {
840
999
  status: "completed"
@@ -853,22 +1012,67 @@ function createExecutorNode(config) {
853
1012
  throw new Error(`Unmet dependencies for step ${currentStep.id}: ${unmetDependencies.join(", ")}`);
854
1013
  }
855
1014
  }
1015
+ const executionCache = /* @__PURE__ */ new Map();
1016
+ let cacheSize = 0;
1017
+ if (enableDeduplication && currentStep.tool) {
1018
+ for (const pastStep of pastSteps) {
1019
+ if (pastStep.step.tool) {
1020
+ const cacheKey = generateToolCallCacheKey(pastStep.step.tool, pastStep.step.args || {});
1021
+ executionCache.set(cacheKey, pastStep);
1022
+ cacheSize++;
1023
+ }
1024
+ }
1025
+ if (cacheSize > 0) {
1026
+ executorLogger.debug("Deduplication cache built", {
1027
+ cacheSize,
1028
+ pastStepsCount: pastSteps.length
1029
+ });
1030
+ }
1031
+ }
856
1032
  let result;
857
1033
  let success = true;
858
1034
  let error;
1035
+ let isDuplicate = false;
859
1036
  try {
860
1037
  if (currentStep.tool) {
861
- const tool = tools.find((t) => t.metadata.name === currentStep.tool);
862
- if (!tool) {
863
- throw new Error(`Tool not found: ${currentStep.tool}`);
1038
+ if (enableDeduplication) {
1039
+ const cacheKey = generateToolCallCacheKey(currentStep.tool, currentStep.args || {});
1040
+ const cachedStep = executionCache.get(cacheKey);
1041
+ if (cachedStep) {
1042
+ isDuplicate = true;
1043
+ result = cachedStep.result;
1044
+ success = cachedStep.success;
1045
+ error = cachedStep.error;
1046
+ executorLogger.info("Duplicate step execution prevented", {
1047
+ stepId: currentStep.id,
1048
+ toolName: currentStep.tool,
1049
+ arguments: currentStep.args,
1050
+ iteration,
1051
+ cacheHit: true
1052
+ });
1053
+ }
1054
+ }
1055
+ if (!isDuplicate) {
1056
+ const tool = tools.find((t) => t.metadata.name === currentStep.tool);
1057
+ if (!tool) {
1058
+ throw new Error(`Tool not found: ${currentStep.tool}`);
1059
+ }
1060
+ const startTime = Date.now();
1061
+ const timeoutPromise = new Promise(
1062
+ (_, reject) => setTimeout(() => reject(new Error("Step execution timeout")), stepTimeout)
1063
+ );
1064
+ result = await Promise.race([
1065
+ tool.execute(currentStep.args || {}),
1066
+ timeoutPromise
1067
+ ]);
1068
+ const executionTime = Date.now() - startTime;
1069
+ executorLogger.debug("Step executed successfully", {
1070
+ stepId: currentStep.id,
1071
+ toolName: currentStep.tool,
1072
+ executionTime,
1073
+ iteration
1074
+ });
864
1075
  }
865
- const timeoutPromise = new Promise(
866
- (_, reject) => setTimeout(() => reject(new Error("Step execution timeout")), stepTimeout)
867
- );
868
- result = await Promise.race([
869
- tool.execute(currentStep.args || {}),
870
- timeoutPromise
871
- ]);
872
1076
  } else {
873
1077
  result = { message: "Step completed without tool execution" };
874
1078
  }
@@ -879,6 +1083,12 @@ function createExecutorNode(config) {
879
1083
  success = false;
880
1084
  error = execError instanceof Error ? execError.message : "Unknown execution error";
881
1085
  result = null;
1086
+ executorLogger.warn("Step execution failed", {
1087
+ stepId: currentStep.id,
1088
+ toolName: currentStep.tool,
1089
+ error,
1090
+ iteration
1091
+ });
882
1092
  }
883
1093
  const completedStep = {
884
1094
  step: currentStep,
@@ -887,11 +1097,23 @@ function createExecutorNode(config) {
887
1097
  error,
888
1098
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
889
1099
  };
1100
+ executorLogger.info("Executor node complete", {
1101
+ stepId: currentStep.id,
1102
+ stepIndex: currentStepIndex,
1103
+ totalSteps: plan.steps.length,
1104
+ success,
1105
+ isDuplicate,
1106
+ iteration
1107
+ });
890
1108
  return {
891
1109
  pastSteps: [completedStep],
892
1110
  currentStepIndex: currentStepIndex + 1
893
1111
  };
894
1112
  } catch (error) {
1113
+ executorLogger.error("Executor node failed", {
1114
+ error: error instanceof Error ? error.message : "Unknown error",
1115
+ iteration
1116
+ });
895
1117
  return {
896
1118
  status: "failed",
897
1119
  error: error instanceof Error ? error.message : "Unknown error in executor"
@@ -906,11 +1128,18 @@ function createReplannerNode(config) {
906
1128
  systemPrompt = DEFAULT_REPLANNER_SYSTEM_PROMPT
907
1129
  } = config;
908
1130
  return async (state) => {
1131
+ const startTime = Date.now();
909
1132
  try {
910
1133
  const { plan, pastSteps = [], currentStepIndex = 0 } = state;
911
1134
  if (!plan) {
912
1135
  return { status: "failed", error: "No plan available for replanning" };
913
1136
  }
1137
+ replannerLogger.debug("Evaluating replanning", {
1138
+ completedSteps: pastSteps.length,
1139
+ remainingSteps: plan.steps.length - currentStepIndex,
1140
+ successfulSteps: pastSteps.filter((ps) => ps.success).length,
1141
+ failedSteps: pastSteps.filter((ps) => !ps.success).length
1142
+ });
914
1143
  const completedStepsText = pastSteps.map(
915
1144
  (ps, idx) => COMPLETED_STEP_TEMPLATE.replace("{stepNumber}", String(idx + 1)).replace("{description}", ps.step.description).replace("{result}", JSON.stringify(ps.result)).replace("{status}", ps.success ? "Success" : `Failed: ${ps.error}`)
916
1145
  ).join("\n\n");
@@ -932,17 +1161,30 @@ function createReplannerNode(config) {
932
1161
  throw new Error(`Failed to parse replan decision from LLM response: ${parseError}`);
933
1162
  }
934
1163
  if (decision.shouldReplan) {
1164
+ replannerLogger.info("Replanning triggered", {
1165
+ reason: decision.reason,
1166
+ newGoal: decision.newGoal?.substring(0, 100),
1167
+ duration: Date.now() - startTime
1168
+ });
935
1169
  return {
936
1170
  status: "planning",
937
1171
  input: decision.newGoal || plan.goal,
938
1172
  iteration: 1
939
1173
  };
940
1174
  } else {
1175
+ replannerLogger.info("Continuing with current plan", {
1176
+ reason: decision.reason,
1177
+ duration: Date.now() - startTime
1178
+ });
941
1179
  return {
942
1180
  status: "executing"
943
1181
  };
944
1182
  }
945
1183
  } catch (error) {
1184
+ replannerLogger.error("Replanning evaluation failed", {
1185
+ error: error instanceof Error ? error.message : String(error),
1186
+ duration: Date.now() - startTime
1187
+ });
946
1188
  return {
947
1189
  status: "failed",
948
1190
  error: error instanceof Error ? error.message : "Unknown error in replanner"
@@ -1043,7 +1285,7 @@ function createPlanExecuteAgent(config) {
1043
1285
 
1044
1286
  // src/reflection/state.ts
1045
1287
  var import_zod6 = require("zod");
1046
- var import_core5 = require("@agentforge/core");
1288
+ var import_core6 = require("@agentforge/core");
1047
1289
 
1048
1290
  // src/reflection/schemas.ts
1049
1291
  var import_zod5 = require("zod");
@@ -1216,7 +1458,7 @@ var ReflectionStateConfig = {
1216
1458
  description: "Error message if reflection failed"
1217
1459
  }
1218
1460
  };
1219
- var ReflectionState = (0, import_core5.createStateAnnotation)(ReflectionStateConfig);
1461
+ var ReflectionState = (0, import_core6.createStateAnnotation)(ReflectionStateConfig);
1220
1462
 
1221
1463
  // src/reflection/prompts.ts
1222
1464
  var DEFAULT_GENERATOR_SYSTEM_PROMPT = `You are an expert content generator. Your task is to create high-quality responses to user requests.
@@ -1320,6 +1562,9 @@ var REVISION_ENTRY_TEMPLATE = `Iteration {iteration}:
1320
1562
 
1321
1563
  // src/reflection/nodes.ts
1322
1564
  var import_messages3 = require("@langchain/core/messages");
1565
+ var generatorLogger = createPatternLogger("agentforge:patterns:reflection:generator");
1566
+ var reflectorLogger = createPatternLogger("agentforge:patterns:reflection:reflector");
1567
+ var reviserLogger = createPatternLogger("agentforge:patterns:reflection:reviser");
1323
1568
  function createGeneratorNode(config) {
1324
1569
  const {
1325
1570
  model,
@@ -1327,10 +1572,13 @@ function createGeneratorNode(config) {
1327
1572
  verbose = false
1328
1573
  } = config;
1329
1574
  return async (state) => {
1575
+ const startTime = Date.now();
1330
1576
  try {
1331
- if (verbose) {
1332
- console.log("[Generator] Generating initial response...");
1333
- }
1577
+ generatorLogger.debug("Generating response", {
1578
+ attempt: state.iteration + 1,
1579
+ hasFeedback: state.reflections.length > 0,
1580
+ hasExistingResponse: !!state.currentResponse
1581
+ });
1334
1582
  let context = "";
1335
1583
  if (state.iteration > 0 && state.reflections.length > 0) {
1336
1584
  const lastReflection = state.reflections[state.reflections.length - 1];
@@ -1345,16 +1593,23 @@ ${lastReflection.critique}`;
1345
1593
  ];
1346
1594
  const response = await model.invoke(messages);
1347
1595
  const content = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
1348
- if (verbose) {
1349
- console.log("[Generator] Generated response:", content.substring(0, 100) + "...");
1350
- }
1596
+ generatorLogger.info("Response generated", {
1597
+ attempt: state.iteration + 1,
1598
+ responseLength: content.length,
1599
+ isRevision: state.iteration > 0,
1600
+ duration: Date.now() - startTime
1601
+ });
1351
1602
  return {
1352
1603
  currentResponse: content,
1353
1604
  status: "reflecting",
1354
1605
  iteration: 1
1355
1606
  };
1356
1607
  } catch (error) {
1357
- console.error("[Generator] Error:", error);
1608
+ generatorLogger.error("Response generation failed", {
1609
+ attempt: state.iteration + 1,
1610
+ error: error instanceof Error ? error.message : String(error),
1611
+ duration: Date.now() - startTime
1612
+ });
1358
1613
  return {
1359
1614
  status: "failed",
1360
1615
  error: error instanceof Error ? error.message : "Unknown error in generator"
@@ -1370,10 +1625,13 @@ function createReflectorNode(config) {
1370
1625
  verbose = false
1371
1626
  } = config;
1372
1627
  return async (state) => {
1628
+ const startTime = Date.now();
1373
1629
  try {
1374
- if (verbose) {
1375
- console.log("[Reflector] Reflecting on response...");
1376
- }
1630
+ reflectorLogger.debug("Reflecting on response", {
1631
+ attempt: state.iteration,
1632
+ responseLength: state.currentResponse?.length || 0,
1633
+ hasCriteria: !!(qualityCriteria || state.qualityCriteria)
1634
+ });
1377
1635
  if (!state.currentResponse) {
1378
1636
  throw new Error("No current response to reflect on");
1379
1637
  }
@@ -1423,16 +1681,24 @@ function createReflectorNode(config) {
1423
1681
  meetsStandards: false
1424
1682
  };
1425
1683
  }
1426
- if (verbose) {
1427
- console.log("[Reflector] Reflection score:", reflection.score);
1428
- console.log("[Reflector] Meets standards:", reflection.meetsStandards);
1429
- }
1684
+ reflectorLogger.info("Reflection complete", {
1685
+ attempt: state.iteration,
1686
+ score: reflection.score,
1687
+ meetsStandards: reflection.meetsStandards,
1688
+ issueCount: reflection.issues.length,
1689
+ suggestionCount: reflection.suggestions.length,
1690
+ duration: Date.now() - startTime
1691
+ });
1430
1692
  return {
1431
1693
  reflections: [reflection],
1432
1694
  status: reflection.meetsStandards ? "completed" : "revising"
1433
1695
  };
1434
1696
  } catch (error) {
1435
- console.error("[Reflector] Error:", error);
1697
+ reflectorLogger.error("Reflection failed", {
1698
+ attempt: state.iteration,
1699
+ error: error instanceof Error ? error.message : String(error),
1700
+ duration: Date.now() - startTime
1701
+ });
1436
1702
  return {
1437
1703
  status: "failed",
1438
1704
  error: error instanceof Error ? error.message : "Unknown error in reflector"
@@ -1447,10 +1713,8 @@ function createReviserNode(config) {
1447
1713
  verbose = false
1448
1714
  } = config;
1449
1715
  return async (state) => {
1716
+ const startTime = Date.now();
1450
1717
  try {
1451
- if (verbose) {
1452
- console.log("[Reviser] Revising response...");
1453
- }
1454
1718
  if (!state.currentResponse) {
1455
1719
  throw new Error("No current response to revise");
1456
1720
  }
@@ -1458,6 +1722,12 @@ function createReviserNode(config) {
1458
1722
  throw new Error("No reflections to base revision on");
1459
1723
  }
1460
1724
  const lastReflection = state.reflections[state.reflections.length - 1];
1725
+ reviserLogger.debug("Revising response", {
1726
+ attempt: state.iteration,
1727
+ previousScore: lastReflection.score,
1728
+ issueCount: lastReflection.issues.length,
1729
+ suggestionCount: lastReflection.suggestions.length
1730
+ });
1461
1731
  let historySection = "";
1462
1732
  if (state.revisions.length > 0) {
1463
1733
  const revisionsText = state.revisions.map(
@@ -1474,14 +1744,17 @@ ${revisionsText}`;
1474
1744
  ];
1475
1745
  const response = await model.invoke(messages);
1476
1746
  const content = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
1477
- if (verbose) {
1478
- console.log("[Reviser] Created revision:", content.substring(0, 100) + "...");
1479
- }
1480
1747
  const revision = {
1481
1748
  content,
1482
1749
  iteration: state.iteration,
1483
1750
  basedOn: lastReflection
1484
1751
  };
1752
+ reviserLogger.info("Revision complete", {
1753
+ attempt: state.iteration,
1754
+ revisionLength: content.length,
1755
+ basedOnScore: lastReflection.score,
1756
+ duration: Date.now() - startTime
1757
+ });
1485
1758
  return {
1486
1759
  currentResponse: content,
1487
1760
  revisions: [revision],
@@ -1489,7 +1762,11 @@ ${revisionsText}`;
1489
1762
  iteration: 1
1490
1763
  };
1491
1764
  } catch (error) {
1492
- console.error("[Reviser] Error:", error);
1765
+ reviserLogger.error("Revision failed", {
1766
+ attempt: state.iteration,
1767
+ error: error instanceof Error ? error.message : String(error),
1768
+ duration: Date.now() - startTime
1769
+ });
1493
1770
  return {
1494
1771
  status: "failed",
1495
1772
  error: error instanceof Error ? error.message : "Unknown error in reviser"
@@ -1579,7 +1856,7 @@ function createReflectionAgent(config) {
1579
1856
 
1580
1857
  // src/multi-agent/state.ts
1581
1858
  var import_zod8 = require("zod");
1582
- var import_core6 = require("@agentforge/core");
1859
+ var import_core7 = require("@agentforge/core");
1583
1860
 
1584
1861
  // src/multi-agent/schemas.ts
1585
1862
  var import_zod7 = require("zod");
@@ -1902,15 +2179,26 @@ var MultiAgentStateConfig = {
1902
2179
  description: "Error message if execution failed"
1903
2180
  }
1904
2181
  };
1905
- var MultiAgentState = (0, import_core6.createStateAnnotation)(MultiAgentStateConfig);
2182
+ var MultiAgentState = (0, import_core7.createStateAnnotation)(MultiAgentStateConfig);
1906
2183
 
1907
2184
  // src/multi-agent/routing.ts
1908
2185
  var import_messages4 = require("@langchain/core/messages");
2186
+ var import_core8 = require("@agentforge/core");
2187
+ var logLevel = process.env.LOG_LEVEL?.toLowerCase() || import_core8.LogLevel.INFO;
2188
+ var logger = (0, import_core8.createLogger)("multi-agent:routing", { level: logLevel });
1909
2189
  async function executeTools(toolCalls, tools) {
1910
2190
  const results = [];
2191
+ logger.debug("Executing tools", {
2192
+ toolCallCount: toolCalls.length,
2193
+ toolNames: toolCalls.map((tc) => tc.name)
2194
+ });
1911
2195
  for (const toolCall of toolCalls) {
1912
2196
  const tool = tools.find((t) => t.metadata.name === toolCall.name);
1913
2197
  if (!tool) {
2198
+ logger.warn("Tool not found", {
2199
+ toolName: toolCall.name,
2200
+ availableTools: tools.map((t) => t.metadata.name)
2201
+ });
1914
2202
  results.push(new import_messages4.ToolMessage({
1915
2203
  content: `Error: Tool '${toolCall.name}' not found`,
1916
2204
  tool_call_id: toolCall.id
@@ -1918,19 +2206,41 @@ async function executeTools(toolCalls, tools) {
1918
2206
  continue;
1919
2207
  }
1920
2208
  try {
2209
+ logger.debug("Executing tool", {
2210
+ toolName: toolCall.name,
2211
+ args: toolCall.args
2212
+ });
1921
2213
  const result = await tool.execute(toolCall.args);
1922
2214
  const content = typeof result === "string" ? result : JSON.stringify(result);
2215
+ logger.debug("Tool execution successful", {
2216
+ toolName: toolCall.name,
2217
+ resultLength: content.length
2218
+ });
1923
2219
  results.push(new import_messages4.ToolMessage({
1924
2220
  content,
1925
2221
  tool_call_id: toolCall.id
1926
2222
  }));
1927
2223
  } catch (error) {
2224
+ logger.error("Tool execution failed", {
2225
+ toolName: toolCall.name,
2226
+ error: error.message
2227
+ });
1928
2228
  results.push(new import_messages4.ToolMessage({
1929
2229
  content: `Error executing tool: ${error.message}`,
1930
2230
  tool_call_id: toolCall.id
1931
2231
  }));
1932
2232
  }
1933
2233
  }
2234
+ logger.debug("Tool execution complete", {
2235
+ successCount: results.filter((r) => {
2236
+ const content = typeof r.content === "string" ? r.content : JSON.stringify(r.content);
2237
+ return !content.startsWith("Error");
2238
+ }).length,
2239
+ errorCount: results.filter((r) => {
2240
+ const content = typeof r.content === "string" ? r.content : JSON.stringify(r.content);
2241
+ return content.startsWith("Error");
2242
+ }).length
2243
+ });
1934
2244
  return results;
1935
2245
  }
1936
2246
  var DEFAULT_SUPERVISOR_SYSTEM_PROMPT = `You are a supervisor agent responsible for routing tasks to specialized worker agents.
@@ -1968,6 +2278,10 @@ Choose parallel routing when the task benefits from multiple perspectives or dat
1968
2278
  var llmBasedRouting = {
1969
2279
  name: "llm-based",
1970
2280
  async route(state, config) {
2281
+ logger.info("Starting LLM-based routing", {
2282
+ iteration: state.iteration,
2283
+ availableWorkers: Object.keys(state.workers).length
2284
+ });
1971
2285
  if (!config.model) {
1972
2286
  throw new Error("LLM-based routing requires a model to be configured");
1973
2287
  }
@@ -1980,8 +2294,20 @@ var llmBasedRouting = {
1980
2294
  const available = caps.available ? "available" : "busy";
1981
2295
  return `- ${id}: Skills: [${skills}], Tools: [${tools2}], Status: ${available}, Workload: ${caps.currentWorkload}`;
1982
2296
  }).join("\n");
2297
+ logger.debug("Worker capabilities", {
2298
+ workers: Object.entries(state.workers).map(([id, caps]) => ({
2299
+ id,
2300
+ skills: caps.skills,
2301
+ available: caps.available,
2302
+ workload: caps.currentWorkload
2303
+ }))
2304
+ });
1983
2305
  const lastMessage = state.messages[state.messages.length - 1];
1984
2306
  const taskContext = lastMessage?.content || state.input;
2307
+ logger.debug("Task context", {
2308
+ taskLength: taskContext.length,
2309
+ taskPreview: taskContext.substring(0, 100)
2310
+ });
1985
2311
  const userPrompt = `Current task: ${taskContext}
1986
2312
 
1987
2313
  Available workers:
@@ -1991,6 +2317,11 @@ Select the best worker(s) for this task and explain your reasoning.`;
1991
2317
  const conversationHistory = [];
1992
2318
  let attempt = 0;
1993
2319
  while (attempt < maxRetries) {
2320
+ logger.debug("LLM routing attempt", {
2321
+ attempt: attempt + 1,
2322
+ maxRetries,
2323
+ conversationHistoryLength: conversationHistory.length
2324
+ });
1994
2325
  const messages = [
1995
2326
  new import_messages4.SystemMessage(systemPrompt),
1996
2327
  new import_messages4.HumanMessage(userPrompt),
@@ -1998,6 +2329,10 @@ Select the best worker(s) for this task and explain your reasoning.`;
1998
2329
  ];
1999
2330
  const response = await config.model.invoke(messages);
2000
2331
  if (response.tool_calls && response.tool_calls.length > 0) {
2332
+ logger.info("LLM requested tool calls", {
2333
+ toolCount: response.tool_calls.length,
2334
+ toolNames: response.tool_calls.map((tc) => tc.name)
2335
+ });
2001
2336
  if (tools.length === 0) {
2002
2337
  throw new Error("LLM requested tool calls but no tools are configured");
2003
2338
  }
@@ -2007,24 +2342,42 @@ Select the best worker(s) for this task and explain your reasoning.`;
2007
2342
  ...toolResults
2008
2343
  );
2009
2344
  attempt++;
2345
+ logger.debug("Retrying routing with tool results", { attempt });
2010
2346
  continue;
2011
2347
  }
2348
+ logger.debug("Parsing routing decision from LLM response");
2012
2349
  let decision;
2013
2350
  if (response && typeof response === "object" && ("targetAgent" in response || "targetAgents" in response)) {
2351
+ logger.debug("Response is structured output", {
2352
+ hasTargetAgent: "targetAgent" in response,
2353
+ hasTargetAgents: "targetAgents" in response
2354
+ });
2014
2355
  decision = response;
2015
2356
  } else if (response.content) {
2016
2357
  if (typeof response.content === "string") {
2017
2358
  try {
2018
2359
  decision = JSON.parse(response.content);
2360
+ logger.debug("Parsed JSON from string response");
2019
2361
  } catch (error) {
2362
+ logger.error("Failed to parse routing decision", {
2363
+ content: response.content,
2364
+ error: error instanceof Error ? error.message : String(error)
2365
+ });
2020
2366
  throw new Error(`Failed to parse routing decision from LLM. Expected JSON but got: ${response.content}`);
2021
2367
  }
2022
2368
  } else if (typeof response.content === "object") {
2369
+ logger.debug("Response content is already an object");
2023
2370
  decision = response.content;
2024
2371
  } else {
2372
+ logger.error("Unexpected response content type", {
2373
+ type: typeof response.content
2374
+ });
2025
2375
  throw new Error(`Unexpected response content type: ${typeof response.content}`);
2026
2376
  }
2027
2377
  } else {
2378
+ logger.error("Unexpected response format", {
2379
+ response: JSON.stringify(response)
2380
+ });
2028
2381
  throw new Error(`Unexpected response format: ${JSON.stringify(response)}`);
2029
2382
  }
2030
2383
  const result = {
@@ -2035,20 +2388,41 @@ Select the best worker(s) for this task and explain your reasoning.`;
2035
2388
  strategy: "llm-based",
2036
2389
  timestamp: Date.now()
2037
2390
  };
2391
+ logger.info("LLM routing decision made", {
2392
+ targetAgent: result.targetAgent,
2393
+ targetAgents: result.targetAgents,
2394
+ isParallel: result.targetAgents && result.targetAgents.length > 1,
2395
+ confidence: result.confidence,
2396
+ reasoning: result.reasoning
2397
+ });
2038
2398
  return result;
2039
2399
  }
2400
+ logger.error("Max tool retries exceeded", { maxRetries });
2040
2401
  throw new Error(`Max tool retries (${maxRetries}) exceeded without routing decision`);
2041
2402
  }
2042
2403
  };
2043
2404
  var roundRobinRouting = {
2044
2405
  name: "round-robin",
2045
2406
  async route(state, config) {
2407
+ logger.info("Starting round-robin routing", {
2408
+ iteration: state.iteration
2409
+ });
2046
2410
  const availableWorkers = Object.entries(state.workers).filter(([_, caps]) => caps.available).map(([id]) => id);
2411
+ logger.debug("Available workers for round-robin", {
2412
+ count: availableWorkers.length,
2413
+ workers: availableWorkers
2414
+ });
2047
2415
  if (availableWorkers.length === 0) {
2416
+ logger.error("No available workers for round-robin routing");
2048
2417
  throw new Error("No available workers for round-robin routing");
2049
2418
  }
2050
2419
  const lastRoutingIndex = state.routingHistory.length % availableWorkers.length;
2051
2420
  const targetAgent = availableWorkers[lastRoutingIndex];
2421
+ logger.info("Round-robin routing decision", {
2422
+ targetAgent,
2423
+ index: lastRoutingIndex + 1,
2424
+ totalWorkers: availableWorkers.length
2425
+ });
2052
2426
  return {
2053
2427
  targetAgent,
2054
2428
  targetAgents: null,
@@ -2062,8 +2436,15 @@ var roundRobinRouting = {
2062
2436
  var skillBasedRouting = {
2063
2437
  name: "skill-based",
2064
2438
  async route(state, config) {
2439
+ logger.info("Starting skill-based routing", {
2440
+ iteration: state.iteration
2441
+ });
2065
2442
  const lastMessage = state.messages[state.messages.length - 1];
2066
2443
  const taskContent = (lastMessage?.content || state.input).toLowerCase();
2444
+ logger.debug("Task content for skill matching", {
2445
+ taskLength: taskContent.length,
2446
+ taskPreview: taskContent.substring(0, 100)
2447
+ });
2067
2448
  const workerScores = Object.entries(state.workers).filter(([_, caps]) => caps.available).map(([id, caps]) => {
2068
2449
  const skillMatches = caps.skills.filter(
2069
2450
  (skill) => taskContent.includes(skill.toLowerCase())
@@ -2074,11 +2455,20 @@ var skillBasedRouting = {
2074
2455
  const score = skillMatches * 2 + toolMatches;
2075
2456
  return { id, score, skills: caps.skills, tools: caps.tools };
2076
2457
  }).filter((w) => w.score > 0).sort((a, b) => b.score - a.score);
2458
+ logger.debug("Worker skill scores", {
2459
+ scoredWorkers: workerScores.map((w) => ({ id: w.id, score: w.score }))
2460
+ });
2077
2461
  if (workerScores.length === 0) {
2462
+ logger.warn("No skill matches found, using fallback");
2078
2463
  const firstAvailable = Object.entries(state.workers).find(([_, caps]) => caps.available);
2079
2464
  if (!firstAvailable) {
2465
+ logger.error("No available workers for skill-based routing");
2080
2466
  throw new Error("No available workers for skill-based routing");
2081
2467
  }
2468
+ logger.info("Skill-based routing fallback decision", {
2469
+ targetAgent: firstAvailable[0],
2470
+ confidence: 0.5
2471
+ });
2082
2472
  return {
2083
2473
  targetAgent: firstAvailable[0],
2084
2474
  targetAgents: null,
@@ -2090,6 +2480,12 @@ var skillBasedRouting = {
2090
2480
  }
2091
2481
  const best = workerScores[0];
2092
2482
  const confidence = Math.min(best.score / 5, 1);
2483
+ logger.info("Skill-based routing decision", {
2484
+ targetAgent: best.id,
2485
+ score: best.score,
2486
+ confidence,
2487
+ matchedSkills: best.skills
2488
+ });
2093
2489
  return {
2094
2490
  targetAgent: best.id,
2095
2491
  targetAgents: null,
@@ -2103,13 +2499,26 @@ var skillBasedRouting = {
2103
2499
  var loadBalancedRouting = {
2104
2500
  name: "load-balanced",
2105
2501
  async route(state, config) {
2502
+ logger.info("Starting load-balanced routing", {
2503
+ iteration: state.iteration
2504
+ });
2106
2505
  const availableWorkers = Object.entries(state.workers).filter(([_, caps]) => caps.available).map(([id, caps]) => ({ id, workload: caps.currentWorkload })).sort((a, b) => a.workload - b.workload);
2506
+ logger.debug("Worker workloads", {
2507
+ workers: availableWorkers.map((w) => ({ id: w.id, workload: w.workload }))
2508
+ });
2107
2509
  if (availableWorkers.length === 0) {
2510
+ logger.error("No available workers for load-balanced routing");
2108
2511
  throw new Error("No available workers for load-balanced routing");
2109
2512
  }
2110
2513
  const targetWorker = availableWorkers[0];
2111
2514
  const avgWorkload = availableWorkers.reduce((sum, w) => sum + w.workload, 0) / availableWorkers.length;
2112
2515
  const confidence = targetWorker.workload === 0 ? 1 : Math.max(0.5, 1 - targetWorker.workload / (avgWorkload * 2));
2516
+ logger.info("Load-balanced routing decision", {
2517
+ targetAgent: targetWorker.id,
2518
+ workload: targetWorker.workload,
2519
+ avgWorkload: avgWorkload.toFixed(1),
2520
+ confidence
2521
+ });
2113
2522
  return {
2114
2523
  targetAgent: targetWorker.id,
2115
2524
  targetAgents: null,
@@ -2123,13 +2532,24 @@ var loadBalancedRouting = {
2123
2532
  var ruleBasedRouting = {
2124
2533
  name: "rule-based",
2125
2534
  async route(state, config) {
2535
+ logger.info("Starting rule-based routing", {
2536
+ iteration: state.iteration
2537
+ });
2126
2538
  if (!config.routingFn) {
2539
+ logger.error("Rule-based routing requires a custom routing function");
2127
2540
  throw new Error("Rule-based routing requires a custom routing function");
2128
2541
  }
2129
- return await config.routingFn(state);
2542
+ const decision = await config.routingFn(state);
2543
+ logger.info("Rule-based routing decision", {
2544
+ targetAgent: decision.targetAgent,
2545
+ targetAgents: decision.targetAgents,
2546
+ confidence: decision.confidence
2547
+ });
2548
+ return decision;
2130
2549
  }
2131
2550
  };
2132
2551
  function getRoutingStrategy(name) {
2552
+ logger.debug("Getting routing strategy", { name });
2133
2553
  switch (name) {
2134
2554
  case "llm-based":
2135
2555
  return llmBasedRouting;
@@ -2142,14 +2562,15 @@ function getRoutingStrategy(name) {
2142
2562
  case "rule-based":
2143
2563
  return ruleBasedRouting;
2144
2564
  default:
2565
+ logger.error("Unknown routing strategy", { name });
2145
2566
  throw new Error(`Unknown routing strategy: ${name}`);
2146
2567
  }
2147
2568
  }
2148
2569
 
2149
2570
  // src/multi-agent/utils.ts
2150
- var import_core7 = require("@agentforge/core");
2151
- var logLevel = process.env.LOG_LEVEL?.toLowerCase() || import_core7.LogLevel.INFO;
2152
- var logger = (0, import_core7.createLogger)("multi-agent", { level: logLevel });
2571
+ var import_core9 = require("@agentforge/core");
2572
+ var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || import_core9.LogLevel.INFO;
2573
+ var logger2 = (0, import_core9.createLogger)("multi-agent", { level: logLevel2 });
2153
2574
  function isReActAgent(obj) {
2154
2575
  return obj && typeof obj === "object" && typeof obj.invoke === "function" && typeof obj.stream === "function" && // Additional check to ensure it's not just any object with invoke/stream
2155
2576
  (obj.constructor?.name === "CompiledGraph" || obj.constructor?.name === "CompiledStateGraph");
@@ -2157,9 +2578,9 @@ function isReActAgent(obj) {
2157
2578
  function wrapReActAgent(workerId, agent, verbose = false) {
2158
2579
  return async (state, config) => {
2159
2580
  try {
2160
- logger.debug("Wrapping ReAct agent execution", { workerId });
2581
+ logger2.debug("Wrapping ReAct agent execution", { workerId });
2161
2582
  const task = state.messages[state.messages.length - 1]?.content || state.input;
2162
- logger.debug("Extracted task", {
2583
+ logger2.debug("Extracted task", {
2163
2584
  workerId,
2164
2585
  taskPreview: task.substring(0, 100) + (task.length > 100 ? "..." : "")
2165
2586
  });
@@ -2167,7 +2588,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2167
2588
  (assignment) => assignment.workerId === workerId && !state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2168
2589
  );
2169
2590
  if (!currentAssignment) {
2170
- logger.debug("No active assignment found", { workerId });
2591
+ logger2.debug("No active assignment found", { workerId });
2171
2592
  return {};
2172
2593
  }
2173
2594
  const result = await agent.invoke(
@@ -2178,14 +2599,14 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2178
2599
  // Pass through the config for checkpointing and interrupt support
2179
2600
  );
2180
2601
  const response = result.messages?.[result.messages.length - 1]?.content || "No response";
2181
- logger.debug("Received response from ReAct agent", {
2602
+ logger2.debug("Received response from ReAct agent", {
2182
2603
  workerId,
2183
2604
  responsePreview: response.substring(0, 100) + (response.length > 100 ? "..." : "")
2184
2605
  });
2185
2606
  const toolsUsed = result.actions?.map((action) => action.name).filter(Boolean) || [];
2186
2607
  const uniqueTools = [...new Set(toolsUsed)];
2187
2608
  if (uniqueTools.length > 0) {
2188
- logger.debug("Tools used by ReAct agent", { workerId, tools: uniqueTools });
2609
+ logger2.debug("Tools used by ReAct agent", { workerId, tools: uniqueTools });
2189
2610
  }
2190
2611
  const taskResult = {
2191
2612
  assignmentId: currentAssignment.id,
@@ -2204,10 +2625,10 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2204
2625
  };
2205
2626
  } catch (error) {
2206
2627
  if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2207
- logger.debug("GraphInterrupt detected - re-throwing", { workerId });
2628
+ logger2.debug("GraphInterrupt detected - re-throwing", { workerId });
2208
2629
  throw error;
2209
2630
  }
2210
- logger.error("Error in ReAct agent execution", {
2631
+ logger2.error("Error in ReAct agent execution", {
2211
2632
  workerId,
2212
2633
  error: error instanceof Error ? error.message : String(error),
2213
2634
  stack: error instanceof Error ? error.stack : void 0
@@ -2240,7 +2661,9 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2240
2661
 
2241
2662
  // src/multi-agent/nodes.ts
2242
2663
  var import_messages5 = require("@langchain/core/messages");
2243
- var import_core8 = require("@agentforge/core");
2664
+ var import_core10 = require("@agentforge/core");
2665
+ var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || import_core10.LogLevel.INFO;
2666
+ var logger3 = (0, import_core10.createLogger)("multi-agent:nodes", { level: logLevel3 });
2244
2667
  var DEFAULT_AGGREGATOR_SYSTEM_PROMPT = `You are an aggregator agent responsible for combining results from multiple worker agents.
2245
2668
 
2246
2669
  Your job is to:
@@ -2258,13 +2681,19 @@ function createSupervisorNode(config) {
2258
2681
  } = config;
2259
2682
  return async (state) => {
2260
2683
  try {
2261
- if (verbose) {
2262
- console.log(`[Supervisor] Routing iteration ${state.iteration}/${maxIterations}`);
2263
- }
2684
+ logger3.info("Supervisor node executing", {
2685
+ iteration: state.iteration,
2686
+ maxIterations,
2687
+ activeAssignments: state.activeAssignments.length,
2688
+ completedTasks: state.completedTasks.length
2689
+ });
2690
+ logger3.debug(`Routing iteration ${state.iteration}/${maxIterations}`);
2264
2691
  if (state.iteration >= maxIterations) {
2265
- if (verbose) {
2266
- console.log("[Supervisor] Max iterations reached, moving to aggregation");
2267
- }
2692
+ logger3.warn("Max iterations reached", {
2693
+ iteration: state.iteration,
2694
+ maxIterations
2695
+ });
2696
+ logger3.debug("Max iterations reached, moving to aggregation");
2268
2697
  return {
2269
2698
  status: "aggregating",
2270
2699
  currentAgent: "aggregator"
@@ -2273,27 +2702,55 @@ function createSupervisorNode(config) {
2273
2702
  const allCompleted = state.activeAssignments.every(
2274
2703
  (assignment) => state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2275
2704
  );
2705
+ logger3.debug("Checking task completion", {
2706
+ activeAssignments: state.activeAssignments.length,
2707
+ completedTasks: state.completedTasks.length,
2708
+ allCompleted
2709
+ });
2276
2710
  if (allCompleted && state.activeAssignments.length > 0) {
2277
- if (verbose) {
2278
- console.log("[Supervisor] All tasks completed, moving to aggregation");
2279
- }
2711
+ logger3.info("All tasks completed, moving to aggregation", {
2712
+ completedCount: state.completedTasks.length
2713
+ });
2714
+ logger3.debug("All tasks completed, moving to aggregation");
2280
2715
  return {
2281
2716
  status: "aggregating",
2282
2717
  currentAgent: "aggregator"
2283
2718
  };
2284
2719
  }
2720
+ logger3.debug("Getting routing strategy", { strategy });
2285
2721
  const routingImpl = getRoutingStrategy(strategy);
2286
2722
  const decision = await routingImpl.route(state, config);
2287
2723
  const targetAgents = decision.targetAgents && decision.targetAgents.length > 0 ? decision.targetAgents : decision.targetAgent ? [decision.targetAgent] : [];
2724
+ logger3.debug("Target agents determined", {
2725
+ targetAgents,
2726
+ isParallel: targetAgents.length > 1,
2727
+ decision: {
2728
+ reasoning: decision.reasoning,
2729
+ confidence: decision.confidence
2730
+ }
2731
+ });
2288
2732
  if (targetAgents.length === 0) {
2733
+ logger3.error("No target agents specified in routing decision");
2289
2734
  throw new Error("Routing decision must specify at least one target agent");
2290
2735
  }
2291
- if (verbose) {
2292
- if (targetAgents.length === 1) {
2293
- console.log(`[Supervisor] Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2294
- } else {
2295
- console.log(`[Supervisor] Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`);
2296
- }
2736
+ if (targetAgents.length === 1) {
2737
+ logger3.info("Routing to single agent", {
2738
+ targetAgent: targetAgents[0],
2739
+ reasoning: decision.reasoning,
2740
+ confidence: decision.confidence
2741
+ });
2742
+ } else {
2743
+ logger3.info("Routing to multiple agents in parallel", {
2744
+ targetAgents,
2745
+ count: targetAgents.length,
2746
+ reasoning: decision.reasoning,
2747
+ confidence: decision.confidence
2748
+ });
2749
+ }
2750
+ if (targetAgents.length === 1) {
2751
+ logger3.debug(`Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2752
+ } else {
2753
+ logger3.debug(`Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`);
2297
2754
  }
2298
2755
  const task = state.messages[state.messages.length - 1]?.content || state.input;
2299
2756
  const assignments = targetAgents.map((workerId) => ({
@@ -2303,6 +2760,14 @@ function createSupervisorNode(config) {
2303
2760
  priority: 5,
2304
2761
  assignedAt: Date.now()
2305
2762
  }));
2763
+ logger3.debug("Created task assignments", {
2764
+ assignmentCount: assignments.length,
2765
+ assignments: assignments.map((a) => ({
2766
+ id: a.id,
2767
+ workerId: a.workerId,
2768
+ taskLength: a.task.length
2769
+ }))
2770
+ });
2306
2771
  const messages = assignments.map((assignment) => ({
2307
2772
  id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2308
2773
  from: "supervisor",
@@ -2315,6 +2780,12 @@ function createSupervisorNode(config) {
2315
2780
  priority: assignment.priority
2316
2781
  }
2317
2782
  }));
2783
+ logger3.info("Supervisor routing complete", {
2784
+ currentAgent: targetAgents.join(","),
2785
+ status: "executing",
2786
+ assignmentCount: assignments.length,
2787
+ nextIteration: state.iteration + 1
2788
+ });
2318
2789
  return {
2319
2790
  currentAgent: targetAgents.join(","),
2320
2791
  // Store all agents (for backward compat)
@@ -2326,7 +2797,11 @@ function createSupervisorNode(config) {
2326
2797
  iteration: state.iteration + 1
2327
2798
  };
2328
2799
  } catch (error) {
2329
- console.error("[Supervisor] Error:", error);
2800
+ logger3.error("Supervisor node error", {
2801
+ error: error instanceof Error ? error.message : String(error),
2802
+ stack: error instanceof Error ? error.stack : void 0,
2803
+ iteration: state.iteration
2804
+ });
2330
2805
  return {
2331
2806
  status: "failed",
2332
2807
  error: error instanceof Error ? error.message : "Unknown error in supervisor"
@@ -2347,40 +2822,52 @@ function createWorkerNode(config) {
2347
2822
  } = config;
2348
2823
  return async (state, runConfig) => {
2349
2824
  try {
2350
- if (verbose) {
2351
- console.log(`[Worker:${id}] Executing task`);
2352
- }
2825
+ logger3.info("Worker node executing", {
2826
+ workerId: id,
2827
+ iteration: state.iteration,
2828
+ activeAssignments: state.activeAssignments.length
2829
+ });
2353
2830
  const currentAssignment = state.activeAssignments.find(
2354
2831
  (assignment) => assignment.workerId === id && !state.completedTasks.some((task) => task.assignmentId === assignment.id)
2355
2832
  );
2356
2833
  if (!currentAssignment) {
2357
- if (verbose) {
2358
- console.log(`[Worker:${id}] No active assignment found`);
2359
- }
2834
+ logger3.debug("No active assignment found for worker", {
2835
+ workerId: id,
2836
+ totalActiveAssignments: state.activeAssignments.length,
2837
+ completedTasks: state.completedTasks.length
2838
+ });
2360
2839
  return {};
2361
2840
  }
2841
+ logger3.info("Worker processing assignment", {
2842
+ workerId: id,
2843
+ assignmentId: currentAssignment.id,
2844
+ taskLength: currentAssignment.task.length,
2845
+ taskPreview: currentAssignment.task.substring(0, 100)
2846
+ });
2362
2847
  if (executeFn) {
2363
- if (verbose) {
2364
- console.log(`[Worker:${id}] Using custom executeFn`);
2365
- }
2848
+ logger3.debug("Using custom execution function", { workerId: id });
2366
2849
  return await executeFn(state, runConfig);
2367
2850
  }
2368
2851
  if (agent) {
2369
2852
  if (isReActAgent(agent)) {
2370
- if (verbose) {
2371
- console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
2372
- }
2853
+ logger3.debug("Using ReAct agent", { workerId: id });
2373
2854
  const wrappedFn = wrapReActAgent(id, agent, verbose);
2374
2855
  return await wrappedFn(state, runConfig);
2375
2856
  } else {
2376
- console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
2857
+ logger3.warn("Agent provided but not a ReAct agent, falling back", { workerId: id });
2377
2858
  }
2378
2859
  }
2379
2860
  if (!model) {
2861
+ logger3.error("Worker missing required configuration", { workerId: id });
2380
2862
  throw new Error(
2381
2863
  `Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
2382
2864
  );
2383
2865
  }
2866
+ logger3.debug("Using default LLM execution", {
2867
+ workerId: id,
2868
+ hasTools: tools.length > 0,
2869
+ toolCount: tools.length
2870
+ });
2384
2871
  const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
2385
2872
  Skills: ${capabilities.skills.join(", ")}
2386
2873
  Tools: ${capabilities.tools.join(", ")}
@@ -2392,14 +2879,23 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2392
2879
  ];
2393
2880
  let modelToUse = model;
2394
2881
  if (tools.length > 0 && model.bindTools) {
2395
- const langchainTools = (0, import_core8.toLangChainTools)(tools);
2882
+ logger3.debug("Binding tools to model", {
2883
+ workerId: id,
2884
+ toolCount: tools.length,
2885
+ toolNames: tools.map((t) => t.metadata.name)
2886
+ });
2887
+ const langchainTools = (0, import_core10.toLangChainTools)(tools);
2396
2888
  modelToUse = model.bindTools(langchainTools);
2397
2889
  }
2890
+ logger3.debug("Invoking LLM", { workerId: id });
2398
2891
  const response = await modelToUse.invoke(messages);
2399
2892
  const result = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2400
- if (verbose) {
2401
- console.log(`[Worker:${id}] Task completed:`, result.substring(0, 100) + "...");
2402
- }
2893
+ logger3.info("Worker task completed", {
2894
+ workerId: id,
2895
+ assignmentId: currentAssignment.id,
2896
+ resultLength: result.length,
2897
+ resultPreview: result.substring(0, 100)
2898
+ });
2403
2899
  const taskResult = {
2404
2900
  assignmentId: currentAssignment.id,
2405
2901
  workerId: id,
@@ -2429,6 +2925,10 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2429
2925
  currentWorkload: Math.max(0, capabilities.currentWorkload - 1)
2430
2926
  }
2431
2927
  };
2928
+ logger3.debug("Worker state update", {
2929
+ workerId: id,
2930
+ newWorkload: updatedWorkers[id].currentWorkload
2931
+ });
2432
2932
  return {
2433
2933
  completedTasks: [taskResult],
2434
2934
  messages: [message],
@@ -2436,13 +2936,22 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2436
2936
  };
2437
2937
  } catch (error) {
2438
2938
  if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2939
+ logger3.info("GraphInterrupt detected, re-throwing", { workerId: id });
2439
2940
  throw error;
2440
2941
  }
2441
- console.error(`[Worker:${id}] Error:`, error);
2942
+ logger3.error("Worker node error", {
2943
+ workerId: id,
2944
+ error: error instanceof Error ? error.message : String(error),
2945
+ stack: error instanceof Error ? error.stack : void 0
2946
+ });
2442
2947
  const currentAssignment = state.activeAssignments.find(
2443
2948
  (assignment) => assignment.workerId === id
2444
2949
  );
2445
2950
  if (currentAssignment) {
2951
+ logger3.warn("Creating error result for assignment", {
2952
+ workerId: id,
2953
+ assignmentId: currentAssignment.id
2954
+ });
2446
2955
  const errorResult = {
2447
2956
  assignmentId: currentAssignment.id,
2448
2957
  workerId: id,
@@ -2457,6 +2966,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2457
2966
  status: "routing"
2458
2967
  };
2459
2968
  }
2969
+ logger3.error("No assignment found for error handling", { workerId: id });
2460
2970
  return {
2461
2971
  status: "failed",
2462
2972
  error: error instanceof Error ? error.message : `Unknown error in worker ${id}`
@@ -2473,29 +2983,44 @@ function createAggregatorNode(config = {}) {
2473
2983
  } = config;
2474
2984
  return async (state) => {
2475
2985
  try {
2476
- if (verbose) {
2477
- console.log("[Aggregator] Combining results from workers");
2478
- }
2986
+ logger3.info("Aggregator node executing", {
2987
+ completedTasks: state.completedTasks.length,
2988
+ successfulTasks: state.completedTasks.filter((t) => t.success).length,
2989
+ failedTasks: state.completedTasks.filter((t) => !t.success).length
2990
+ });
2991
+ logger3.debug("Combining results from workers");
2479
2992
  if (aggregateFn) {
2993
+ logger3.debug("Using custom aggregation function");
2480
2994
  const response2 = await aggregateFn(state);
2995
+ logger3.info("Custom aggregation complete", {
2996
+ responseLength: response2.length
2997
+ });
2481
2998
  return {
2482
2999
  response: response2,
2483
3000
  status: "completed"
2484
3001
  };
2485
3002
  }
2486
3003
  if (state.completedTasks.length === 0) {
3004
+ logger3.warn("No completed tasks to aggregate");
2487
3005
  return {
2488
3006
  response: "No tasks were completed.",
2489
3007
  status: "completed"
2490
3008
  };
2491
3009
  }
2492
3010
  if (!model) {
3011
+ logger3.debug("No model provided, concatenating results");
2493
3012
  const combinedResults = state.completedTasks.filter((task) => task.success).map((task) => task.result).join("\n\n");
3013
+ logger3.info("Simple concatenation complete", {
3014
+ resultLength: combinedResults.length
3015
+ });
2494
3016
  return {
2495
3017
  response: combinedResults || "No successful results to aggregate.",
2496
3018
  status: "completed"
2497
3019
  };
2498
3020
  }
3021
+ logger3.debug("Using LLM for intelligent aggregation", {
3022
+ taskCount: state.completedTasks.length
3023
+ });
2499
3024
  const taskResults = state.completedTasks.map((task, idx) => {
2500
3025
  const status = task.success ? "\u2713" : "\u2717";
2501
3026
  const result = task.success ? task.result : `Error: ${task.error}`;
@@ -2512,17 +3037,24 @@ Please synthesize these results into a comprehensive response that addresses the
2512
3037
  new import_messages5.SystemMessage(systemPrompt),
2513
3038
  new import_messages5.HumanMessage(userPrompt)
2514
3039
  ];
3040
+ logger3.debug("Invoking aggregation LLM");
2515
3041
  const response = await model.invoke(messages);
2516
3042
  const aggregatedResponse = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2517
- if (verbose) {
2518
- console.log("[Aggregator] Aggregation complete");
2519
- }
3043
+ logger3.info("Aggregation complete", {
3044
+ responseLength: aggregatedResponse.length,
3045
+ responsePreview: aggregatedResponse.substring(0, 100)
3046
+ });
3047
+ logger3.debug("Aggregation complete");
2520
3048
  return {
2521
3049
  response: aggregatedResponse,
2522
3050
  status: "completed"
2523
3051
  };
2524
3052
  } catch (error) {
2525
- console.error("[Aggregator] Error:", error);
3053
+ logger3.error("Aggregator node error", {
3054
+ error: error instanceof Error ? error.message : String(error),
3055
+ stack: error instanceof Error ? error.stack : void 0,
3056
+ completedTasks: state.completedTasks.length
3057
+ });
2526
3058
  return {
2527
3059
  status: "failed",
2528
3060
  error: error instanceof Error ? error.message : "Unknown error in aggregator"
@@ -2533,7 +3065,9 @@ Please synthesize these results into a comprehensive response that addresses the
2533
3065
 
2534
3066
  // src/multi-agent/agent.ts
2535
3067
  var import_langgraph4 = require("@langchain/langgraph");
2536
- var import_core9 = require("@agentforge/core");
3068
+ var import_core11 = require("@agentforge/core");
3069
+ var logLevel4 = process.env.LOG_LEVEL?.toLowerCase() || import_core11.LogLevel.INFO;
3070
+ var logger4 = (0, import_core11.createLogger)("multi-agent:system", { level: logLevel4 });
2537
3071
  function createMultiAgentSystem(config) {
2538
3072
  const {
2539
3073
  supervisor,
@@ -2551,7 +3085,7 @@ function createMultiAgentSystem(config) {
2551
3085
  configuredModel = configuredModel.withStructuredOutput(RoutingDecisionSchema);
2552
3086
  }
2553
3087
  if (supervisor.tools && supervisor.tools.length > 0) {
2554
- const langchainTools = (0, import_core9.toLangChainTools)(supervisor.tools);
3088
+ const langchainTools = (0, import_core11.toLangChainTools)(supervisor.tools);
2555
3089
  configuredModel = configuredModel.bindTools(langchainTools);
2556
3090
  }
2557
3091
  supervisorConfig.model = configuredModel;
@@ -2575,25 +3109,49 @@ function createMultiAgentSystem(config) {
2575
3109
  });
2576
3110
  workflow.addNode("aggregator", aggregatorNode);
2577
3111
  const supervisorRouter = (state) => {
3112
+ logger4.debug("Supervisor router executing", {
3113
+ status: state.status,
3114
+ currentAgent: state.currentAgent,
3115
+ iteration: state.iteration
3116
+ });
2578
3117
  if (state.status === "completed" || state.status === "failed") {
3118
+ logger4.info("Supervisor router: ending workflow", { status: state.status });
2579
3119
  return import_langgraph4.END;
2580
3120
  }
2581
3121
  if (state.status === "aggregating") {
3122
+ logger4.info("Supervisor router: routing to aggregator");
2582
3123
  return "aggregator";
2583
3124
  }
2584
3125
  if (state.currentAgent && state.currentAgent !== "supervisor") {
2585
3126
  if (state.currentAgent.includes(",")) {
2586
3127
  const agents = state.currentAgent.split(",").map((a) => a.trim());
3128
+ logger4.info("Supervisor router: parallel routing", {
3129
+ agents,
3130
+ count: agents.length
3131
+ });
2587
3132
  return agents;
2588
3133
  }
3134
+ logger4.info("Supervisor router: single agent routing", {
3135
+ targetAgent: state.currentAgent
3136
+ });
2589
3137
  return state.currentAgent;
2590
3138
  }
3139
+ logger4.debug("Supervisor router: staying at supervisor");
2591
3140
  return "supervisor";
2592
3141
  };
2593
3142
  const workerRouter = (state) => {
3143
+ logger4.debug("Worker router executing", {
3144
+ iteration: state.iteration,
3145
+ completedTasks: state.completedTasks.length
3146
+ });
3147
+ logger4.debug("Worker router: returning to supervisor");
2594
3148
  return "supervisor";
2595
3149
  };
2596
3150
  const aggregatorRouter = (state) => {
3151
+ logger4.info("Aggregator router: ending workflow", {
3152
+ completedTasks: state.completedTasks.length,
3153
+ status: state.status
3154
+ });
2597
3155
  return import_langgraph4.END;
2598
3156
  };
2599
3157
  workflow.setEntryPoint("supervisor");
@@ -2787,11 +3345,14 @@ function registerWorkers(system, workers) {
2787
3345
  ToolCallSchema,
2788
3346
  ToolResultSchema,
2789
3347
  WorkerCapabilitiesSchema,
3348
+ buildDeduplicationMetrics,
3349
+ calculateDeduplicationSavings,
2790
3350
  createAggregatorNode,
2791
3351
  createExecutorNode,
2792
3352
  createFinisherNode,
2793
3353
  createGeneratorNode,
2794
3354
  createMultiAgentSystem,
3355
+ createPatternLogger,
2795
3356
  createPlanExecuteAgent,
2796
3357
  createPlannerNode,
2797
3358
  createReActAgent,
@@ -2803,6 +3364,7 @@ function registerWorkers(system, workers) {
2803
3364
  createReviserNode,
2804
3365
  createSupervisorNode,
2805
3366
  createWorkerNode,
3367
+ generateToolCallCacheKey,
2806
3368
  getRoutingStrategy,
2807
3369
  llmBasedRouting,
2808
3370
  loadBalancedRouting,