@agentforge/patterns 0.8.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.cjs CHANGED
@@ -604,7 +604,8 @@ function createReActAgent(config, options) {
604
604
  return ACTION_NODE;
605
605
  };
606
606
  const workflow = new import_langgraph.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);
607
- return workflow.compile(checkpointer ? { checkpointer } : void 0);
607
+ const checkpointerConfig = checkpointer === true ? { checkpointer: true } : checkpointer ? { checkpointer } : void 0;
608
+ return workflow.compile(checkpointerConfig);
608
609
  }
609
610
 
610
611
  // src/react/builder.ts
@@ -689,6 +690,43 @@ var ReActAgentBuilder = class {
689
690
  this.options.nodeNames = nodeNames;
690
691
  return this;
691
692
  }
693
+ /**
694
+ * Set the checkpointer for state persistence (optional)
695
+ *
696
+ * Can be:
697
+ * - A BaseCheckpointSaver instance (e.g., MemorySaver) for standalone agents
698
+ * - `true` to use the parent graph's checkpointer with a separate namespace (for nested graphs)
699
+ *
700
+ * Required for human-in-the-loop workflows (askHuman tool) and conversation continuity.
701
+ *
702
+ * @param checkpointer - Checkpointer instance or `true` for nested graphs
703
+ *
704
+ * @example
705
+ * Standalone agent with its own checkpointer:
706
+ * ```typescript
707
+ * import { MemorySaver } from '@langchain/langgraph';
708
+ *
709
+ * const agent = new ReActAgentBuilder()
710
+ * .withModel(model)
711
+ * .withTools(tools)
712
+ * .withCheckpointer(new MemorySaver())
713
+ * .build();
714
+ * ```
715
+ *
716
+ * @example
717
+ * Nested agent using parent's checkpointer (for multi-agent systems):
718
+ * ```typescript
719
+ * const agent = new ReActAgentBuilder()
720
+ * .withModel(model)
721
+ * .withTools(tools)
722
+ * .withCheckpointer(true) // Use parent's checkpointer with separate namespace
723
+ * .build();
724
+ * ```
725
+ */
726
+ withCheckpointer(checkpointer) {
727
+ this.config.checkpointer = checkpointer;
728
+ return this;
729
+ }
692
730
  /**
693
731
  * Build the ReAct agent
694
732
  *
@@ -708,7 +746,8 @@ var ReActAgentBuilder = class {
708
746
  systemPrompt: this.config.systemPrompt || DEFAULT_REACT_SYSTEM_PROMPT,
709
747
  maxIterations: this.config.maxIterations ?? 10,
710
748
  returnIntermediateSteps: this.config.returnIntermediateSteps ?? false,
711
- stopCondition: this.config.stopCondition
749
+ stopCondition: this.config.stopCondition,
750
+ checkpointer: this.config.checkpointer
712
751
  };
713
752
  return createReActAgent(finalConfig, this.options);
714
753
  }
@@ -2362,12 +2401,26 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2362
2401
  logger.debug("No active assignment found", { workerId });
2363
2402
  return {};
2364
2403
  }
2404
+ const workerThreadId = config?.configurable?.thread_id ? `${config.configurable.thread_id}:worker:${workerId}` : void 0;
2405
+ const workerConfig = workerThreadId ? {
2406
+ ...config,
2407
+ configurable: {
2408
+ ...config.configurable,
2409
+ thread_id: workerThreadId
2410
+ }
2411
+ } : config;
2412
+ logger.debug("Invoking ReAct agent with worker-specific config", {
2413
+ workerId,
2414
+ parentThreadId: config?.configurable?.thread_id,
2415
+ workerThreadId,
2416
+ hasConfig: !!workerConfig
2417
+ });
2365
2418
  const result = await agent.invoke(
2366
2419
  {
2367
2420
  messages: [{ role: "user", content: task }]
2368
2421
  },
2369
- config
2370
- // Pass through the config for checkpointing and interrupt support
2422
+ workerConfig
2423
+ // Worker-specific config with unique thread_id
2371
2424
  );
2372
2425
  const response = result.messages?.[result.messages.length - 1]?.content || "No response";
2373
2426
  logger.debug("Received response from ReAct agent", {
package/dist/index.d.cts CHANGED
@@ -172,7 +172,12 @@ interface ReActAgentConfig {
172
172
  * Optional checkpointer for state persistence
173
173
  * Required for human-in-the-loop workflows (askHuman tool), interrupts, and conversation continuity
174
174
  *
175
+ * Can be:
176
+ * - A BaseCheckpointSaver instance (e.g., MemorySaver) for standalone agents
177
+ * - `true` to use the parent graph's checkpointer with a separate namespace (for nested graphs)
178
+ *
175
179
  * @example
180
+ * Standalone agent with its own checkpointer:
176
181
  * ```typescript
177
182
  * import { MemorySaver } from '@langchain/langgraph';
178
183
  *
@@ -183,8 +188,18 @@ interface ReActAgentConfig {
183
188
  * checkpointer
184
189
  * });
185
190
  * ```
191
+ *
192
+ * @example
193
+ * Nested agent using parent's checkpointer (for multi-agent systems):
194
+ * ```typescript
195
+ * const agent = createReActAgent({
196
+ * model,
197
+ * tools,
198
+ * checkpointer: true // Use parent's checkpointer with separate namespace
199
+ * });
200
+ * ```
186
201
  */
