@agentforge/patterns 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -327,6 +327,9 @@ function createActionNode(tools, verbose = false) {
327
327
  console.log(`[action] Tool '${action.name}' executed successfully`);
328
328
  }
329
329
  } catch (error) {
330
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
331
+ throw error;
332
+ }
330
333
  const errorMessage = error instanceof Error ? error.message : String(error);
331
334
  observations.push({
332
335
  toolCallId: action.id,
@@ -870,6 +873,9 @@ function createExecutorNode(config) {
870
873
  result = { message: "Step completed without tool execution" };
871
874
  }
872
875
  } catch (execError) {
876
+ if (execError && typeof execError === "object" && "constructor" in execError && execError.constructor.name === "GraphInterrupt") {
877
+ throw execError;
878
+ }
873
879
  success = false;
874
880
  error = execError instanceof Error ? execError.message : "Unknown execution error";
875
881
  result = null;
@@ -2097,43 +2103,48 @@ function getRoutingStrategy(name) {
2097
2103
  }
2098
2104
 
2099
2105
  // src/multi-agent/utils.ts
2106
+ var import_core7 = require("@agentforge/core");
2107
+ var logLevel = process.env.LOG_LEVEL?.toLowerCase() || import_core7.LogLevel.INFO;
2108
+ var logger = (0, import_core7.createLogger)("multi-agent", { level: logLevel });
2100
2109
  function isReActAgent(obj) {
2101
2110
  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
2102
2111
  (obj.constructor?.name === "CompiledGraph" || obj.constructor?.name === "CompiledStateGraph");
2103
2112
  }
2104
2113
  function wrapReActAgent(workerId, agent, verbose = false) {
2105
- return async (state) => {
2114
+ return async (state, config) => {
2106
2115
  try {
2107
- if (verbose) {
2108
- console.log(`[ReActWrapper:${workerId}] Wrapping ReAct agent execution`);
2109
- }
2116
+ logger.debug("Wrapping ReAct agent execution", { workerId });
2110
2117
  const task = state.messages[state.messages.length - 1]?.content || state.input;
2111
- if (verbose) {
2112
- console.log(`[ReActWrapper:${workerId}] Task:`, task.substring(0, 100) + "...");
2113
- }
2118
+ logger.debug("Extracted task", {
2119
+ workerId,
2120
+ taskPreview: task.substring(0, 100) + (task.length > 100 ? "..." : "")
2121
+ });
2114
2122
  const currentAssignment = state.activeAssignments.find(
2115
2123
  (assignment) => assignment.workerId === workerId && !state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2116
2124
  );
2117
2125
  if (!currentAssignment) {
2118
- if (verbose) {
2119
- console.log(`[ReActWrapper:${workerId}] No active assignment found`);
2120
- }
2126
+ logger.debug("No active assignment found", { workerId });
2121
2127
  return {
2122
2128
  currentAgent: "supervisor",
2123
2129
  status: "routing"
2124
2130
  };
2125
2131
  }
2126
- const result = await agent.invoke({
2127
- messages: [{ role: "user", content: task }]
2128
- });
2132
+ const result = await agent.invoke(
2133
+ {
2134
+ messages: [{ role: "user", content: task }]
2135
+ },
2136
+ config
2137
+ // Pass through the config for checkpointing and interrupt support
2138
+ );
2129
2139
  const response = result.messages?.[result.messages.length - 1]?.content || "No response";
2130
- if (verbose) {
2131
- console.log(`[ReActWrapper:${workerId}] Response:`, response.substring(0, 100) + "...");
2132
- }
2140
+ logger.debug("Received response from ReAct agent", {
2141
+ workerId,
2142
+ responsePreview: response.substring(0, 100) + (response.length > 100 ? "..." : "")
2143
+ });
2133
2144
  const toolsUsed = result.actions?.map((action) => action.name).filter(Boolean) || [];
2134
2145
  const uniqueTools = [...new Set(toolsUsed)];
2135
- if (verbose && uniqueTools.length > 0) {
2136
- console.log(`[ReActWrapper:${workerId}] Tools used:`, uniqueTools.join(", "));
2146
+ if (uniqueTools.length > 0) {
2147
+ logger.debug("Tools used by ReAct agent", { workerId, tools: uniqueTools });
2137
2148
  }
2138
2149
  const taskResult = {
2139
2150
  assignmentId: currentAssignment.id,
@@ -2153,7 +2164,15 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2153
2164
  status: "routing"
2154
2165
  };
2155
2166
  } catch (error) {
2156
- console.error(`[ReActWrapper:${workerId}] Error:`, error);
2167
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2168
+ logger.debug("GraphInterrupt detected - re-throwing", { workerId });
2169
+ throw error;
2170
+ }
2171
+ logger.error("Error in ReAct agent execution", {
2172
+ workerId,
2173
+ error: error instanceof Error ? error.message : String(error),
2174
+ stack: error instanceof Error ? error.stack : void 0
2175
+ });
2157
2176
  const currentAssignment = state.activeAssignments.find(
2158
2177
  (assignment) => assignment.workerId === workerId
2159
2178
  );
@@ -2182,7 +2201,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2182
2201
 
2183
2202
  // src/multi-agent/nodes.ts
2184
2203
  var import_messages5 = require("@langchain/core/messages");
2185
- var import_core7 = require("@agentforge/core");
2204
+ var import_core8 = require("@agentforge/core");
2186
2205
  var DEFAULT_AGGREGATOR_SYSTEM_PROMPT = `You are an aggregator agent responsible for combining results from multiple worker agents.
2187
2206
 
2188
2207
  Your job is to:
@@ -2276,7 +2295,7 @@ function createWorkerNode(config) {
2276
2295
  executeFn,
2277
2296
  agent
2278
2297
  } = config;
2279
- return async (state) => {
2298
+ return async (state, runConfig) => {
2280
2299
  try {
2281
2300
  if (verbose) {
2282
2301
  console.log(`[Worker:${id}] Executing task`);
@@ -2297,7 +2316,7 @@ function createWorkerNode(config) {
2297
2316
  if (verbose) {
2298
2317
  console.log(`[Worker:${id}] Using custom executeFn`);
2299
2318
  }
2300
- return await executeFn(state);
2319
+ return await executeFn(state, runConfig);
2301
2320
  }
2302
2321
  if (agent) {
2303
2322
  if (isReActAgent(agent)) {
@@ -2305,7 +2324,7 @@ function createWorkerNode(config) {
2305
2324
  console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
2306
2325
  }
2307
2326
  const wrappedFn = wrapReActAgent(id, agent, verbose);
2308
- return await wrappedFn(state);
2327
+ return await wrappedFn(state, runConfig);
2309
2328
  } else {
2310
2329
  console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
2311
2330
  }
@@ -2326,7 +2345,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2326
2345
  ];
2327
2346
  let modelToUse = model;
2328
2347
  if (tools.length > 0 && model.bindTools) {
2329
- const langchainTools = (0, import_core7.toLangChainTools)(tools);
2348
+ const langchainTools = (0, import_core8.toLangChainTools)(tools);
2330
2349
  modelToUse = model.bindTools(langchainTools);
2331
2350
  }
2332
2351
  const response = await modelToUse.invoke(messages);
@@ -2371,6 +2390,9 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2371
2390
  status: "routing"
2372
2391
  };
2373
2392
  } catch (error) {
2393
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2394
+ throw error;
2395
+ }
2374
2396
  console.error(`[Worker:${id}] Error:`, error);
2375
2397
  const currentAssignment = state.activeAssignments.find(
2376
2398
  (assignment) => assignment.workerId === id
@@ -2466,7 +2488,7 @@ Please synthesize these results into a comprehensive response that addresses the
2466
2488
 
2467
2489
  // src/multi-agent/agent.ts
2468
2490
  var import_langgraph4 = require("@langchain/langgraph");
2469
- var import_core8 = require("@agentforge/core");
2491
+ var import_core9 = require("@agentforge/core");
2470
2492
  function createMultiAgentSystem(config) {
2471
2493
  const {
2472
2494
  supervisor,
@@ -2479,7 +2501,7 @@ function createMultiAgentSystem(config) {
2479
2501
  const workflow = new import_langgraph4.StateGraph(MultiAgentState);
2480
2502
  let supervisorConfig = { ...supervisor, maxIterations, verbose };
2481
2503
  if (supervisor.model && supervisor.tools && supervisor.tools.length > 0) {
2482
- const langchainTools = (0, import_core8.toLangChainTools)(supervisor.tools);
2504
+ const langchainTools = (0, import_core9.toLangChainTools)(supervisor.tools);
2483
2505
  const modelWithTools = supervisor.model.bindTools(langchainTools);
2484
2506
  supervisorConfig.model = modelWithTools;
2485
2507
  }
package/dist/index.d.cts CHANGED
@@ -2476,8 +2476,11 @@ interface WorkerConfig {
2476
2476
  *
2477
2477
  * If provided, this function will be used to execute tasks for this worker.
2478
2478
  * Takes precedence over the `agent` property.
2479
+ *
2480
+ * The config parameter contains LangGraph runtime configuration including
2481
+ * thread_id for checkpointing, which is required for interrupt functionality.
2479
2482
  */
2480
- executeFn?: (state: MultiAgentStateType) => Promise<Partial<MultiAgentStateType>>;
2483
+ executeFn?: (state: MultiAgentStateType, config?: any) => Promise<Partial<MultiAgentStateType>>;
2481
2484
  /**
2482
2485
  * ReAct agent instance
2483
2486
  *
@@ -2655,7 +2658,7 @@ declare function createSupervisorNode(config: SupervisorConfig): (state: MultiAg
2655
2658
  /**
2656
2659
  * Create a worker agent node
2657
2660
  */
2658
- declare function createWorkerNode(config: WorkerConfig): (state: MultiAgentStateType) => Promise<Partial<MultiAgentStateType>>;
2661
+ declare function createWorkerNode(config: WorkerConfig): (state: MultiAgentStateType, runConfig?: any) => Promise<Partial<MultiAgentStateType>>;
2659
2662
  /**
2660
2663
  * Create an aggregator node that combines worker results
2661
2664
  */
package/dist/index.d.ts CHANGED
@@ -2476,8 +2476,11 @@ interface WorkerConfig {
2476
2476
  *
2477
2477
  * If provided, this function will be used to execute tasks for this worker.
2478
2478
  * Takes precedence over the `agent` property.
2479
+ *
2480
+ * The config parameter contains LangGraph runtime configuration including
2481
+ * thread_id for checkpointing, which is required for interrupt functionality.
2479
2482
  */
2480
- executeFn?: (state: MultiAgentStateType) => Promise<Partial<MultiAgentStateType>>;
2483
+ executeFn?: (state: MultiAgentStateType, config?: any) => Promise<Partial<MultiAgentStateType>>;
2481
2484
  /**
2482
2485
  * ReAct agent instance
2483
2486
  *
@@ -2655,7 +2658,7 @@ declare function createSupervisorNode(config: SupervisorConfig): (state: MultiAg
2655
2658
  /**
2656
2659
  * Create a worker agent node
2657
2660
  */
2658
- declare function createWorkerNode(config: WorkerConfig): (state: MultiAgentStateType) => Promise<Partial<MultiAgentStateType>>;
2661
+ declare function createWorkerNode(config: WorkerConfig): (state: MultiAgentStateType, runConfig?: any) => Promise<Partial<MultiAgentStateType>>;
2659
2662
  /**
2660
2663
  * Create an aggregator node that combines worker results
2661
2664
  */
package/dist/index.js CHANGED
@@ -228,6 +228,9 @@ function createActionNode(tools, verbose = false) {
228
228
  console.log(`[action] Tool '${action.name}' executed successfully`);
229
229
  }
230
230
  } catch (error) {
231
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
232
+ throw error;
233
+ }
231
234
  const errorMessage = error instanceof Error ? error.message : String(error);
232
235
  observations.push({
233
236
  toolCallId: action.id,
@@ -771,6 +774,9 @@ function createExecutorNode(config) {
771
774
  result = { message: "Step completed without tool execution" };
772
775
  }
773
776
  } catch (execError) {
777
+ if (execError && typeof execError === "object" && "constructor" in execError && execError.constructor.name === "GraphInterrupt") {
778
+ throw execError;
779
+ }
774
780
  success = false;
775
781
  error = execError instanceof Error ? execError.message : "Unknown execution error";
776
782
  result = null;
@@ -1998,43 +2004,48 @@ function getRoutingStrategy(name) {
1998
2004
  }
1999
2005
 
2000
2006
  // src/multi-agent/utils.ts
2007
+ import { createLogger, LogLevel } from "@agentforge/core";
2008
+ var logLevel = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
2009
+ var logger = createLogger("multi-agent", { level: logLevel });
2001
2010
  function isReActAgent(obj) {
2002
2011
  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
2003
2012
  (obj.constructor?.name === "CompiledGraph" || obj.constructor?.name === "CompiledStateGraph");
2004
2013
  }
2005
2014
  function wrapReActAgent(workerId, agent, verbose = false) {
2006
- return async (state) => {
2015
+ return async (state, config) => {
2007
2016
  try {
2008
- if (verbose) {
2009
- console.log(`[ReActWrapper:${workerId}] Wrapping ReAct agent execution`);
2010
- }
2017
+ logger.debug("Wrapping ReAct agent execution", { workerId });
2011
2018
  const task = state.messages[state.messages.length - 1]?.content || state.input;
2012
- if (verbose) {
2013
- console.log(`[ReActWrapper:${workerId}] Task:`, task.substring(0, 100) + "...");
2014
- }
2019
+ logger.debug("Extracted task", {
2020
+ workerId,
2021
+ taskPreview: task.substring(0, 100) + (task.length > 100 ? "..." : "")
2022
+ });
2015
2023
  const currentAssignment = state.activeAssignments.find(
2016
2024
  (assignment) => assignment.workerId === workerId && !state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2017
2025
  );
2018
2026
  if (!currentAssignment) {
2019
- if (verbose) {
2020
- console.log(`[ReActWrapper:${workerId}] No active assignment found`);
2021
- }
2027
+ logger.debug("No active assignment found", { workerId });
2022
2028
  return {
2023
2029
  currentAgent: "supervisor",
2024
2030
  status: "routing"
2025
2031
  };
2026
2032
  }
2027
- const result = await agent.invoke({
2028
- messages: [{ role: "user", content: task }]
2029
- });
2033
+ const result = await agent.invoke(
2034
+ {
2035
+ messages: [{ role: "user", content: task }]
2036
+ },
2037
+ config
2038
+ // Pass through the config for checkpointing and interrupt support
2039
+ );
2030
2040
  const response = result.messages?.[result.messages.length - 1]?.content || "No response";
2031
- if (verbose) {
2032
- console.log(`[ReActWrapper:${workerId}] Response:`, response.substring(0, 100) + "...");
2033
- }
2041
+ logger.debug("Received response from ReAct agent", {
2042
+ workerId,
2043
+ responsePreview: response.substring(0, 100) + (response.length > 100 ? "..." : "")
2044
+ });
2034
2045
  const toolsUsed = result.actions?.map((action) => action.name).filter(Boolean) || [];
2035
2046
  const uniqueTools = [...new Set(toolsUsed)];
2036
- if (verbose && uniqueTools.length > 0) {
2037
- console.log(`[ReActWrapper:${workerId}] Tools used:`, uniqueTools.join(", "));
2047
+ if (uniqueTools.length > 0) {
2048
+ logger.debug("Tools used by ReAct agent", { workerId, tools: uniqueTools });
2038
2049
  }
2039
2050
  const taskResult = {
2040
2051
  assignmentId: currentAssignment.id,
@@ -2054,7 +2065,15 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2054
2065
  status: "routing"
2055
2066
  };
2056
2067
  } catch (error) {
2057
- console.error(`[ReActWrapper:${workerId}] Error:`, error);
2068
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2069
+ logger.debug("GraphInterrupt detected - re-throwing", { workerId });
2070
+ throw error;
2071
+ }
2072
+ logger.error("Error in ReAct agent execution", {
2073
+ workerId,
2074
+ error: error instanceof Error ? error.message : String(error),
2075
+ stack: error instanceof Error ? error.stack : void 0
2076
+ });
2058
2077
  const currentAssignment = state.activeAssignments.find(
2059
2078
  (assignment) => assignment.workerId === workerId
2060
2079
  );
@@ -2177,7 +2196,7 @@ function createWorkerNode(config) {
2177
2196
  executeFn,
2178
2197
  agent
2179
2198
  } = config;
2180
- return async (state) => {
2199
+ return async (state, runConfig) => {
2181
2200
  try {
2182
2201
  if (verbose) {
2183
2202
  console.log(`[Worker:${id}] Executing task`);
@@ -2198,7 +2217,7 @@ function createWorkerNode(config) {
2198
2217
  if (verbose) {
2199
2218
  console.log(`[Worker:${id}] Using custom executeFn`);
2200
2219
  }
2201
- return await executeFn(state);
2220
+ return await executeFn(state, runConfig);
2202
2221
  }
2203
2222
  if (agent) {
2204
2223
  if (isReActAgent(agent)) {
@@ -2206,7 +2225,7 @@ function createWorkerNode(config) {
2206
2225
  console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
2207
2226
  }
2208
2227
  const wrappedFn = wrapReActAgent(id, agent, verbose);
2209
- return await wrappedFn(state);
2228
+ return await wrappedFn(state, runConfig);
2210
2229
  } else {
2211
2230
  console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
2212
2231
  }
@@ -2272,6 +2291,9 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2272
2291
  status: "routing"
2273
2292
  };
2274
2293
  } catch (error) {
2294
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2295
+ throw error;
2296
+ }
2275
2297
  console.error(`[Worker:${id}] Error:`, error);
2276
2298
  const currentAssignment = state.activeAssignments.find(
2277
2299
  (assignment) => assignment.workerId === id
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/patterns",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Agent patterns (ReAct, Planner-Executor) for AgentForge framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",