@agentforge/patterns 0.6.0 → 0.6.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.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,
@@ -2097,43 +2100,48 @@ function getRoutingStrategy(name) {
2097
2100
  }
2098
2101
 
2099
2102
  // src/multi-agent/utils.ts
2103
+ var import_core7 = require("@agentforge/core");
2104
+ var logLevel = process.env.LOG_LEVEL?.toLowerCase() || import_core7.LogLevel.INFO;
2105
+ var logger = (0, import_core7.createLogger)("multi-agent", { level: logLevel });
2100
2106
  function isReActAgent(obj) {
2101
2107
  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
2108
  (obj.constructor?.name === "CompiledGraph" || obj.constructor?.name === "CompiledStateGraph");
2103
2109
  }
2104
2110
  function wrapReActAgent(workerId, agent, verbose = false) {
2105
- return async (state) => {
2111
+ return async (state, config) => {
2106
2112
  try {
2107
- if (verbose) {
2108
- console.log(`[ReActWrapper:${workerId}] Wrapping ReAct agent execution`);
2109
- }
2113
+ logger.debug("Wrapping ReAct agent execution", { workerId });
2110
2114
  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
- }
2115
+ logger.debug("Extracted task", {
2116
+ workerId,
2117
+ taskPreview: task.substring(0, 100) + (task.length > 100 ? "..." : "")
2118
+ });
2114
2119
  const currentAssignment = state.activeAssignments.find(
2115
2120
  (assignment) => assignment.workerId === workerId && !state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2116
2121
  );
2117
2122
  if (!currentAssignment) {
2118
- if (verbose) {
2119
- console.log(`[ReActWrapper:${workerId}] No active assignment found`);
2120
- }
2123
+ logger.debug("No active assignment found", { workerId });
2121
2124
  return {
2122
2125
  currentAgent: "supervisor",
2123
2126
  status: "routing"
2124
2127
  };
2125
2128
  }
2126
- const result = await agent.invoke({
2127
- messages: [{ role: "user", content: task }]
2128
- });
2129
+ const result = await agent.invoke(
2130
+ {
2131
+ messages: [{ role: "user", content: task }]
2132
+ },
2133
+ config
2134
+ // Pass through the config for checkpointing and interrupt support
2135
+ );
2129
2136
  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
- }
2137
+ logger.debug("Received response from ReAct agent", {
2138
+ workerId,
2139
+ responsePreview: response.substring(0, 100) + (response.length > 100 ? "..." : "")
2140
+ });
2133
2141
  const toolsUsed = result.actions?.map((action) => action.name).filter(Boolean) || [];
2134
2142
  const uniqueTools = [...new Set(toolsUsed)];
2135
- if (verbose && uniqueTools.length > 0) {
2136
- console.log(`[ReActWrapper:${workerId}] Tools used:`, uniqueTools.join(", "));
2143
+ if (uniqueTools.length > 0) {
2144
+ logger.debug("Tools used by ReAct agent", { workerId, tools: uniqueTools });
2137
2145
  }
2138
2146
  const taskResult = {
2139
2147
  assignmentId: currentAssignment.id,
@@ -2153,7 +2161,15 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2153
2161
  status: "routing"
2154
2162
  };
2155
2163
  } catch (error) {
2156
- console.error(`[ReActWrapper:${workerId}] Error:`, error);
2164
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2165
+ logger.debug("GraphInterrupt detected - re-throwing", { workerId });
2166
+ throw error;
2167
+ }
2168
+ logger.error("Error in ReAct agent execution", {
2169
+ workerId,
2170
+ error: error instanceof Error ? error.message : String(error),
2171
+ stack: error instanceof Error ? error.stack : void 0
2172
+ });
2157
2173
  const currentAssignment = state.activeAssignments.find(
2158
2174
  (assignment) => assignment.workerId === workerId
2159
2175
  );
@@ -2182,7 +2198,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2182
2198
 
2183
2199
  // src/multi-agent/nodes.ts
2184
2200
  var import_messages5 = require("@langchain/core/messages");
2185
- var import_core7 = require("@agentforge/core");
2201
+ var import_core8 = require("@agentforge/core");
2186
2202
  var DEFAULT_AGGREGATOR_SYSTEM_PROMPT = `You are an aggregator agent responsible for combining results from multiple worker agents.
2187
2203
 
2188
2204
  Your job is to:
@@ -2276,7 +2292,7 @@ function createWorkerNode(config) {
2276
2292
  executeFn,
2277
2293
  agent
2278
2294
  } = config;
2279
- return async (state) => {
2295
+ return async (state, runConfig) => {
2280
2296
  try {
2281
2297
  if (verbose) {
2282
2298
  console.log(`[Worker:${id}] Executing task`);
@@ -2297,7 +2313,7 @@ function createWorkerNode(config) {
2297
2313
  if (verbose) {
2298
2314
  console.log(`[Worker:${id}] Using custom executeFn`);
2299
2315
  }
2300
- return await executeFn(state);
2316
+ return await executeFn(state, runConfig);
2301
2317
  }
2302
2318
  if (agent) {
2303
2319
  if (isReActAgent(agent)) {
@@ -2305,7 +2321,7 @@ function createWorkerNode(config) {
2305
2321
  console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
2306
2322
  }
2307
2323
  const wrappedFn = wrapReActAgent(id, agent, verbose);
2308
- return await wrappedFn(state);
2324
+ return await wrappedFn(state, runConfig);
2309
2325
  } else {
2310
2326
  console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
2311
2327
  }
@@ -2326,7 +2342,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2326
2342
  ];
2327
2343
  let modelToUse = model;
2328
2344
  if (tools.length > 0 && model.bindTools) {
2329
- const langchainTools = (0, import_core7.toLangChainTools)(tools);
2345
+ const langchainTools = (0, import_core8.toLangChainTools)(tools);
2330
2346
  modelToUse = model.bindTools(langchainTools);
2331
2347
  }
2332
2348
  const response = await modelToUse.invoke(messages);
@@ -2371,6 +2387,9 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2371
2387
  status: "routing"
2372
2388
  };
2373
2389
  } catch (error) {
2390
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2391
+ throw error;
2392
+ }
2374
2393
  console.error(`[Worker:${id}] Error:`, error);
2375
2394
  const currentAssignment = state.activeAssignments.find(
2376
2395
  (assignment) => assignment.workerId === id
@@ -2466,7 +2485,7 @@ Please synthesize these results into a comprehensive response that addresses the
2466
2485
 
2467
2486
  // src/multi-agent/agent.ts
2468
2487
  var import_langgraph4 = require("@langchain/langgraph");
2469
- var import_core8 = require("@agentforge/core");
2488
+ var import_core9 = require("@agentforge/core");
2470
2489
  function createMultiAgentSystem(config) {
2471
2490
  const {
2472
2491
  supervisor,
@@ -2479,7 +2498,7 @@ function createMultiAgentSystem(config) {
2479
2498
  const workflow = new import_langgraph4.StateGraph(MultiAgentState);
2480
2499
  let supervisorConfig = { ...supervisor, maxIterations, verbose };
2481
2500
  if (supervisor.model && supervisor.tools && supervisor.tools.length > 0) {
2482
- const langchainTools = (0, import_core8.toLangChainTools)(supervisor.tools);
2501
+ const langchainTools = (0, import_core9.toLangChainTools)(supervisor.tools);
2483
2502
  const modelWithTools = supervisor.model.bindTools(langchainTools);
2484
2503
  supervisorConfig.model = modelWithTools;
2485
2504
  }
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,
@@ -1998,43 +2001,48 @@ function getRoutingStrategy(name) {
1998
2001
  }
1999
2002
 
2000
2003
  // src/multi-agent/utils.ts
2004
+ import { createLogger, LogLevel } from "@agentforge/core";
2005
+ var logLevel = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
2006
+ var logger = createLogger("multi-agent", { level: logLevel });
2001
2007
  function isReActAgent(obj) {
2002
2008
  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
2009
  (obj.constructor?.name === "CompiledGraph" || obj.constructor?.name === "CompiledStateGraph");
2004
2010
  }
2005
2011
  function wrapReActAgent(workerId, agent, verbose = false) {
2006
- return async (state) => {
2012
+ return async (state, config) => {
2007
2013
  try {
2008
- if (verbose) {
2009
- console.log(`[ReActWrapper:${workerId}] Wrapping ReAct agent execution`);
2010
- }
2014
+ logger.debug("Wrapping ReAct agent execution", { workerId });
2011
2015
  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
- }
2016
+ logger.debug("Extracted task", {
2017
+ workerId,
2018
+ taskPreview: task.substring(0, 100) + (task.length > 100 ? "..." : "")
2019
+ });
2015
2020
  const currentAssignment = state.activeAssignments.find(
2016
2021
  (assignment) => assignment.workerId === workerId && !state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2017
2022
  );
2018
2023
  if (!currentAssignment) {
2019
- if (verbose) {
2020
- console.log(`[ReActWrapper:${workerId}] No active assignment found`);
2021
- }
2024
+ logger.debug("No active assignment found", { workerId });
2022
2025
  return {
2023
2026
  currentAgent: "supervisor",
2024
2027
  status: "routing"
2025
2028
  };
2026
2029
  }
2027
- const result = await agent.invoke({
2028
- messages: [{ role: "user", content: task }]
2029
- });
2030
+ const result = await agent.invoke(
2031
+ {
2032
+ messages: [{ role: "user", content: task }]
2033
+ },
2034
+ config
2035
+ // Pass through the config for checkpointing and interrupt support
2036
+ );
2030
2037
  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
- }
2038
+ logger.debug("Received response from ReAct agent", {
2039
+ workerId,
2040
+ responsePreview: response.substring(0, 100) + (response.length > 100 ? "..." : "")
2041
+ });
2034
2042
  const toolsUsed = result.actions?.map((action) => action.name).filter(Boolean) || [];
2035
2043
  const uniqueTools = [...new Set(toolsUsed)];
2036
- if (verbose && uniqueTools.length > 0) {
2037
- console.log(`[ReActWrapper:${workerId}] Tools used:`, uniqueTools.join(", "));
2044
+ if (uniqueTools.length > 0) {
2045
+ logger.debug("Tools used by ReAct agent", { workerId, tools: uniqueTools });
2038
2046
  }
2039
2047
  const taskResult = {
2040
2048
  assignmentId: currentAssignment.id,
@@ -2054,7 +2062,15 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2054
2062
  status: "routing"
2055
2063
  };
2056
2064
  } catch (error) {
2057
- console.error(`[ReActWrapper:${workerId}] Error:`, error);
2065
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2066
+ logger.debug("GraphInterrupt detected - re-throwing", { workerId });
2067
+ throw error;
2068
+ }
2069
+ logger.error("Error in ReAct agent execution", {
2070
+ workerId,
2071
+ error: error instanceof Error ? error.message : String(error),
2072
+ stack: error instanceof Error ? error.stack : void 0
2073
+ });
2058
2074
  const currentAssignment = state.activeAssignments.find(
2059
2075
  (assignment) => assignment.workerId === workerId
2060
2076
  );
@@ -2177,7 +2193,7 @@ function createWorkerNode(config) {
2177
2193
  executeFn,
2178
2194
  agent
2179
2195
  } = config;
2180
- return async (state) => {
2196
+ return async (state, runConfig) => {
2181
2197
  try {
2182
2198
  if (verbose) {
2183
2199
  console.log(`[Worker:${id}] Executing task`);
@@ -2198,7 +2214,7 @@ function createWorkerNode(config) {
2198
2214
  if (verbose) {
2199
2215
  console.log(`[Worker:${id}] Using custom executeFn`);
2200
2216
  }
2201
- return await executeFn(state);
2217
+ return await executeFn(state, runConfig);
2202
2218
  }
2203
2219
  if (agent) {
2204
2220
  if (isReActAgent(agent)) {
@@ -2206,7 +2222,7 @@ function createWorkerNode(config) {
2206
2222
  console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
2207
2223
  }
2208
2224
  const wrappedFn = wrapReActAgent(id, agent, verbose);
2209
- return await wrappedFn(state);
2225
+ return await wrappedFn(state, runConfig);
2210
2226
  } else {
2211
2227
  console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
2212
2228
  }
@@ -2272,6 +2288,9 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2272
2288
  status: "routing"
2273
2289
  };
2274
2290
  } catch (error) {
2291
+ if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
2292
+ throw error;
2293
+ }
2275
2294
  console.error(`[Worker:${id}] Error:`, error);
2276
2295
  const currentAssignment = state.activeAssignments.find(
2277
2296
  (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.1",
4
4
  "description": "Agent patterns (ReAct, Planner-Executor) for AgentForge framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",