187
- checkpointer?: BaseCheckpointSaver;
202
+ checkpointer?: BaseCheckpointSaver | true;
188
203
  /**
189
204
  * Enable tool call deduplication to prevent calling the same tool with identical parameters multiple times
190
205
  * @default true
@@ -287,6 +302,31 @@ declare const DEFAULT_REACT_SYSTEM_PROMPT = "You are a helpful assistant that us
287
302
  * { configurable: { thread_id: 'conversation-123' } }
288
303
  * );
289
304
  * ```
305
+ *
306
+ * @example
307
+ * As a nested agent in a multi-agent system:
308
+ * ```typescript
309
+ * import { createReActAgent, createMultiAgentSystem } from '@agentforge/patterns';
310
+ * import { createAskHumanTool } from '@agentforge/tools';
311
+ * import { MemorySaver } from '@langchain/langgraph';
312
+ * import { ChatOpenAI } from '@langchain/openai';
313
+ *
314
+ * // Create worker agent with checkpointer: true to use parent's checkpointer
315
+ * const hrAgent = createReActAgent({
316
+ * model: new ChatOpenAI({ model: 'gpt-4' }),
317
+ * tools: [createAskHumanTool(), ...hrTools],
318
+ * checkpointer: true // Use parent's checkpointer with separate namespace
319
+ * });
320
+ *
321
+ * // Create multi-agent system with its own checkpointer
322
+ * const system = createMultiAgentSystem({
323
+ * workers: { hr: hrAgent },
324
+ * checkpointer: new MemorySaver() // Parent checkpointer
325
+ * });
326
+ *
327
+ * // When hrAgent calls askHuman, it will use a separate checkpoint namespace
328
+ * // Format: {parent_thread_id}:worker:hr
329
+ * ```
290
330
  */
291
331
  declare function createReActAgent(config: ReActAgentConfig, options?: ReActBuilderOptions): CompiledStateGraph<any, any>;
292
332
 
@@ -372,6 +412,40 @@ declare class ReActAgentBuilder {
372
412
  action?: string;
373
413
  observation?: string;
374
414
  }): this;
