@agentforge/patterns 0.7.0 → 0.8.1

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.js CHANGED
@@ -180,8 +180,8 @@ function generateToolCallCacheKey(toolName, args) {
180
180
  return `${toolName}:${sortedArgs}`;
181
181
  }
182
182
  function createPatternLogger(name, defaultLevel = "info") {
183
- const logLevel5 = process.env.LOG_LEVEL?.toLowerCase() || defaultLevel;
184
- return createLogger(name, { level: logLevel5 });
183
+ const logLevel4 = process.env.LOG_LEVEL?.toLowerCase() || defaultLevel;
184
+ return createLogger(name, { level: logLevel4 });
185
185
  }
186
186
  function calculateDeduplicationSavings(duplicatesSkipped, toolsExecuted) {
187
187
  if (duplicatesSkipped === 0) {
@@ -501,7 +501,8 @@ function createReActAgent(config, options) {
501
501
  return ACTION_NODE;
502
502
  };
503
503
  const workflow = new StateGraph(ReActState).addNode(REASONING_NODE, reasoningNode).addNode(ACTION_NODE, actionNode).addNode(OBSERVATION_NODE, observationNode).addEdge("__start__", REASONING_NODE).addConditionalEdges(REASONING_NODE, shouldContinue).addEdge(ACTION_NODE, OBSERVATION_NODE).addEdge(OBSERVATION_NODE, REASONING_NODE);
504
- return workflow.compile(checkpointer ? { checkpointer } : void 0);
504
+ const checkpointerConfig = checkpointer === true ? { checkpointer: true } : checkpointer ? { checkpointer } : void 0;
505
+ return workflow.compile(checkpointerConfig);
505
506
  }
506
507
 
507
508
  // src/react/builder.ts
@@ -586,6 +587,43 @@ var ReActAgentBuilder = class {
586
587
  this.options.nodeNames = nodeNames;
587
588
  return this;
588
589
  }
590
+ /**
591
+ * Set the checkpointer for state persistence (optional)
592
+ *
593
+ * Can be:
594
+ * - A BaseCheckpointSaver instance (e.g., MemorySaver) for standalone agents
595
+ * - `true` to use the parent graph's checkpointer with a separate namespace (for nested graphs)
596
+ *
597
+ * Required for human-in-the-loop workflows (askHuman tool) and conversation continuity.
598
+ *
599
+ * @param checkpointer - Checkpointer instance or `true` for nested graphs
600
+ *
601
+ * @example
602
+ * Standalone agent with its own checkpointer:
603
+ * ```typescript
604
+ * import { MemorySaver } from '@langchain/langgraph';
605
+ *
606
+ * const agent = new ReActAgentBuilder()
607
+ * .withModel(model)
608
+ * .withTools(tools)
609
+ * .withCheckpointer(new MemorySaver())
610
+ * .build();
611
+ * ```
612
+ *
613
+ * @example
614
+ * Nested agent using parent's checkpointer (for multi-agent systems):
615
+ * ```typescript
616
+ * const agent = new ReActAgentBuilder()
617
+ * .withModel(model)
618
+ * .withTools(tools)
619
+ * .withCheckpointer(true) // Use parent's checkpointer with separate namespace
620
+ * .build();
621
+ * ```
622
+ */
623
+ withCheckpointer(checkpointer) {
624
+ this.config.checkpointer = checkpointer;
625
+ return this;
626
+ }
589
627
  /**
590
628
  * Build the ReAct agent
591
629
  *
@@ -605,7 +643,8 @@ var ReActAgentBuilder = class {
605
643
  systemPrompt: this.config.systemPrompt || DEFAULT_REACT_SYSTEM_PROMPT,
606
644
  maxIterations: this.config.maxIterations ?? 10,
607
645
  returnIntermediateSteps: this.config.returnIntermediateSteps ?? false,
608
- stopCondition: this.config.stopCondition
646
+ stopCondition: this.config.stopCondition,
647
+ checkpointer: this.config.checkpointer
609
648
  };
610
649
  return createReActAgent(finalConfig, this.options);
611
650
  }
@@ -2060,67 +2099,7 @@ var MultiAgentStateConfig = {
2060
2099
  var MultiAgentState = createStateAnnotation4(MultiAgentStateConfig);
2061
2100
 
2062
2101
  // src/multi-agent/routing.ts
2063
- import { HumanMessage as HumanMessage4, SystemMessage as SystemMessage4, AIMessage as AIMessage2, ToolMessage as ToolMessage2 } from "@langchain/core/messages";
2064
- import { createLogger as createLogger2, LogLevel } from "@agentforge/core";
2065
- var logLevel = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
2066
- var logger = createLogger2("multi-agent:routing", { level: logLevel });
2067
- async function executeTools(toolCalls, tools) {
2068
- const results = [];
2069
- logger.debug("Executing tools", {
2070
- toolCallCount: toolCalls.length,
2071
- toolNames: toolCalls.map((tc) => tc.name)
2072
- });
2073
- for (const toolCall of toolCalls) {
2074
- const tool = tools.find((t) => t.metadata.name === toolCall.name);
2075
- if (!tool) {
2076
- logger.warn("Tool not found", {
2077
- toolName: toolCall.name,
2078
- availableTools: tools.map((t) => t.metadata.name)
2079
- });
2080
- results.push(new ToolMessage2({
2081
- content: `Error: Tool '${toolCall.name}' not found`,
2082
- tool_call_id: toolCall.id
2083
- }));
2084
- continue;
2085
- }
2086
- try {
2087
- logger.debug("Executing tool", {
2088
- toolName: toolCall.name,
2089
- args: toolCall.args
2090
- });
2091
- const result = await tool.execute(toolCall.args);
2092
- const content = typeof result === "string" ? result : JSON.stringify(result);
2093
- logger.debug("Tool execution successful", {
2094
- toolName: toolCall.name,
2095
- resultLength: content.length
2096
- });
2097
- results.push(new ToolMessage2({
2098
- content,
2099
- tool_call_id: toolCall.id
2100
- }));
2101
- } catch (error) {
2102
- logger.error("Tool execution failed", {
2103
- toolName: toolCall.name,
2104
- error: error.message
2105
- });
2106
- results.push(new ToolMessage2({
2107
- content: `Error executing tool: ${error.message}`,
2108
- tool_call_id: toolCall.id
2109
- }));
2110
- }
2111
- }
2112
- logger.debug("Tool execution complete", {
2113
- successCount: results.filter((r) => {
2114
- const content = typeof r.content === "string" ? r.content : JSON.stringify(r.content);
2115
- return !content.startsWith("Error");
2116
- }).length,
2117
- errorCount: results.filter((r) => {
2118
- const content = typeof r.content === "string" ? r.content : JSON.stringify(r.content);
2119
- return content.startsWith("Error");
2120
- }).length
2121
- });
2122
- return results;
2123
- }
2102
+ import { HumanMessage as HumanMessage4, SystemMessage as SystemMessage4 } from "@langchain/core/messages";
2124
2103
  var DEFAULT_SUPERVISOR_SYSTEM_PROMPT = `You are a supervisor agent responsible for routing tasks to specialized worker agents.
2125
2104
 
2126
2105
  Your job is to:
@@ -2156,151 +2135,48 @@ Choose parallel routing when the task benefits from multiple perspectives or dat
2156
2135
  var llmBasedRouting = {
2157
2136
  name: "llm-based",
2158
2137
  async route(state, config) {
2159
- logger.info("Starting LLM-based routing", {
2160
- iteration: state.iteration,
2161
- availableWorkers: Object.keys(state.workers).length
2162
- });
2163
2138
  if (!config.model) {
2164
2139
  throw new Error("LLM-based routing requires a model to be configured");
2165
2140
  }
2166
2141
  const systemPrompt = config.systemPrompt || DEFAULT_SUPERVISOR_SYSTEM_PROMPT;
2167
- const maxRetries = config.maxToolRetries || 3;
2168
- const tools = config.tools || [];
2169
2142
  const workerInfo = Object.entries(state.workers).map(([id, caps]) => {
2170
2143
  const skills = caps.skills.join(", ");
2171
- const tools2 = caps.tools.join(", ");
2144
+ const tools = caps.tools.join(", ");
2172
2145
  const available = caps.available ? "available" : "busy";
2173
- return `- ${id}: Skills: [${skills}], Tools: [${tools2}], Status: ${available}, Workload: ${caps.currentWorkload}`;
2146
+ return `- ${id}: Skills: [${skills}], Tools: [${tools}], Status: ${available}, Workload: ${caps.currentWorkload}`;
2174
2147
  }).join("\n");
2175
- logger.debug("Worker capabilities", {
2176
- workers: Object.entries(state.workers).map(([id, caps]) => ({
2177
- id,
2178
- skills: caps.skills,
2179
- available: caps.available,
2180
- workload: caps.currentWorkload
2181
- }))
2182
- });
2183
2148
  const lastMessage = state.messages[state.messages.length - 1];
2184
2149
  const taskContext = lastMessage?.content || state.input;
2185
- logger.debug("Task context", {
2186
- taskLength: taskContext.length,
2187
- taskPreview: taskContext.substring(0, 100)
2188
- });
2189
2150
  const userPrompt = `Current task: ${taskContext}
2190
2151
 
2191
2152
  Available workers:
2192
2153
  ${workerInfo}
2193
2154
 
2194
2155
  Select the best worker(s) for this task and explain your reasoning.`;
2195
- const conversationHistory = [];
2196
- let attempt = 0;
2197
- while (attempt < maxRetries) {
2198
- logger.debug("LLM routing attempt", {
2199
- attempt: attempt + 1,
2200
- maxRetries,
2201
- conversationHistoryLength: conversationHistory.length
2202
- });
2203
- const messages = [
2204
- new SystemMessage4(systemPrompt),
2205
- new HumanMessage4(userPrompt),
2206
- ...conversationHistory
2207
- ];
2208
- const response = await config.model.invoke(messages);
2209
- if (response.tool_calls && response.tool_calls.length > 0) {
2210
- logger.info("LLM requested tool calls", {
2211
- toolCount: response.tool_calls.length,
2212
- toolNames: response.tool_calls.map((tc) => tc.name)
2213
- });
2214
- if (tools.length === 0) {
2215
- throw new Error("LLM requested tool calls but no tools are configured");
2216
- }
2217
- const toolResults = await executeTools(response.tool_calls, tools);
2218
- conversationHistory.push(
2219
- new AIMessage2({ content: response.content || "", tool_calls: response.tool_calls }),
2220
- ...toolResults
2221
- );
2222
- attempt++;
2223
- logger.debug("Retrying routing with tool results", { attempt });
2224
- continue;
2225
- }
2226
- logger.debug("Parsing routing decision from LLM response");
2227
- let decision;
2228
- if (response && typeof response === "object" && ("targetAgent" in response || "targetAgents" in response)) {
2229
- logger.debug("Response is structured output", {
2230
- hasTargetAgent: "targetAgent" in response,
2231
- hasTargetAgents: "targetAgents" in response
2232
- });
2233
- decision = response;
2234
- } else if (response.content) {
2235
- if (typeof response.content === "string") {
2236
- try {
2237
- decision = JSON.parse(response.content);
2238
- logger.debug("Parsed JSON from string response");
2239
- } catch (error) {
2240
- logger.error("Failed to parse routing decision", {
2241
- content: response.content,
2242
- error: error instanceof Error ? error.message : String(error)
2243
- });
2244
- throw new Error(`Failed to parse routing decision from LLM. Expected JSON but got: ${response.content}`);
2245
- }
2246
- } else if (typeof response.content === "object") {
2247
- logger.debug("Response content is already an object");
2248
- decision = response.content;
2249
- } else {
2250
- logger.error("Unexpected response content type", {
2251
- type: typeof response.content
2252
- });
2253
- throw new Error(`Unexpected response content type: ${typeof response.content}`);
2254
- }
2255
- } else {
2256
- logger.error("Unexpected response format", {
2257
- response: JSON.stringify(response)
2258
- });
2259
- throw new Error(`Unexpected response format: ${JSON.stringify(response)}`);
2260
- }
2261
- const result = {
2262
- targetAgent: decision.targetAgent,
2263
- targetAgents: decision.targetAgents,
2264
- reasoning: decision.reasoning,
2265
- confidence: decision.confidence,
2266
- strategy: "llm-based",
2267
- timestamp: Date.now()
2268
- };
2269
- logger.info("LLM routing decision made", {
2270
- targetAgent: result.targetAgent,
2271
- targetAgents: result.targetAgents,
2272
- isParallel: result.targetAgents && result.targetAgents.length > 1,
2273
- confidence: result.confidence,
2274
- reasoning: result.reasoning
2275
- });
2276
- return result;
2277
- }
2278
- logger.error("Max tool retries exceeded", { maxRetries });
2279
- throw new Error(`Max tool retries (${maxRetries}) exceeded without routing decision`);
2156
+ const messages = [
2157
+ new SystemMessage4(systemPrompt),
2158
+ new HumanMessage4(userPrompt)
2159
+ ];
2160
+ const decision = await config.model.invoke(messages);
2161
+ return {
2162
+ targetAgent: decision.targetAgent,
2163
+ targetAgents: decision.targetAgents,
2164
+ reasoning: decision.reasoning,
2165
+ confidence: decision.confidence,
2166
+ strategy: "llm-based",
2167
+ timestamp: Date.now()
2168
+ };
2280
2169
  }
2281
2170
  };
2282
2171
  var roundRobinRouting = {
2283
2172
  name: "round-robin",
2284
2173
  async route(state, config) {
2285
- logger.info("Starting round-robin routing", {
2286
- iteration: state.iteration
2287
- });
2288
2174
  const availableWorkers = Object.entries(state.workers).filter(([_, caps]) => caps.available).map(([id]) => id);
2289
- logger.debug("Available workers for round-robin", {
2290
- count: availableWorkers.length,
2291
- workers: availableWorkers
2292
- });
2293
2175
  if (availableWorkers.length === 0) {
2294
- logger.error("No available workers for round-robin routing");
2295
2176
  throw new Error("No available workers for round-robin routing");
2296
2177
  }
2297
2178
  const lastRoutingIndex = state.routingHistory.length % availableWorkers.length;
2298
2179
  const targetAgent = availableWorkers[lastRoutingIndex];
2299
- logger.info("Round-robin routing decision", {
2300
- targetAgent,
2301
- index: lastRoutingIndex + 1,
2302
- totalWorkers: availableWorkers.length
2303
- });
2304
2180
  return {
2305
2181
  targetAgent,
2306
2182
  targetAgents: null,
@@ -2314,15 +2190,8 @@ var roundRobinRouting = {
2314
2190
  var skillBasedRouting = {
2315
2191
  name: "skill-based",
2316
2192
  async route(state, config) {
2317
- logger.info("Starting skill-based routing", {
2318
- iteration: state.iteration
2319
- });
2320
2193
  const lastMessage = state.messages[state.messages.length - 1];
2321
2194
  const taskContent = (lastMessage?.content || state.input).toLowerCase();
2322
- logger.debug("Task content for skill matching", {
2323
- taskLength: taskContent.length,
2324
- taskPreview: taskContent.substring(0, 100)
2325
- });
2326
2195
  const workerScores = Object.entries(state.workers).filter(([_, caps]) => caps.available).map(([id, caps]) => {
2327
2196
  const skillMatches = caps.skills.filter(
2328
2197
  (skill) => taskContent.includes(skill.toLowerCase())
@@ -2333,20 +2202,11 @@ var skillBasedRouting = {
2333
2202
  const score = skillMatches * 2 + toolMatches;
2334
2203
  return { id, score, skills: caps.skills, tools: caps.tools };
2335
2204
  }).filter((w) => w.score > 0).sort((a, b) => b.score - a.score);
2336
- logger.debug("Worker skill scores", {
2337
- scoredWorkers: workerScores.map((w) => ({ id: w.id, score: w.score }))
2338
- });
2339
2205
  if (workerScores.length === 0) {
2340
- logger.warn("No skill matches found, using fallback");
2341
2206
  const firstAvailable = Object.entries(state.workers).find(([_, caps]) => caps.available);
2342
2207
  if (!firstAvailable) {
2343
- logger.error("No available workers for skill-based routing");
2344
2208
  throw new Error("No available workers for skill-based routing");
2345
2209
  }
2346
- logger.info("Skill-based routing fallback decision", {
2347
- targetAgent: firstAvailable[0],
2348
- confidence: 0.5
2349
- });
2350
2210
  return {
2351
2211
  targetAgent: firstAvailable[0],
2352
2212
  targetAgents: null,
@@ -2358,12 +2218,6 @@ var skillBasedRouting = {
2358
2218
  }
2359
2219
  const best = workerScores[0];
2360
2220
  const confidence = Math.min(best.score / 5, 1);
2361
- logger.info("Skill-based routing decision", {
2362
- targetAgent: best.id,
2363
- score: best.score,
2364
- confidence,
2365
- matchedSkills: best.skills
2366
- });
2367
2221
  return {
2368
2222
  targetAgent: best.id,
2369
2223
  targetAgents: null,
@@ -2377,26 +2231,13 @@ var skillBasedRouting = {
2377
2231
  var loadBalancedRouting = {
2378
2232
  name: "load-balanced",
2379
2233
  async route(state, config) {
2380
- logger.info("Starting load-balanced routing", {
2381
- iteration: state.iteration
2382
- });
2383
2234
  const availableWorkers = Object.entries(state.workers).filter(([_, caps]) => caps.available).map(([id, caps]) => ({ id, workload: caps.currentWorkload })).sort((a, b) => a.workload - b.workload);
2384
- logger.debug("Worker workloads", {
2385
- workers: availableWorkers.map((w) => ({ id: w.id, workload: w.workload }))
2386
- });
2387
2235
  if (availableWorkers.length === 0) {
2388
- logger.error("No available workers for load-balanced routing");
2389
2236
  throw new Error("No available workers for load-balanced routing");
2390
2237
  }
2391
2238
  const targetWorker = availableWorkers[0];
2392
2239
  const avgWorkload = availableWorkers.reduce((sum, w) => sum + w.workload, 0) / availableWorkers.length;
2393
2240
  const confidence = targetWorker.workload === 0 ? 1 : Math.max(0.5, 1 - targetWorker.workload / (avgWorkload * 2));
2394
- logger.info("Load-balanced routing decision", {
2395
- targetAgent: targetWorker.id,
2396
- workload: targetWorker.workload,
2397
- avgWorkload: avgWorkload.toFixed(1),
2398
- confidence
2399
- });
2400
2241
  return {
2401
2242
  targetAgent: targetWorker.id,
2402
2243
  targetAgents: null,
@@ -2410,24 +2251,13 @@ var loadBalancedRouting = {
2410
2251
  var ruleBasedRouting = {
2411
2252
  name: "rule-based",
2412
2253
  async route(state, config) {
2413
- logger.info("Starting rule-based routing", {
2414
- iteration: state.iteration
2415
- });
2416
2254
  if (!config.routingFn) {
2417
- logger.error("Rule-based routing requires a custom routing function");
2418
2255
  throw new Error("Rule-based routing requires a custom routing function");
2419
2256
  }
2420
- const decision = await config.routingFn(state);
2421
- logger.info("Rule-based routing decision", {
2422
- targetAgent: decision.targetAgent,
2423
- targetAgents: decision.targetAgents,
2424
- confidence: decision.confidence
2425
- });
2426
- return decision;
2257
+ return await config.routingFn(state);
2427
2258
  }
2428
2259
  };
2429
2260
  function getRoutingStrategy(name) {
2430
- logger.debug("Getting routing strategy", { name });
2431
2261
  switch (name) {
2432
2262
  case "llm-based":
2433
2263
  return llmBasedRouting;
@@ -2440,15 +2270,14 @@ function getRoutingStrategy(name) {
2440
2270
  case "rule-based":
2441
2271
  return ruleBasedRouting;
2442
2272
  default:
2443
- logger.error("Unknown routing strategy", { name });
2444
2273
  throw new Error(`Unknown routing strategy: ${name}`);
2445
2274
  }
2446
2275
  }
2447
2276
 
2448
2277
  // src/multi-agent/utils.ts
2449
- import { createLogger as createLogger3, LogLevel as LogLevel2 } from "@agentforge/core";
2450
- var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel2.INFO;
2451
- var logger2 = createLogger3("multi-agent", { level: logLevel2 });
2278
+ import { createLogger as createLogger2, LogLevel } from "@agentforge/core";
2279
+ var logLevel = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
2280
+ var logger = createLogger2("multi-agent", { level: logLevel });
2452
2281
  function isReActAgent(obj) {
2453
2282
  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
2454
2283
  (obj.constructor?.name === "CompiledGraph" || obj.constructor?.name === "CompiledStateGraph");
@@ -2456,9 +2285,9 @@ function isReActAgent(obj) {
2456
2285
  function wrapReActAgent(workerId, agent, verbose = false) {
2457
2286
  return async (state, config) => {
2458
2287
  try {
2459
- logger2.debug("Wrapping ReAct agent execution", { workerId });
2288
+ logger.debug("Wrapping ReAct agent execution", { workerId });
2460
2289
  const task = state.messages[state.messages.length - 1]?.content || state.input;
2461
- logger2.debug("Extracted task", {
2290
+ logger.debug("Extracted task", {
2462
2291
  workerId,
2463
2292
  taskPreview: task.substring(0, 100) + (task.length > 100 ? "..." : "")
2464
2293
  });
@@ -2466,25 +2295,39 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2466
2295
  (assignment) => assignment.workerId === workerId && !state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2467
2296
  );
2468
2297
  if (!currentAssignment) {
2469
- logger2.debug("No active assignment found", { workerId });
2298
+ logger.debug("No active assignment found", { workerId });
2470
2299
  return {};
2471
2300
  }
2301
+ const workerThreadId = config?.configurable?.thread_id ? `${config.configurable.thread_id}:worker:${workerId}` : void 0;
2302
+ const workerConfig = workerThreadId ? {
2303
+ ...config,
2304
+ configurable: {
2305
+ ...config.configurable,
2306
+ thread_id: workerThreadId
2307
+ }
2308
+ } : config;
2309
+ logger.debug("Invoking ReAct agent with worker-specific config", {
2310
+ workerId,
2311
+ parentThreadId: config?.configurable?.thread_id,
2312
+ workerThreadId,
2313
+ hasConfig: !!workerConfig
2314
+ });
2472
2315
  const result = await agent.invoke(
2473
2316
  {
2474
2317
  messages: [{ role: "user", content: task }]
2475
2318
  },
2476
- config
2477
- // Pass through the config for checkpointing and interrupt support
2319
+ workerConfig
2320
+ // Worker-specific config with unique thread_id
2478
2321
  );
2479
2322
  const response = result.messages?.[result.messages.length - 1]?.content || "No response";
2480
- logger2.debug("Received response from ReAct agent", {
2323
+ logger.debug("Received response from ReAct agent", {
2481
2324
  workerId,
2482
2325
  responsePreview: response.substring(0, 100) + (response.length > 100 ? "..." : "")
2483
2326
  });
2484
2327
  const toolsUsed = result.actions?.map((action) => action.name).filter(Boolean) || [];
2485
2328
  const uniqueTools = [...new Set(toolsUsed)];
2486
2329
  if (uniqueTools.length > 0) {
2487
- logger2.debug("Tools used by ReAct agent", { workerId, tools: uniqueTools });
2330
+ logger.debug("Tools used by ReAct agent", { workerId, tools: uniqueTools });
2488
2331
  }
2489
2332
  const taskResult = {
2490
2333
  assignmentId: currentAssignment.id,
@@ -2503,7 +2346,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2503
2346
  };
2504
2347
  } catch (error) {
2505
2348
  const errorMessage = handleNodeError(error, `react-agent:${workerId}`, false);
2506
- logger2.error("Error in ReAct agent execution", {
2349
+ logger.error("Error in ReAct agent execution", {
2507
2350
  workerId,
2508
2351
  error: errorMessage
2509
2352
  });
@@ -2535,9 +2378,9 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2535
2378
 
2536
2379
  // src/multi-agent/nodes.ts
2537
2380
  import { HumanMessage as HumanMessage5, SystemMessage as SystemMessage5 } from "@langchain/core/messages";
2538
- import { toLangChainTools as toLangChainTools2, createLogger as createLogger4, LogLevel as LogLevel3 } from "@agentforge/core";
2539
- var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel3.INFO;
2540
- var logger3 = createLogger4("multi-agent:nodes", { level: logLevel3 });
2381
+ import { toLangChainTools as toLangChainTools2, createLogger as createLogger3, LogLevel as LogLevel2 } from "@agentforge/core";
2382
+ var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel2.INFO;
2383
+ var logger2 = createLogger3("multi-agent:nodes", { level: logLevel2 });
2541
2384
  var DEFAULT_AGGREGATOR_SYSTEM_PROMPT = `You are an aggregator agent responsible for combining results from multiple worker agents.
2542
2385
 
2543
2386
  Your job is to:
@@ -2555,19 +2398,19 @@ function createSupervisorNode(config) {
2555
2398
  } = config;
2556
2399
  return async (state) => {
2557
2400
  try {
2558
- logger3.info("Supervisor node executing", {
2401
+ logger2.info("Supervisor node executing", {
2559
2402
  iteration: state.iteration,
2560
2403
  maxIterations,
2561
2404
  activeAssignments: state.activeAssignments.length,
2562
2405
  completedTasks: state.completedTasks.length
2563
2406
  });
2564
- logger3.debug(`Routing iteration ${state.iteration}/${maxIterations}`);
2407
+ logger2.debug(`Routing iteration ${state.iteration}/${maxIterations}`);
2565
2408
  if (state.iteration >= maxIterations) {
2566
- logger3.warn("Max iterations reached", {
2409
+ logger2.warn("Max iterations reached", {
2567
2410
  iteration: state.iteration,
2568
2411
  maxIterations
2569
2412
  });
2570
- logger3.debug("Max iterations reached, moving to aggregation");
2413
+ logger2.debug("Max iterations reached, moving to aggregation");
2571
2414
  return {
2572
2415
  status: "aggregating",
2573
2416
  currentAgent: "aggregator"
@@ -2576,26 +2419,26 @@ function createSupervisorNode(config) {
2576
2419
  const allCompleted = state.activeAssignments.every(
2577
2420
  (assignment) => state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2578
2421
  );
2579
- logger3.debug("Checking task completion", {
2422
+ logger2.debug("Checking task completion", {
2580
2423
  activeAssignments: state.activeAssignments.length,
2581
2424
  completedTasks: state.completedTasks.length,
2582
2425
  allCompleted
2583
2426
  });
2584
2427
  if (allCompleted && state.activeAssignments.length > 0) {
2585
- logger3.info("All tasks completed, moving to aggregation", {
2428
+ logger2.info("All tasks completed, moving to aggregation", {
2586
2429
  completedCount: state.completedTasks.length
2587
2430
  });
2588
- logger3.debug("All tasks completed, moving to aggregation");
2431
+ logger2.debug("All tasks completed, moving to aggregation");
2589
2432
  return {
2590
2433
  status: "aggregating",
2591
2434
  currentAgent: "aggregator"
2592
2435
  };
2593
2436
  }
2594
- logger3.debug("Getting routing strategy", { strategy });
2437
+ logger2.debug("Getting routing strategy", { strategy });
2595
2438
  const routingImpl = getRoutingStrategy(strategy);
2596
2439
  const decision = await routingImpl.route(state, config);
2597
2440
  const targetAgents = decision.targetAgents && decision.targetAgents.length > 0 ? decision.targetAgents : decision.targetAgent ? [decision.targetAgent] : [];
2598
- logger3.debug("Target agents determined", {
2441
+ logger2.debug("Target agents determined", {
2599
2442
  targetAgents,
2600
2443
  isParallel: targetAgents.length > 1,
2601
2444
  decision: {
@@ -2604,17 +2447,17 @@ function createSupervisorNode(config) {
2604
2447
  }
2605
2448
  });
2606
2449
  if (targetAgents.length === 0) {
2607
- logger3.error("No target agents specified in routing decision");
2450
+ logger2.error("No target agents specified in routing decision");
2608
2451
  throw new Error("Routing decision must specify at least one target agent");
2609
2452
  }
2610
2453
  if (targetAgents.length === 1) {
2611
- logger3.info("Routing to single agent", {
2454
+ logger2.info("Routing to single agent", {
2612
2455
  targetAgent: targetAgents[0],
2613
2456
  reasoning: decision.reasoning,
2614
2457
  confidence: decision.confidence
2615
2458
  });
2616
2459
  } else {
2617
- logger3.info("Routing to multiple agents in parallel", {
2460
+ logger2.info("Routing to multiple agents in parallel", {
2618
2461
  targetAgents,
2619
2462
  count: targetAgents.length,
2620
2463
  reasoning: decision.reasoning,
@@ -2622,9 +2465,9 @@ function createSupervisorNode(config) {
2622
2465
  });
2623
2466
  }
2624
2467
  if (targetAgents.length === 1) {
2625
- logger3.debug(`Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2468
+ logger2.debug(`Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2626
2469
  } else {
2627
- logger3.debug(`Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`);
2470
+ logger2.debug(`Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`);
2628
2471
  }
2629
2472
  const task = state.messages[state.messages.length - 1]?.content || state.input;
2630
2473
  const assignments = targetAgents.map((workerId) => ({
@@ -2634,7 +2477,7 @@ function createSupervisorNode(config) {
2634
2477
  priority: 5,
2635
2478
  assignedAt: Date.now()
2636
2479
  }));
2637
- logger3.debug("Created task assignments", {
2480
+ logger2.debug("Created task assignments", {
2638
2481
  assignmentCount: assignments.length,
2639
2482
  assignments: assignments.map((a) => ({
2640
2483
  id: a.id,
@@ -2654,7 +2497,7 @@ function createSupervisorNode(config) {
2654
2497
  priority: assignment.priority
2655
2498
  }
2656
2499
  }));
2657
- logger3.info("Supervisor routing complete", {
2500
+ logger2.info("Supervisor routing complete", {
2658
2501
  currentAgent: targetAgents.join(","),
2659
2502
  status: "executing",
2660
2503
  assignmentCount: assignments.length,
@@ -2671,7 +2514,7 @@ function createSupervisorNode(config) {
2671
2514
  iteration: state.iteration + 1
2672
2515
  };
2673
2516
  } catch (error) {
2674
- logger3.error("Supervisor node error", {
2517
+ logger2.error("Supervisor node error", {
2675
2518
  error: error instanceof Error ? error.message : String(error),
2676
2519
  stack: error instanceof Error ? error.stack : void 0,
2677
2520
  iteration: state.iteration
@@ -2696,7 +2539,7 @@ function createWorkerNode(config) {
2696
2539
  } = config;
2697
2540
  return async (state, runConfig) => {
2698
2541
  try {
2699
- logger3.info("Worker node executing", {
2542
+ logger2.info("Worker node executing", {
2700
2543
  workerId: id,
2701
2544
  iteration: state.iteration,
2702
2545
  activeAssignments: state.activeAssignments.length
@@ -2705,39 +2548,39 @@ function createWorkerNode(config) {
2705
2548
  (assignment) => assignment.workerId === id && !state.completedTasks.some((task) => task.assignmentId === assignment.id)
2706
2549
  );
2707
2550
  if (!currentAssignment) {
2708
- logger3.debug("No active assignment found for worker", {
2551
+ logger2.debug("No active assignment found for worker", {
2709
2552
  workerId: id,
2710
2553
  totalActiveAssignments: state.activeAssignments.length,
2711
2554
  completedTasks: state.completedTasks.length
2712
2555
  });
2713
2556
  return {};
2714
2557
  }
2715
- logger3.info("Worker processing assignment", {
2558
+ logger2.info("Worker processing assignment", {
2716
2559
  workerId: id,
2717
2560
  assignmentId: currentAssignment.id,
2718
2561
  taskLength: currentAssignment.task.length,
2719
2562
  taskPreview: currentAssignment.task.substring(0, 100)
2720
2563
  });
2721
2564
  if (executeFn) {
2722
- logger3.debug("Using custom execution function", { workerId: id });
2565
+ logger2.debug("Using custom execution function", { workerId: id });
2723
2566
  return await executeFn(state, runConfig);
2724
2567
  }
2725
2568
  if (agent) {
2726
2569
  if (isReActAgent(agent)) {
2727
- logger3.debug("Using ReAct agent", { workerId: id });
2570
+ logger2.debug("Using ReAct agent", { workerId: id });
2728
2571
  const wrappedFn = wrapReActAgent(id, agent, verbose);
2729
2572
  return await wrappedFn(state, runConfig);
2730
2573
  } else {
2731
- logger3.warn("Agent provided but not a ReAct agent, falling back", { workerId: id });
2574
+ logger2.warn("Agent provided but not a ReAct agent, falling back", { workerId: id });
2732
2575
  }
2733
2576
  }
2734
2577
  if (!model) {
2735
- logger3.error("Worker missing required configuration", { workerId: id });
2578
+ logger2.error("Worker missing required configuration", { workerId: id });
2736
2579
  throw new Error(
2737
2580
  `Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
2738
2581
  );
2739
2582
  }
2740
- logger3.debug("Using default LLM execution", {
2583
+ logger2.debug("Using default LLM execution", {
2741
2584
  workerId: id,
2742
2585
  hasTools: tools.length > 0,
2743
2586
  toolCount: tools.length
@@ -2753,7 +2596,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2753
2596
  ];
2754
2597
  let modelToUse = model;
2755
2598
  if (tools.length > 0 && model.bindTools) {
2756
- logger3.debug("Binding tools to model", {
2599
+ logger2.debug("Binding tools to model", {
2757
2600
  workerId: id,
2758
2601
  toolCount: tools.length,
2759
2602
  toolNames: tools.map((t) => t.metadata.name)
@@ -2761,10 +2604,10 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2761
2604
  const langchainTools = toLangChainTools2(tools);
2762
2605
  modelToUse = model.bindTools(langchainTools);
2763
2606
  }
2764
- logger3.debug("Invoking LLM", { workerId: id });
2607
+ logger2.debug("Invoking LLM", { workerId: id });
2765
2608
  const response = await modelToUse.invoke(messages);
2766
2609
  const result = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2767
- logger3.info("Worker task completed", {
2610
+ logger2.info("Worker task completed", {
2768
2611
  workerId: id,
2769
2612
  assignmentId: currentAssignment.id,
2770
2613
  resultLength: result.length,
@@ -2799,7 +2642,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2799
2642
  currentWorkload: Math.max(0, capabilities.currentWorkload - 1)
2800
2643
  }
2801
2644
  };
2802
- logger3.debug("Worker state update", {
2645
+ logger2.debug("Worker state update", {
2803
2646
  workerId: id,
2804
2647
  newWorkload: updatedWorkers[id].currentWorkload
2805
2648
  });
@@ -2810,7 +2653,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2810
2653
  };
2811
2654
  } catch (error) {
2812
2655
  const errorMessage = handleNodeError(error, `worker:${id}`, false);
2813
- logger3.error("Worker node error", {
2656
+ logger2.error("Worker node error", {
2814
2657
  workerId: id,
2815
2658
  error: errorMessage
2816
2659
  });
@@ -2818,7 +2661,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2818
2661
  (assignment) => assignment.workerId === id
2819
2662
  );
2820
2663
  if (currentAssignment) {
2821
- logger3.warn("Creating error result for assignment", {
2664
+ logger2.warn("Creating error result for assignment", {
2822
2665
  workerId: id,
2823
2666
  assignmentId: currentAssignment.id
2824
2667
  });
@@ -2836,7 +2679,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2836
2679
  status: "routing"
2837
2680
  };
2838
2681
  }
2839
- logger3.error("No assignment found for error handling", { workerId: id });
2682
+ logger2.error("No assignment found for error handling", { workerId: id });
2840
2683
  return {
2841
2684
  status: "failed",
2842
2685
  error: errorMessage
@@ -2853,16 +2696,16 @@ function createAggregatorNode(config = {}) {
2853
2696
  } = config;
2854
2697
  return async (state) => {
2855
2698
  try {
2856
- logger3.info("Aggregator node executing", {
2699
+ logger2.info("Aggregator node executing", {
2857
2700
  completedTasks: state.completedTasks.length,
2858
2701
  successfulTasks: state.completedTasks.filter((t) => t.success).length,
2859
2702
  failedTasks: state.completedTasks.filter((t) => !t.success).length
2860
2703
  });
2861
- logger3.debug("Combining results from workers");
2704
+ logger2.debug("Combining results from workers");
2862
2705
  if (aggregateFn) {
2863
- logger3.debug("Using custom aggregation function");
2706
+ logger2.debug("Using custom aggregation function");
2864
2707
  const response2 = await aggregateFn(state);
2865
- logger3.info("Custom aggregation complete", {
2708
+ logger2.info("Custom aggregation complete", {
2866
2709
  responseLength: response2.length
2867
2710
  });
2868
2711
  return {
@@ -2871,16 +2714,16 @@ function createAggregatorNode(config = {}) {
2871
2714
  };
2872
2715
  }
2873
2716
  if (state.completedTasks.length === 0) {
2874
- logger3.warn("No completed tasks to aggregate");
2717
+ logger2.warn("No completed tasks to aggregate");
2875
2718
  return {
2876
2719
  response: "No tasks were completed.",
2877
2720
  status: "completed"
2878
2721
  };
2879
2722
  }
2880
2723
  if (!model) {
2881
- logger3.debug("No model provided, concatenating results");
2724
+ logger2.debug("No model provided, concatenating results");
2882
2725
  const combinedResults = state.completedTasks.filter((task) => task.success).map((task) => task.result).join("\n\n");
2883
- logger3.info("Simple concatenation complete", {
2726
+ logger2.info("Simple concatenation complete", {
2884
2727
  resultLength: combinedResults.length
2885
2728
  });
2886
2729
  return {
@@ -2888,7 +2731,7 @@ function createAggregatorNode(config = {}) {
2888
2731
  status: "completed"
2889
2732
  };
2890
2733
  }
2891
- logger3.debug("Using LLM for intelligent aggregation", {
2734
+ logger2.debug("Using LLM for intelligent aggregation", {
2892
2735
  taskCount: state.completedTasks.length
2893
2736
  });
2894
2737
  const taskResults = state.completedTasks.map((task, idx) => {
@@ -2907,20 +2750,20 @@ Please synthesize these results into a comprehensive response that addresses the
2907
2750
  new SystemMessage5(systemPrompt),
2908
2751
  new HumanMessage5(userPrompt)
2909
2752
  ];
2910
- logger3.debug("Invoking aggregation LLM");
2753
+ logger2.debug("Invoking aggregation LLM");
2911
2754
  const response = await model.invoke(messages);
2912
2755
  const aggregatedResponse = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2913
- logger3.info("Aggregation complete", {
2756
+ logger2.info("Aggregation complete", {
2914
2757
  responseLength: aggregatedResponse.length,
2915
2758
  responsePreview: aggregatedResponse.substring(0, 100)
2916
2759
  });
2917
- logger3.debug("Aggregation complete");
2760
+ logger2.debug("Aggregation complete");
2918
2761
  return {
2919
2762
  response: aggregatedResponse,
2920
2763
  status: "completed"
2921
2764
  };
2922
2765
  } catch (error) {
2923
- logger3.error("Aggregator node error", {
2766
+ logger2.error("Aggregator node error", {
2924
2767
  error: error instanceof Error ? error.message : String(error),
2925
2768
  stack: error instanceof Error ? error.stack : void 0,
2926
2769
  completedTasks: state.completedTasks.length
@@ -2935,9 +2778,9 @@ Please synthesize these results into a comprehensive response that addresses the
2935
2778
 
2936
2779
  // src/multi-agent/agent.ts
2937
2780
  import { StateGraph as StateGraph4, END as END4 } from "@langchain/langgraph";
2938
- import { toLangChainTools as toLangChainTools3, createLogger as createLogger5, LogLevel as LogLevel4 } from "@agentforge/core";
2939
- var logLevel4 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel4.INFO;
2940
- var logger4 = createLogger5("multi-agent:system", { level: logLevel4 });
2781
+ import { createLogger as createLogger4, LogLevel as LogLevel3 } from "@agentforge/core";
2782
+ var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel3.INFO;
2783
+ var logger3 = createLogger4("multi-agent:system", { level: logLevel3 });
2941
2784
  function createMultiAgentSystem(config) {
2942
2785
  const {
2943
2786
  supervisor,
@@ -2954,10 +2797,6 @@ function createMultiAgentSystem(config) {
2954
2797
  if (supervisor.strategy === "llm-based") {
2955
2798
  configuredModel = configuredModel.withStructuredOutput(RoutingDecisionSchema);
2956
2799
  }
2957
- if (supervisor.tools && supervisor.tools.length > 0) {
2958
- const langchainTools = toLangChainTools3(supervisor.tools);
2959
- configuredModel = configuredModel.bindTools(langchainTools);
2960
- }
2961
2800
  supervisorConfig.model = configuredModel;
2962
2801
  }
2963
2802
  const supervisorNode = createSupervisorNode(supervisorConfig);
@@ -2979,46 +2818,46 @@ function createMultiAgentSystem(config) {
2979
2818
  });
2980
2819
  workflow.addNode("aggregator", aggregatorNode);
2981
2820
  const supervisorRouter = (state) => {
2982
- logger4.debug("Supervisor router executing", {
2821
+ logger3.debug("Supervisor router executing", {
2983
2822
  status: state.status,
2984
2823
  currentAgent: state.currentAgent,
2985
2824
  iteration: state.iteration
2986
2825
  });
2987
2826
  if (state.status === "completed" || state.status === "failed") {
2988
- logger4.info("Supervisor router: ending workflow", { status: state.status });
2827
+ logger3.info("Supervisor router: ending workflow", { status: state.status });
2989
2828
  return END4;
2990
2829
  }
2991
2830
  if (state.status === "aggregating") {
2992
- logger4.info("Supervisor router: routing to aggregator");
2831
+ logger3.info("Supervisor router: routing to aggregator");
2993
2832
  return "aggregator";
2994
2833
  }
2995
2834
  if (state.currentAgent && state.currentAgent !== "supervisor") {
2996
2835
  if (state.currentAgent.includes(",")) {
2997
2836
  const agents = state.currentAgent.split(",").map((a) => a.trim());
2998
- logger4.info("Supervisor router: parallel routing", {
2837
+ logger3.info("Supervisor router: parallel routing", {
2999
2838
  agents,
3000
2839
  count: agents.length
3001
2840
  });
3002
2841
  return agents;
3003
2842
  }
3004
- logger4.info("Supervisor router: single agent routing", {
2843
+ logger3.info("Supervisor router: single agent routing", {
3005
2844
  targetAgent: state.currentAgent
3006
2845
  });
3007
2846
  return state.currentAgent;
3008
2847
  }
3009
- logger4.debug("Supervisor router: staying at supervisor");
2848
+ logger3.debug("Supervisor router: staying at supervisor");
3010
2849
  return "supervisor";
3011
2850
  };
3012
2851
  const workerRouter = (state) => {
3013
- logger4.debug("Worker router executing", {
2852
+ logger3.debug("Worker router executing", {
3014
2853
  iteration: state.iteration,
3015
2854
  completedTasks: state.completedTasks.length
3016
2855
  });
3017
- logger4.debug("Worker router: returning to supervisor");
2856
+ logger3.debug("Worker router: returning to supervisor");
3018
2857
  return "supervisor";
3019
2858
  };
3020
2859
  const aggregatorRouter = (state) => {
3021
- logger4.info("Aggregator router: ending workflow", {
2860
+ logger3.info("Aggregator router: ending workflow", {
3022
2861
  completedTasks: state.completedTasks.length,
3023
2862
  status: state.status
3024
2863
  });