415
+ /**
416
+ * Set the checkpointer for state persistence (optional)
417
+ *
418
+ * Can be:
419
+ * - A BaseCheckpointSaver instance (e.g., MemorySaver) for standalone agents
420
+ * - `true` to use the parent graph's checkpointer with a separate namespace (for nested graphs)
421
+ *
422
+ * Required for human-in-the-loop workflows (askHuman tool) and conversation continuity.
423
+ *
424
+ * @param checkpointer - Checkpointer instance or `true` for nested graphs
425
+ *
426
+ * @example
427
+ * Standalone agent with its own checkpointer:
428
+ * ```typescript
429
+ * import { MemorySaver } from '@langchain/langgraph';
430
+ *
431
+ * const agent = new ReActAgentBuilder()
432
+ * .withModel(model)
433
+ * .withTools(tools)
434
+ * .withCheckpointer(new MemorySaver())
435
+ * .build();
436
+ * ```
437
+ *
438
+ * @example
439
+ * Nested agent using parent's checkpointer (for multi-agent systems):
440
+ * ```typescript
441
+ * const agent = new ReActAgentBuilder()
442
+ * .withModel(model)
443
+ * .withTools(tools)
444
+ * .withCheckpointer(true) // Use parent's checkpointer with separate namespace
445
+ * .build();
446
+ * ```
447
+ */
448
+ withCheckpointer(checkpointer: any): this;
375
449
  /**
376
450
  * Build the ReAct agent
377
451
  *
@@ -2593,7 +2667,20 @@ interface MultiAgentSystemConfig {
2593
2667
  * Optional checkpointer for state persistence
2594
2668
  * Required for human-in-the-loop workflows (askHuman tool), interrupts, and conversation continuity
2595
2669
  *
2670
+ * **Worker Checkpoint Namespaces:**
2671
+ * When worker agents are configured with `checkpointer: true`, they automatically use
2672
+ * separate checkpoint namespaces to enable proper handling of nested graph interrupts.
2673
+ *
2674
+ * The namespace format is: `{parent_thread_id}:worker:{workerId}`
2675
+ *
2676
+ * For example, if the parent thread ID is `thread_abc123` and the worker ID is `hr`,
2677
+ * the worker's checkpoint namespace will be `thread_abc123:worker:hr`.
2678
+ *
2679
+ * This allows worker agents to use the `askHuman` tool without causing infinite loops,
2680
+ * as each worker's state is saved and resumed independently.
2681
+ *
2596
2682
  * @example
2683
+ * Basic usage with checkpointer:
2597
2684
  * ```typescript
2598
2685
  * import { MemorySaver } from '@langchain/langgraph';
2599
2686
  *
@@ -2604,6 +2691,35 @@ interface MultiAgentSystemConfig {
2604
2691
  * checkpointer
2605
2692
  * });
2606
2693
  * ```
2694
+ *
2695
+ * @example
2696
+ * Worker agents with nested graph interrupts:
2697
+ * ```typescript
2698
+ * import { MemorySaver } from '@langchain/langgraph';
2699
+ * import { createReActAgent } from '@agentforge/patterns';
2700
+ * import { createAskHumanTool } from '@agentforge/tools';
2701
+ *
2702
+ * // Create worker agent with checkpointer: true
2703
+ * const hrAgent = createReActAgent({
2704
+ * model,
2705
+ * tools: [createAskHumanTool(), ...hrTools],
2706
+ * checkpointer: true // Use parent's checkpointer with separate namespace
2707
+ * });
2708
+ *
2709
+ * // Create multi-agent system with checkpointer
2710
+ * const system = createMultiAgentSystem({
2711
+ * supervisor: { strategy: 'skill-based', model },
2712
+ * workers: [{
2713
+ * id: 'hr',
2714
+ * capabilities: { skills: ['hr'], ... },
2715
+ * agent: hrAgent
2716
+ * }],
2717
+ * checkpointer: new MemorySaver()
2718
+ * });
2719
+ *
2720
+ * // When hrAgent calls askHuman, it will use checkpoint namespace:
2721
+ * // thread_abc123:worker:hr
2722
+ * ```
2607
2723
  */
2608
2724
  checkpointer?: BaseCheckpointSaver;
2609
2725
  }
package/dist/index.d.ts CHANGED
@@ -172,7 +172,12 @@ interface ReActAgentConfig {
172
172
  * Optional checkpointer for state persistence
173
173
  * Required for human-in-the-loop workflows (askHuman tool), interrupts, and conversation continuity
174
174
  *
175
+ * Can be:
176
+ * - A BaseCheckpointSaver instance (e.g., MemorySaver) for standalone agents
177
+ * - `true` to use the parent graph's checkpointer with a separate namespace (for nested graphs)
178
+ *
175
179
  * @example
180
+ * Standalone agent with its own checkpointer:
176
181
  * ```typescript
177
182
  * import { MemorySaver } from '@langchain/langgraph';
178
183
  *
@@ -183,8 +188,18 @@ interface ReActAgentConfig {
183
188
  * checkpointer
184
189
  * });
185
190
  * ```
191
+ *
192
+ * @example
193
+ * Nested agent using parent's checkpointer (for multi-agent systems):
194
+ * ```typescript
195
+ * const agent = createReActAgent({
196
+ * model,
197
+ * tools,
198
+ * checkpointer: true // Use parent's checkpointer with separate namespace
199
+ * });
200
+ * ```
186
201
  */
187
- checkpointer?: BaseCheckpointSaver;
202
+ checkpointer?: BaseCheckpointSaver | true;
188
203
  /**
189
204
  * Enable tool call deduplication to prevent calling the same tool with identical parameters multiple times
190
205
  * @default true
@@ -287,6 +302,31 @@ declare const DEFAULT_REACT_SYSTEM_PROMPT = "You are a helpful assistant that us
287
302
  * { configurable: { thread_id: 'conversation-123' } }
288
303
  * );
289
304
  * ```
305
+ *
306
+ * @example
307
+ * As a nested agent in a multi-agent system:
308
+ * ```typescript
309
+ * import { createReActAgent, createMultiAgentSystem } from '@agentforge/patterns';
310
+ * import { createAskHumanTool } from '@agentforge/tools';
311
+ * import { MemorySaver } from '@langchain/langgraph';
312
+ * import { ChatOpenAI } from '@langchain/openai';
313
+ *
314
+ * // Create worker agent with checkpointer: true to use parent's checkpointer
315
+ * const hrAgent = createReActAgent({
316
+ * model: new ChatOpenAI({ model: 'gpt-4' }),
317
+ * tools: [createAskHumanTool(), ...hrTools],
318
+ * checkpointer: true // Use parent's checkpointer with separate namespace
319
+ * });
320
+ *
321
+ * // Create multi-agent system with its own checkpointer
322
+ * const system = createMultiAgentSystem({
323
+ * workers: { hr: hrAgent },
324
+ * checkpointer: new MemorySaver() // Parent checkpointer
325
+ * });
326
+ *
327
+ * // When hrAgent calls askHuman, it will use a separate checkpoint namespace
328
+ * // Format: {parent_thread_id}:worker:hr
329
+ * ```
290
330
  */
291
331
  declare function createReActAgent(config: ReActAgentConfig, options?: ReActBuilderOptions): CompiledStateGraph<any, any>;
292
332
 
@@ -372,6 +412,40 @@ declare class ReActAgentBuilder {
372
412
  action?: string;
373
413
  observation?: string;
374
414
  }): this;
415
+ /**
416
+ * Set the checkpointer for state persistence (optional)
417
+ *
418
+ * Can be:
419
+ * - A BaseCheckpointSaver instance (e.g., MemorySaver) for standalone agents
420
+ * - `true` to use the parent graph's checkpointer with a separate namespace (for nested graphs)
421
+ *
422
+ * Required for human-in-the-loop workflows (askHuman tool) and conversation continuity.
423
+ *
424
+ * @param checkpointer - Checkpointer instance or `true` for nested graphs
425
+ *
426
+ * @example
427
+ * Standalone agent with its own checkpointer:
428
+ * ```typescript
429
+ * import { MemorySaver } from '@langchain/langgraph';
430
+ *
431
+ * const agent = new ReActAgentBuilder()
432
+ * .withModel(model)
433
+ * .withTools(tools)
434
+ * .withCheckpointer(new MemorySaver())
435
+ * .build();
436
+ * ```
437
+ *
438
+ * @example
439
+ * Nested agent using parent's checkpointer (for multi-agent systems):
440
+ * ```typescript
441
+ * const agent = new ReActAgentBuilder()
442
+ * .withModel(model)
443
+ * .withTools(tools)
444
+ * .withCheckpointer(true) // Use parent's checkpointer with separate namespace
445
+ * .build();
446
+ * ```
447
+ */
448
+ withCheckpointer(checkpointer: any): this;
375
449
  /**
376
450
  * Build the ReAct agent
377
451
  *
@@ -2593,7 +2667,20 @@ interface MultiAgentSystemConfig {
2593
2667
  * Optional checkpointer for state persistence
2594
2668
  * Required for human-in-the-loop workflows (askHuman tool), interrupts, and conversation continuity
2595
2669
  *
2670
+ * **Worker Checkpoint Namespaces:**
2671
+ * When worker agents are configured with `checkpointer: true`, they automatically use
2672
+ * separate checkpoint namespaces to enable proper handling of nested graph interrupts.
2673
+ *
2674
+ * The namespace format is: `{parent_thread_id}:worker:{workerId}`
2675
+ *
2676
+ * For example, if the parent thread ID is `thread_abc123` and the worker ID is `hr`,
2677
+ * the worker's checkpoint namespace will be `thread_abc123:worker:hr`.
2678
+ *
2679
+ * This allows worker agents to use the `askHuman` tool without causing infinite loops,
2680
+ * as each worker's state is saved and resumed independently.
2681
+ *
2596
2682
  * @example
2683
+ * Basic usage with checkpointer:
2597
2684
  * ```typescript
2598
2685
  * import { MemorySaver } from '@langchain/langgraph';
2599
2686
  *
@@ -2604,6 +2691,35 @@ interface MultiAgentSystemConfig {
2604
2691
  * checkpointer
2605
2692
  * });
2606
2693
  * ```
2694
+ *
2695
+ * @example
2696
+ * Worker agents with nested graph interrupts:
2697
+ * ```typescript
2698
+ * import { MemorySaver } from '@langchain/langgraph';
2699
+ * import { createReActAgent } from '@agentforge/patterns';
2700
+ * import { createAskHumanTool } from '@agentforge/tools';
2701
+ *
2702
+ * // Create worker agent with checkpointer: true
2703
+ * const hrAgent = createReActAgent({
2704
+ * model,
2705
+ * tools: [createAskHumanTool(), ...hrTools],
2706
+ * checkpointer: true // Use parent's checkpointer with separate namespace
2707
+ * });
2708
+ *
2709
+ * // Create multi-agent system with checkpointer
2710
+ * const system = createMultiAgentSystem({
2711
+ * supervisor: { strategy: 'skill-based', model },
2712
+ * workers: [{
2713
+ * id: 'hr',
2714
+ * capabilities: { skills: ['hr'], ... },
2715
+ * agent: hrAgent
2716
+ * }],
2717
+ * checkpointer: new MemorySaver()
2718
+ * });
2719
+ *
2720
+ * // When hrAgent calls askHuman, it will use checkpoint namespace:
2721
+ * // thread_abc123:worker:hr
2722
+ * ```
2607
2723
  */
2608
2724
  checkpointer?: BaseCheckpointSaver;
2609
2725
  }
package/dist/index.js CHANGED
@@ -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
  }
@@ -2259,12 +2298,26 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2259
2298
  logger.debug("No active assignment found", { workerId });
2260
2299
  return {};
2261
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
+ });
2262
2315
  const result = await agent.invoke(
2263
2316
  {
2264
2317
  messages: [{ role: "user", content: task }]
2265
2318
  },
2266
- config
2267
- // Pass through the config for checkpointing and interrupt support
2319
+ workerConfig
2320
+ // Worker-specific config with unique thread_id
2268
2321
  );
2269
2322
  const response = result.messages?.[result.messages.length - 1]?.content || "No response";
2270
2323
  logger.debug("Received response from ReAct agent", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/patterns",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Agent patterns (ReAct, Planner-Executor) for AgentForge framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",