@illuma-ai/agents 1.1.15 → 1.1.16

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.
Files changed (64) hide show
  1. package/dist/cjs/common/enum.cjs +13 -13
  2. package/dist/cjs/common/enum.cjs.map +1 -1
  3. package/dist/cjs/graphs/MultiAgentGraph.cjs +146 -150
  4. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  5. package/dist/cjs/main.cjs +2 -2
  6. package/dist/cjs/types/graph.cjs.map +1 -1
  7. package/dist/esm/common/enum.mjs +12 -12
  8. package/dist/esm/common/enum.mjs.map +1 -1
  9. package/dist/esm/graphs/MultiAgentGraph.mjs +147 -151
  10. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  11. package/dist/esm/main.mjs +1 -1
  12. package/dist/esm/types/graph.mjs.map +1 -1
  13. package/dist/types/common/enum.d.ts +11 -11
  14. package/dist/types/graphs/MultiAgentGraph.d.ts +38 -36
  15. package/dist/types/types/graph.d.ts +13 -7
  16. package/package.json +1 -1
  17. package/src/common/__tests__/enum.test.ts +14 -6
  18. package/src/common/enum.ts +11 -11
  19. package/src/graphs/MultiAgentGraph.ts +148 -152
  20. package/src/graphs/__tests__/multi-agent-delegate.test.ts +44 -44
  21. package/src/graphs/__tests__/multi-agent-edges.test.ts +83 -85
  22. package/src/scripts/multi-agent-chain.js +1 -1
  23. package/src/scripts/multi-agent-chain.ts +1 -1
  24. package/src/scripts/multi-agent-document-review-chain.js +1 -1
  25. package/src/scripts/multi-agent-document-review-chain.ts +1 -1
  26. package/src/scripts/multi-agent-hybrid-flow.js +3 -3
  27. package/src/scripts/multi-agent-hybrid-flow.ts +3 -3
  28. package/src/scripts/multi-agent-parallel.js +2 -2
  29. package/src/scripts/multi-agent-parallel.ts +2 -2
  30. package/src/scripts/multi-agent-sequence.js +2 -2
  31. package/src/scripts/multi-agent-sequence.ts +2 -2
  32. package/src/scripts/multi-agent-supervisor.js +5 -5
  33. package/src/scripts/multi-agent-supervisor.ts +5 -5
  34. package/src/scripts/poc-multi-agent-comprehensive.ts +7 -7
  35. package/src/scripts/sequential-full-metadata-test.js +1 -1
  36. package/src/scripts/sequential-full-metadata-test.ts +1 -1
  37. package/src/scripts/test-custom-prompt-key.js +3 -3
  38. package/src/scripts/test-custom-prompt-key.ts +3 -3
  39. package/src/scripts/test-handoff-input.js +1 -1
  40. package/src/scripts/test-handoff-input.ts +1 -1
  41. package/src/scripts/test-handoff-preamble.js +1 -1
  42. package/src/scripts/test-handoff-preamble.ts +1 -1
  43. package/src/scripts/test-handoff-steering.js +3 -3
  44. package/src/scripts/test-handoff-steering.ts +3 -3
  45. package/src/scripts/test-multi-agent-list-handoff.js +1 -1
  46. package/src/scripts/test-multi-agent-list-handoff.ts +1 -1
  47. package/src/scripts/test-parallel-agent-labeling.js +2 -2
  48. package/src/scripts/test-parallel-agent-labeling.ts +2 -2
  49. package/src/scripts/test-parallel-handoffs.js +2 -2
  50. package/src/scripts/test-parallel-handoffs.ts +2 -2
  51. package/src/scripts/test-thinking-handoff-bedrock.js +1 -1
  52. package/src/scripts/test-thinking-handoff-bedrock.ts +1 -1
  53. package/src/scripts/test-thinking-handoff.js +1 -1
  54. package/src/scripts/test-thinking-handoff.ts +1 -1
  55. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js +1 -1
  56. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +1 -1
  57. package/src/scripts/test-tool-before-handoff-role-order.js +1 -1
  58. package/src/scripts/test-tool-before-handoff-role-order.ts +1 -1
  59. package/src/scripts/test-tools-before-handoff.js +1 -1
  60. package/src/scripts/test-tools-before-handoff.ts +1 -1
  61. package/src/specs/agent-handoffs-bedrock.integration.test.ts +6 -6
  62. package/src/specs/agent-handoffs.test.ts +35 -35
  63. package/src/specs/thinking-handoff.test.ts +9 -9
  64. package/src/types/graph.ts +13 -7
@@ -25,35 +25,35 @@ import { StandardGraph } from './Graph';
25
25
  import {
26
26
  Constants,
27
27
  EdgeType,
28
- DEFAULT_DELEGATE_MAX_RESULT_CHARS,
28
+ DEFAULT_HANDOFF_MAX_RESULT_CHARS,
29
29
  } from '@/common';
30
30
 
31
31
  /** Pattern to extract instructions from transfer ToolMessage content */
32
- const HANDOFF_INSTRUCTIONS_PATTERN = /(?:Instructions?|Context):\s*(.+)/is;
32
+ const TRANSFER_INSTRUCTIONS_PATTERN = /(?:Instructions?|Context):\s*(.+)/is;
33
33
 
34
34
  /**
35
35
  * MultiAgentGraph extends StandardGraph to support dynamic multi-agent workflows
36
36
  * with handoffs, fan-in/fan-out, and other composable patterns.
37
37
  *
38
38
  * Key behavior:
39
- * - Agents with ONLY handoff edges: Can dynamically route to any handoff destination
40
- * - Agents with ONLY direct edges: Always follow their direct edges
41
- * - Agents with BOTH: Use Command for exclusive routing (handoff OR direct, not both)
42
- * - If handoff occurs: Only the handoff destination executes
43
- * - If no handoff: Direct edges execute (potentially in parallel)
39
+ * - Agents with ONLY transfer edges: Can dynamically route to any transfer destination
40
+ * - Agents with ONLY sequence edges: Always follow their sequence edges
41
+ * - Agents with BOTH: Use Command for exclusive routing (transfer OR sequence, not both)
42
+ * - If transfer occurs: Only the transfer destination executes
43
+ * - If no transfer: Sequence edges execute (potentially in parallel)
44
44
  *
45
- * This enables the common pattern where an agent either delegates (handoff)
46
- * OR continues its workflow (direct edges), but not both simultaneously.
45
+ * This enables the common pattern where an agent either transfers (one-way)
46
+ * OR continues its workflow (sequence edges), but not both simultaneously.
47
47
  */
48
48
  export class MultiAgentGraph extends StandardGraph {
49
49
  private edges: t.GraphEdge[];
50
50
  private startingNodes: Set<string> = new Set();
51
- private directEdges: t.GraphEdge[] = [];
51
+ private sequenceEdges: t.GraphEdge[] = [];
52
+ private transferEdges: t.GraphEdge[] = [];
52
53
  private handoffEdges: t.GraphEdge[] = [];
53
- private delegateEdges: t.GraphEdge[] = [];
54
54
  /**
55
55
  * Lazily populated registry of compiled subgraphs, keyed by agentId.
56
- * Delegate tools are created in the constructor but reference subgraphs
56
+ * Handoff tools are created in the constructor but reference subgraphs
57
57
  * that are only created in createWorkflow(). This Map bridges that gap —
58
58
  * tools capture the Map reference in their closure, and createWorkflow()
59
59
  * populates it before any tool invocation occurs.
@@ -81,42 +81,40 @@ export class MultiAgentGraph extends StandardGraph {
81
81
  this.edges = input.edges;
82
82
  this.categorizeEdges();
83
83
  this.analyzeGraph();
84
+ this.createTransferTools();
84
85
  this.createHandoffTools();
85
- this.createDelegateTools();
86
86
  console.debug(
87
87
  `[MultiAgentGraph] Constructor complete: ${this.agentContexts.size} agents, ${this.edges.length} edges`
88
88
  );
89
89
  }
90
90
 
91
91
  /**
92
- * Categorize edges into handoff and direct types
92
+ * Categorize edges into handoff, transfer, and sequence types
93
93
  */
94
94
  private categorizeEdges(): void {
95
95
  for (const edge of this.edges) {
96
- // Default behavior: edges with conditions or explicit 'handoff' type are handoff edges
97
- // Edges with explicit 'direct' type or multi-destination without conditions are direct edges
98
- if (edge.edgeType === EdgeType.DELEGATE) {
99
- this.delegateEdges.push(edge);
100
- } else if (edge.edgeType === EdgeType.DIRECT) {
101
- this.directEdges.push(edge);
102
- } else if (edge.edgeType === EdgeType.HANDOFF || edge.condition != null) {
96
+ if (edge.edgeType === EdgeType.HANDOFF) {
103
97
  this.handoffEdges.push(edge);
98
+ } else if (edge.edgeType === EdgeType.SEQUENCE) {
99
+ this.sequenceEdges.push(edge);
100
+ } else if (edge.edgeType === EdgeType.TRANSFER || edge.condition != null) {
101
+ this.transferEdges.push(edge);
104
102
  } else {
105
- // Default: single-to-single edges are handoff, single-to-multiple are direct
103
+ // Default: single-to-single edges are transfer, single-to-multiple are sequence
106
104
  const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];
107
105
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
108
106
 
109
107
  if (sources.length === 1 && destinations.length > 1) {
110
- // Fan-out pattern defaults to direct
111
- this.directEdges.push(edge);
108
+ // Fan-out pattern defaults to sequence
109
+ this.sequenceEdges.push(edge);
112
110
  } else {
113
- // Everything else defaults to handoff
114
- this.handoffEdges.push(edge);
111
+ // Everything else defaults to transfer
112
+ this.transferEdges.push(edge);
115
113
  }
116
114
  }
117
115
  }
118
116
  console.debug(
119
- `[MultiAgentGraph] Edge categorization: ${this.handoffEdges.length} handoff, ${this.directEdges.length} direct, ${this.delegateEdges.length} delegate (of ${this.edges.length} total)`
117
+ `[MultiAgentGraph] Edge categorization: ${this.handoffEdges.length} handoff, ${this.transferEdges.length} transfer, ${this.sequenceEdges.length} sequence (of ${this.edges.length} total)`
120
118
  );
121
119
  }
122
120
 
@@ -187,8 +185,8 @@ export class MultiAgentGraph extends StandardGraph {
187
185
  if (visited.has(current)) continue;
188
186
  visited.add(current);
189
187
 
190
- // Find direct edges from this node
191
- for (const edge of this.directEdges) {
188
+ // Find sequence edges from this node
189
+ for (const edge of this.sequenceEdges) {
192
190
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
193
191
  if (!sources.includes(current)) continue;
194
192
 
@@ -216,8 +214,8 @@ export class MultiAgentGraph extends StandardGraph {
216
214
  }
217
215
  }
218
216
 
219
- // Also follow handoff and delegate edges for traversal (they don't create parallel groups)
220
- for (const edge of [...this.handoffEdges, ...this.delegateEdges]) {
217
+ // Also follow transfer and handoff edges for traversal (they don't create parallel groups)
218
+ for (const edge of [...this.transferEdges, ...this.handoffEdges]) {
221
219
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
222
220
  if (!sources.includes(current)) continue;
223
221
 
@@ -267,54 +265,52 @@ export class MultiAgentGraph extends StandardGraph {
267
265
  }
268
266
 
269
267
  /**
270
- * Create handoff tools for agents based on handoff edges only
268
+ * Create transfer tools for agents based on transfer edges only.
269
+ * Transfer tools return Command for one-way routing — parent exits, child takes over.
271
270
  */
272
- private createHandoffTools(): void {
273
- // Group handoff edges by source agent(s)
274
- const handoffsByAgent = new Map<string, t.GraphEdge[]>();
271
+ private createTransferTools(): void {
272
+ const transfersByAgent = new Map<string, t.GraphEdge[]>();
275
273
 
276
- // Only process handoff edges for tool creation
277
- for (const edge of this.handoffEdges) {
274
+ for (const edge of this.transferEdges) {
278
275
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
279
276
  sources.forEach((source) => {
280
- if (!handoffsByAgent.has(source)) {
281
- handoffsByAgent.set(source, []);
277
+ if (!transfersByAgent.has(source)) {
278
+ transfersByAgent.set(source, []);
282
279
  }
283
- handoffsByAgent.get(source)!.push(edge);
280
+ transfersByAgent.get(source)!.push(edge);
284
281
  });
285
282
  }
286
283
 
287
- // Create handoff tools for each agent
288
- for (const [agentId, edges] of handoffsByAgent) {
284
+ for (const [agentId, edges] of transfersByAgent) {
289
285
  const agentContext = this.agentContexts.get(agentId);
290
286
  if (!agentContext) continue;
291
287
 
292
- // Create handoff tools for this agent's outgoing edges
293
- const handoffTools: t.GenericTool[] = [];
288
+ const transferTools: t.GenericTool[] = [];
294
289
  const sourceAgentName = agentContext.name ?? agentId;
295
290
  for (const edge of edges) {
296
- handoffTools.push(
297
- ...this.createHandoffToolsForEdge(edge, agentId, sourceAgentName)
291
+ transferTools.push(
292
+ ...this.createTransferToolsForEdge(edge, agentId, sourceAgentName)
298
293
  );
299
294
  }
300
295
 
301
296
  if (!agentContext.graphTools) {
302
297
  agentContext.graphTools = [];
303
298
  }
304
- agentContext.graphTools.push(...handoffTools);
299
+ agentContext.graphTools.push(...transferTools);
305
300
  console.debug(
306
- `[MultiAgentGraph] Handoff tools for "${agentId}": [${handoffTools.map((t) => t.name).join(', ')}]`
301
+ `[MultiAgentGraph] Transfer tools for "${agentId}": [${transferTools.map((t) => t.name).join(', ')}]`
307
302
  );
308
303
  }
309
304
  }
310
305
 
311
306
  /**
312
- * Create handoff tools for an edge (handles multiple destinations)
313
- * @param edge - The graph edge defining the handoff
314
- * @param sourceAgentId - The ID of the agent that will perform the handoff
307
+ * Create transfer tools for an edge (handles multiple destinations).
308
+ * Transfer tools return Command for one-way routing parent exits, child takes over.
309
+ * @param edge - The graph edge defining the transfer
310
+ * @param sourceAgentId - The ID of the agent that will perform the transfer
315
311
  * @param sourceAgentName - The human-readable name of the source agent
316
312
  */
317
- private createHandoffToolsForEdge(
313
+ private createTransferToolsForEdge(
318
314
  edge: t.GraphEdge,
319
315
  sourceAgentId: string,
320
316
  sourceAgentName: string
@@ -329,9 +325,9 @@ export class MultiAgentGraph extends StandardGraph {
329
325
  edge.description ?? 'Conditionally transfer control based on state';
330
326
 
331
327
  /** Check if we have a prompt for handoff input */
332
- const hasHandoffInput =
328
+ const hasTransferInput =
333
329
  edge.prompt != null && typeof edge.prompt === 'string';
334
- const handoffInputDescription = hasHandoffInput ? edge.prompt : undefined;
330
+ const transferInputDescription = hasTransferInput ? edge.prompt : undefined;
335
331
  const promptKey = edge.promptKey ?? 'instructions';
336
332
 
337
333
  tools.push(
@@ -360,7 +356,7 @@ export class MultiAgentGraph extends StandardGraph {
360
356
 
361
357
  let content = `Conditionally transferred to ${destination}`;
362
358
  if (
363
- hasHandoffInput &&
359
+ hasTransferInput &&
364
360
  promptKey in input &&
365
361
  input[promptKey] != null
366
362
  ) {
@@ -387,13 +383,13 @@ export class MultiAgentGraph extends StandardGraph {
387
383
  },
388
384
  {
389
385
  name: toolName,
390
- schema: hasHandoffInput
386
+ schema: hasTransferInput
391
387
  ? {
392
388
  type: 'object',
393
389
  properties: {
394
390
  [promptKey]: {
395
391
  type: 'string',
396
- description: handoffInputDescription as string,
392
+ description: transferInputDescription as string,
397
393
  },
398
394
  },
399
395
  required: [],
@@ -410,12 +406,12 @@ export class MultiAgentGraph extends StandardGraph {
410
406
  const destContext = this.agentContexts.get(destination);
411
407
  const toolDescription =
412
408
  edge.description ??
413
- this.buildDefaultHandoffDescription(destContext, destination);
409
+ this.buildDefaultTransferDescription(destContext, destination);
414
410
 
415
411
  /** Check if we have a prompt for handoff input */
416
- const hasHandoffInput =
412
+ const hasTransferInput =
417
413
  edge.prompt != null && typeof edge.prompt === 'string';
418
- const handoffInputDescription = hasHandoffInput
414
+ const transferInputDescription = hasTransferInput
419
415
  ? edge.prompt
420
416
  : undefined;
421
417
  const promptKey = edge.promptKey ?? 'instructions';
@@ -430,7 +426,7 @@ export class MultiAgentGraph extends StandardGraph {
430
426
 
431
427
  let content = `Successfully transferred to ${destination}`;
432
428
  if (
433
- hasHandoffInput &&
429
+ hasTransferInput &&
434
430
  promptKey in input &&
435
431
  input[promptKey] != null
436
432
  ) {
@@ -521,13 +517,13 @@ export class MultiAgentGraph extends StandardGraph {
521
517
  },
522
518
  {
523
519
  name: toolName,
524
- schema: hasHandoffInput
520
+ schema: hasTransferInput
525
521
  ? {
526
522
  type: 'object',
527
523
  properties: {
528
524
  [promptKey]: {
529
525
  type: 'string',
530
- description: handoffInputDescription as string,
526
+ description: transferInputDescription as string,
531
527
  },
532
528
  },
533
529
  required: [],
@@ -544,13 +540,13 @@ export class MultiAgentGraph extends StandardGraph {
544
540
  }
545
541
 
546
542
  /**
547
- * Builds a meaningful default description for a handoff tool when no explicit
543
+ * Builds a meaningful default description for a transfer tool when no explicit
548
544
  * edge.description is provided. Uses the destination agent's name and description
549
545
  * so the LLM can make informed routing decisions.
550
546
  * @param destContext - AgentContext of the destination agent (may be undefined)
551
547
  * @param destinationId - Raw agent ID (fallback when context unavailable)
552
548
  */
553
- private buildDefaultHandoffDescription(
549
+ private buildDefaultTransferDescription(
554
550
  destContext: import('@/agents/AgentContext').AgentContext | undefined,
555
551
  destinationId: string
556
552
  ): string {
@@ -564,72 +560,72 @@ export class MultiAgentGraph extends StandardGraph {
564
560
  }
565
561
 
566
562
  /**
567
- * Create delegate tools for agents based on delegate edges.
568
- * Delegate tools invoke child agent subgraphs inline and return the result
569
- * as a string to the parent agent's context. Unlike handoff tools (which
570
- * return Command for fire-and-forget routing), delegate tools execute the
571
- * child, extract the final text, and return it within the parent's agent loop.
563
+ * Create handoff tools for agents based on handoff edges.
564
+ * Handoff tools invoke child agent subgraphs inline and return the result
565
+ * as a string to the parent agent's context. Unlike transfer tools (which
566
+ * return Command for one-way routing), handoff tools execute the child,
567
+ * extract the final text, and return it within the parent's agent loop.
572
568
  *
573
569
  * This enables the supervisor pattern: parent calls child → gets result → thinks → calls another.
574
570
  */
575
- private createDelegateTools(): void {
576
- const delegatesByAgent = new Map<string, t.GraphEdge[]>();
571
+ private createHandoffTools(): void {
572
+ const handoffsByAgent = new Map<string, t.GraphEdge[]>();
577
573
 
578
- for (const edge of this.delegateEdges) {
574
+ for (const edge of this.handoffEdges) {
579
575
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
580
576
  sources.forEach((source) => {
581
- if (!delegatesByAgent.has(source)) {
582
- delegatesByAgent.set(source, []);
577
+ if (!handoffsByAgent.has(source)) {
578
+ handoffsByAgent.set(source, []);
583
579
  }
584
- delegatesByAgent.get(source)!.push(edge);
580
+ handoffsByAgent.get(source)!.push(edge);
585
581
  });
586
582
  }
587
583
 
588
- for (const [agentId, edges] of delegatesByAgent) {
584
+ for (const [agentId, edges] of handoffsByAgent) {
589
585
  const agentContext = this.agentContexts.get(agentId);
590
586
  if (!agentContext) continue;
591
587
 
592
- const delegateTools: t.GenericTool[] = [];
588
+ const handoffTools: t.GenericTool[] = [];
593
589
  for (const edge of edges) {
594
- delegateTools.push(
595
- ...this.createDelegateToolsForEdge(edge, agentId)
590
+ handoffTools.push(
591
+ ...this.createHandoffToolsForEdge(edge, agentId)
596
592
  );
597
593
  }
598
594
 
599
595
  if (!agentContext.graphTools) {
600
596
  agentContext.graphTools = [];
601
597
  }
602
- agentContext.graphTools.push(...delegateTools);
598
+ agentContext.graphTools.push(...handoffTools);
603
599
  console.debug(
604
- `[MultiAgentGraph] Delegate tools for "${agentId}": [${delegateTools.map((t) => t.name).join(', ')}]`
600
+ `[MultiAgentGraph] Handoff tools for "${agentId}": [${handoffTools.map((t) => t.name).join(', ')}]`
605
601
  );
606
602
  }
607
603
  }
608
604
 
609
605
  /**
610
- * Create delegate tools for an edge (handles multiple destinations).
611
- * Each delegate tool invokes the child agent's compiled subgraph inline,
606
+ * Create handoff tools for an edge (handles multiple destinations).
607
+ * Each handoff tool invokes the child agent's compiled subgraph inline,
612
608
  * extracts the final AI message text, truncates it, and returns it as
613
609
  * a string (which becomes a ToolMessage in the parent's context).
614
610
  *
615
- * @param edge - The graph edge defining the delegation
611
+ * @param edge - The graph edge defining the handoff
616
612
  * @param sourceAgentId - The ID of the parent/supervisor agent
617
613
  */
618
- private createDelegateToolsForEdge(
614
+ private createHandoffToolsForEdge(
619
615
  edge: t.GraphEdge,
620
616
  sourceAgentId: string
621
617
  ): t.GenericTool[] {
622
618
  const tools: t.GenericTool[] = [];
623
619
  const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];
624
620
  const maxResultChars =
625
- edge.maxResultChars ?? DEFAULT_DELEGATE_MAX_RESULT_CHARS;
621
+ edge.maxResultChars ?? DEFAULT_HANDOFF_MAX_RESULT_CHARS;
626
622
 
627
623
  for (const destination of destinations) {
628
- const toolName = `${Constants.LC_DELEGATE_TO_}${destination}`;
624
+ const toolName = `${Constants.LC_HANDOFF_TO_}${destination}`;
629
625
  const destContext = this.agentContexts.get(destination);
630
626
  const toolDescription =
631
627
  edge.description ??
632
- this.buildDefaultDelegateDescription(destContext, destination);
628
+ this.buildDefaultHandoffDescription(destContext, destination);
633
629
 
634
630
  const hasPromptInput =
635
631
  edge.prompt != null && typeof edge.prompt === 'string';
@@ -646,7 +642,7 @@ export class MultiAgentGraph extends StandardGraph {
646
642
  const subgraph = registry.get(destination);
647
643
  if (!subgraph) {
648
644
  throw new Error(
649
- `Delegate target "${destination}" subgraph not found in registry. ` +
645
+ `Handoff target "${destination}" subgraph not found in registry. ` +
650
646
  'This is a bug: createWorkflow() should have populated the subgraph registry.'
651
647
  );
652
648
  }
@@ -671,7 +667,7 @@ export class MultiAgentGraph extends StandardGraph {
671
667
  };
672
668
 
673
669
  console.debug(
674
- `[MultiAgentGraph] Delegate "${sourceAgentId}" -> "${destination}" START ` +
670
+ `[MultiAgentGraph] Handoff "${sourceAgentId}" -> "${destination}" START ` +
675
671
  `(messages: ${childMessages.length})`
676
672
  );
677
673
 
@@ -683,17 +679,17 @@ export class MultiAgentGraph extends StandardGraph {
683
679
  */
684
680
  const result = await subgraph.invoke(childState, config);
685
681
 
686
- const resultText = MultiAgentGraph.extractDelegateResult(
682
+ const resultText = MultiAgentGraph.extractHandoffResult(
687
683
  result.messages,
688
684
  destination
689
685
  );
690
- const truncatedResult = MultiAgentGraph.truncateDelegateResult(
686
+ const truncatedResult = MultiAgentGraph.truncateHandoffResult(
691
687
  resultText,
692
688
  maxResultChars
693
689
  );
694
690
 
695
691
  console.debug(
696
- `[MultiAgentGraph] Delegate "${sourceAgentId}" -> "${destination}" DONE ` +
692
+ `[MultiAgentGraph] Handoff "${sourceAgentId}" -> "${destination}" DONE ` +
697
693
  `(result: ${resultText.length} chars` +
698
694
  `${truncatedResult.length < resultText.length ? `, truncated to ${truncatedResult.length}` : ''})`
699
695
  );
@@ -703,10 +699,10 @@ export class MultiAgentGraph extends StandardGraph {
703
699
  const errorMessage =
704
700
  err instanceof Error ? err.message : String(err);
705
701
  console.error(
706
- `[MultiAgentGraph] Delegate "${sourceAgentId}" -> "${destination}" ERROR:`,
702
+ `[MultiAgentGraph] Handoff "${sourceAgentId}" -> "${destination}" ERROR:`,
707
703
  errorMessage
708
704
  );
709
- return `[Delegate to "${destination}" failed: ${errorMessage}]`;
705
+ return `[Handoff to "${destination}" failed: ${errorMessage}]`;
710
706
  }
711
707
  },
712
708
  {
@@ -739,7 +735,7 @@ export class MultiAgentGraph extends StandardGraph {
739
735
  * @param messages - The child agent's output messages
740
736
  * @param agentId - The child agent ID (for fallback message)
741
737
  */
742
- static extractDelegateResult(
738
+ static extractHandoffResult(
743
739
  messages: BaseMessage[],
744
740
  agentId: string
745
741
  ): string {
@@ -780,19 +776,19 @@ export class MultiAgentGraph extends StandardGraph {
780
776
  }
781
777
 
782
778
  /**
783
- * Truncate delegate result using head/tail strategy (60/40 split).
779
+ * Truncate handoff result using head/tail strategy (60/40 split).
784
780
  * Preserves the beginning (key findings) and end (conclusions).
785
781
  * Matches the TaskTool.truncateResult pattern from Ranger.
786
782
  * @param result - The full result text
787
783
  * @param maxChars - Maximum allowed characters
788
784
  */
789
- static truncateDelegateResult(result: string, maxChars: number): string {
785
+ static truncateHandoffResult(result: string, maxChars: number): string {
790
786
  if (!result || result.length <= maxChars) {
791
787
  return result;
792
788
  }
793
789
 
794
790
  const truncationNotice =
795
- '\n\n[... delegate output truncated — middle section omitted to fit parent context ...]\n\n';
791
+ '\n\n[... handoff output truncated — middle section omitted to fit parent context ...]\n\n';
796
792
  const available = maxChars - truncationNotice.length;
797
793
  if (available <= 0) {
798
794
  return result.substring(0, maxChars);
@@ -809,11 +805,11 @@ export class MultiAgentGraph extends StandardGraph {
809
805
  }
810
806
 
811
807
  /**
812
- * Build a meaningful default description for a delegate tool.
808
+ * Build a meaningful default description for a handoff tool.
813
809
  * @param destContext - AgentContext of the destination agent
814
810
  * @param destinationId - Raw agent ID (fallback)
815
811
  */
816
- private buildDefaultDelegateDescription(
812
+ private buildDefaultHandoffDescription(
817
813
  destContext: import('@/agents/AgentContext').AgentContext | undefined,
818
814
  destinationId: string
819
815
  ): string {
@@ -821,9 +817,9 @@ export class MultiAgentGraph extends StandardGraph {
821
817
  const agentDescription = destContext?.description;
822
818
 
823
819
  if (agentDescription != null && agentDescription !== '') {
824
- return `Delegate task to "${displayName}": ${agentDescription}. The agent will execute and return its result.`;
820
+ return `Hand off task to "${displayName}": ${agentDescription}. The agent will execute and return its result.`;
825
821
  }
826
- return `Delegate task to "${displayName}" and receive its result.`;
822
+ return `Hand off task to "${displayName}" and receive its result.`;
827
823
  }
828
824
 
829
825
  /**
@@ -846,7 +842,7 @@ export class MultiAgentGraph extends StandardGraph {
846
842
  * @param agentId - The agent ID to check for handoff reception
847
843
  * @returns Object with filtered messages, extracted instructions, source agent, and parallel siblings
848
844
  */
849
- private processHandoffReception(
845
+ private processTransferReception(
850
846
  messages: BaseMessage[],
851
847
  agentId: string
852
848
  ): {
@@ -886,8 +882,8 @@ export class MultiAgentGraph extends StandardGraph {
886
882
  if (isTransferMessage) {
887
883
  destinationAgent = toolName.replace(Constants.LC_TRANSFER_TO_, '');
888
884
  } else if (isConditionalTransfer) {
889
- const handoffDest = candidateMsg.additional_kwargs.handoff_destination;
890
- destinationAgent = typeof handoffDest === 'string' ? handoffDest : null;
885
+ const transferDest = candidateMsg.additional_kwargs.handoff_destination;
886
+ destinationAgent = typeof transferDest === 'string' ? transferDest : null;
891
887
  }
892
888
 
893
889
  /** Check if this transfer targets our agent */
@@ -907,7 +903,7 @@ export class MultiAgentGraph extends StandardGraph {
907
903
  ? toolMessage.content
908
904
  : JSON.stringify(toolMessage.content);
909
905
 
910
- const instructionsMatch = contentStr.match(HANDOFF_INSTRUCTIONS_PATTERN);
906
+ const instructionsMatch = contentStr.match(TRANSFER_INSTRUCTIONS_PATTERN);
911
907
  const instructions = instructionsMatch?.[1]?.trim() ?? null;
912
908
 
913
909
  /** Extract source agent name from additional_kwargs */
@@ -1138,7 +1134,7 @@ export class MultiAgentGraph extends StandardGraph {
1138
1134
  }
1139
1135
 
1140
1136
  /**
1141
- * Create the multi-agent workflow with dynamic handoffs
1137
+ * Create the multi-agent workflow with handoffs, transfers, and sequences
1142
1138
  */
1143
1139
  override createWorkflow(): t.CompiledMultiAgentWorkflow {
1144
1140
  const StateAnnotation = Annotation.Root({
@@ -1166,45 +1162,45 @@ export class MultiAgentGraph extends StandardGraph {
1166
1162
  // Add all agents as complete subgraphs
1167
1163
  for (const [agentId] of this.agentContexts) {
1168
1164
  // Get all possible destinations for this agent
1169
- const handoffDestinations = new Set<string>();
1170
- const directDestinations = new Set<string>();
1165
+ const transferDestinations = new Set<string>();
1166
+ const sequenceDestinations = new Set<string>();
1171
1167
 
1172
- // Check handoff edges for destinations
1173
- for (const edge of this.handoffEdges) {
1168
+ // Check transfer edges for destinations
1169
+ for (const edge of this.transferEdges) {
1174
1170
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
1175
1171
  if (sources.includes(agentId) === true) {
1176
1172
  const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
1177
- dests.forEach((dest) => handoffDestinations.add(dest));
1173
+ dests.forEach((dest) => transferDestinations.add(dest));
1178
1174
  }
1179
1175
  }
1180
1176
 
1181
- // Check direct edges for destinations
1182
- for (const edge of this.directEdges) {
1177
+ // Check sequence edges for destinations
1178
+ for (const edge of this.sequenceEdges) {
1183
1179
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
1184
1180
  if (sources.includes(agentId) === true) {
1185
1181
  const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
1186
- dests.forEach((dest) => directDestinations.add(dest));
1182
+ dests.forEach((dest) => sequenceDestinations.add(dest));
1187
1183
  }
1188
1184
  }
1189
1185
 
1190
- /** Check if this agent has BOTH handoff and direct edges */
1191
- const hasHandoffEdges = handoffDestinations.size > 0;
1192
- const hasDirectEdges = directDestinations.size > 0;
1193
- const needsCommandRouting = hasHandoffEdges && hasDirectEdges;
1186
+ /** Check if this agent has BOTH transfer and sequence edges */
1187
+ const hasTransferEdges = transferDestinations.size > 0;
1188
+ const hasSequenceEdges = sequenceDestinations.size > 0;
1189
+ const needsCommandRouting = hasTransferEdges && hasSequenceEdges;
1194
1190
 
1195
1191
  /** Collect all possible destinations for this agent */
1196
1192
  const allDestinations = new Set([
1197
- ...handoffDestinations,
1198
- ...directDestinations,
1193
+ ...transferDestinations,
1194
+ ...sequenceDestinations,
1199
1195
  ]);
1200
- if (handoffDestinations.size > 0 || directDestinations.size === 0) {
1196
+ if (transferDestinations.size > 0 || sequenceDestinations.size === 0) {
1201
1197
  allDestinations.add(END);
1202
1198
  }
1203
1199
 
1204
1200
  /** Agent subgraph (includes agent + tools) */
1205
1201
  const agentSubgraph = this.createAgentSubgraph(agentId);
1206
1202
 
1207
- /** Register subgraph for delegate tools (lazy reference resolution) */
1203
+ /** Register subgraph for handoff tools (lazy reference resolution) */
1208
1204
  this.subgraphRegistry.set(agentId, agentSubgraph);
1209
1205
 
1210
1206
  /** Wrapper function that handles agentMessages channel, handoff reception, and conditional routing */
@@ -1218,25 +1214,25 @@ export class MultiAgentGraph extends StandardGraph {
1218
1214
  let result: t.MultiAgentGraphState;
1219
1215
 
1220
1216
  /**
1221
- * Check if this agent is receiving a handoff.
1217
+ * Check if this agent is receiving a transfer.
1222
1218
  * If so, filter out the transfer messages and inject instructions as preamble.
1223
1219
  * This prevents the receiving agent from seeing the transfer as "completed work"
1224
1220
  * and prematurely producing an end token.
1225
1221
  */
1226
- const handoffContext = this.processHandoffReception(
1222
+ const transferContext = this.processTransferReception(
1227
1223
  state.messages,
1228
1224
  agentId
1229
1225
  );
1230
1226
 
1231
- if (handoffContext !== null) {
1227
+ if (transferContext !== null) {
1232
1228
  const {
1233
1229
  filteredMessages,
1234
1230
  instructions,
1235
1231
  sourceAgentName,
1236
1232
  parallelSiblings,
1237
- } = handoffContext;
1233
+ } = transferContext;
1238
1234
  console.debug(
1239
- `[MultiAgentGraph] Agent "${agentId}" receiving handoff from "${sourceAgentName}" (instructions: ${instructions != null}, parallelSiblings: ${parallelSiblings.length})`
1235
+ `[MultiAgentGraph] Agent "${agentId}" receiving transfer from "${sourceAgentName}" (instructions: ${instructions != null}, parallelSiblings: ${parallelSiblings.length})`
1240
1236
  );
1241
1237
 
1242
1238
  /**
@@ -1381,9 +1377,9 @@ export class MultiAgentGraph extends StandardGraph {
1381
1377
  `[MultiAgentGraph] Agent "${agentId}" wrapper EXIT (result messages: ${result.messages.length})`
1382
1378
  );
1383
1379
 
1384
- /** If agent has both handoff and direct edges, use Command for exclusive routing */
1380
+ /** If agent has both transfer and sequence edges, use Command for exclusive routing */
1385
1381
  if (needsCommandRouting) {
1386
- /** Check if a handoff occurred */
1382
+ /** Check if a transfer occurred */
1387
1383
  const lastMessage = result.messages[
1388
1384
  result.messages.length - 1
1389
1385
  ] as BaseMessage | null;
@@ -1393,26 +1389,26 @@ export class MultiAgentGraph extends StandardGraph {
1393
1389
  typeof lastMessage.name === 'string' &&
1394
1390
  lastMessage.name.startsWith(Constants.LC_TRANSFER_TO_)
1395
1391
  ) {
1396
- /** Handoff occurred - extract destination and navigate there exclusively */
1397
- const handoffDest = lastMessage.name.replace(
1392
+ /** Transfer occurred - extract destination and navigate there exclusively */
1393
+ const transferDest = lastMessage.name.replace(
1398
1394
  Constants.LC_TRANSFER_TO_,
1399
1395
  ''
1400
1396
  );
1401
1397
  console.debug(
1402
- `[MultiAgentGraph] Command routing: "${agentId}" -> handoff to "${handoffDest}" (direct edges skipped: [${Array.from(directDestinations).join(', ')}])`
1398
+ `[MultiAgentGraph] Command routing: "${agentId}" -> transfer to "${transferDest}" (sequence edges skipped: [${Array.from(sequenceDestinations).join(', ')}])`
1403
1399
  );
1404
1400
 
1405
1401
  /** Validate destination agent exists */
1406
- if (!this.agentContexts.has(handoffDest)) {
1402
+ if (!this.agentContexts.has(transferDest)) {
1407
1403
  const availableAgents = Array.from(
1408
1404
  this.agentContexts.keys()
1409
1405
  ).join(', ');
1410
1406
  console.error(
1411
- `[MultiAgentGraph] Handoff to non-existent agent "${handoffDest}". Available: ${availableAgents}`
1407
+ `[MultiAgentGraph] Transfer to non-existent agent "${transferDest}". Available: ${availableAgents}`
1412
1408
  );
1413
1409
  /** Return error to model so it can self-correct */
1414
1410
  const errorMsg = new ToolMessage({
1415
- content: `Transfer failed: agent "${handoffDest}" does not exist. Available agents: ${availableAgents}. Please choose a valid agent to transfer to.`,
1411
+ content: `Transfer failed: agent "${transferDest}" does not exist. Available agents: ${availableAgents}. Please choose a valid agent to transfer to.`,
1416
1412
  tool_call_id: (lastMessage as ToolMessage).tool_call_id,
1417
1413
  name: lastMessage.name,
1418
1414
  });
@@ -1423,7 +1419,7 @@ export class MultiAgentGraph extends StandardGraph {
1423
1419
  }
1424
1420
 
1425
1421
  /** Pre-handoff context compaction: if receiving agent has smaller budget */
1426
- const receiverContext = this.agentContexts.get(handoffDest);
1422
+ const receiverContext = this.agentContexts.get(transferDest);
1427
1423
  const senderContext = this.agentContexts.get(agentId);
1428
1424
  if (
1429
1425
  receiverContext?.maxContextTokens != null &&
@@ -1439,7 +1435,7 @@ export class MultiAgentGraph extends StandardGraph {
1439
1435
  if (currentSize > receiverBudget * 0.7) {
1440
1436
  console.warn(
1441
1437
  `[MultiAgentGraph] Pre-handoff compaction: context (${currentSize} tokens) exceeds ` +
1442
- `70% of receiver "${handoffDest}" budget (${receiverBudget} tokens)`
1438
+ `70% of receiver "${transferDest}" budget (${receiverBudget} tokens)`
1443
1439
  );
1444
1440
 
1445
1441
  /** Generate handoff briefing */
@@ -1457,8 +1453,8 @@ export class MultiAgentGraph extends StandardGraph {
1457
1453
  summaryBudget: Math.floor(receiverBudget * 0.2),
1458
1454
  isMultiAgent: true,
1459
1455
  agentWorkflowState: {
1460
- currentAgentId: handoffDest,
1461
- agentChain: [agentId, handoffDest],
1456
+ currentAgentId: transferDest,
1457
+ agentChain: [agentId, transferDest],
1462
1458
  pendingAgents: [],
1463
1459
  },
1464
1460
  }
@@ -1514,14 +1510,14 @@ export class MultiAgentGraph extends StandardGraph {
1514
1510
 
1515
1511
  return new Command({
1516
1512
  update: result,
1517
- goto: handoffDest,
1513
+ goto: transferDest,
1518
1514
  });
1519
1515
  } else {
1520
- /** No handoff - proceed with direct edges */
1516
+ /** No transfer - proceed with sequence edges */
1521
1517
  console.debug(
1522
- `[MultiAgentGraph] Command routing: "${agentId}" -> no handoff, following direct edges: [${Array.from(directDestinations).join(', ')}]`
1518
+ `[MultiAgentGraph] Command routing: "${agentId}" -> no transfer, following sequence edges: [${Array.from(sequenceDestinations).join(', ')}]`
1523
1519
  );
1524
- const directDests = Array.from(directDestinations);
1520
+ const directDests = Array.from(sequenceDestinations);
1525
1521
  if (directDests.length === 1) {
1526
1522
  return new Command({
1527
1523
  update: result,
@@ -1555,12 +1551,12 @@ export class MultiAgentGraph extends StandardGraph {
1555
1551
  }
1556
1552
 
1557
1553
  /**
1558
- * Add direct edges for automatic transitions
1554
+ * Add sequence edges for automatic transitions
1559
1555
  * Group edges by destination to handle fan-in scenarios
1560
1556
  */
1561
1557
  const edgesByDestination = new Map<string, t.GraphEdge[]>();
1562
1558
 
1563
- for (const edge of this.directEdges) {
1559
+ for (const edge of this.sequenceEdges) {
1564
1560
  const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];
1565
1561
  for (const destination of destinations) {
1566
1562
  if (!edgesByDestination.has(destination)) {
@@ -1659,18 +1655,18 @@ export class MultiAgentGraph extends StandardGraph {
1659
1655
  for (const edge of edges) {
1660
1656
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
1661
1657
  for (const source of sources) {
1662
- /** Check if this source node has both handoff and direct edges */
1663
- const sourceHandoffEdges = this.handoffEdges.filter((e) => {
1658
+ /** Check if this source node has both transfer and sequence edges */
1659
+ const sourceTransferEdges = this.transferEdges.filter((e) => {
1664
1660
  const eSources = Array.isArray(e.from) ? e.from : [e.from];
1665
1661
  return eSources.includes(source);
1666
1662
  });
1667
- const sourceDirectEdges = this.directEdges.filter((e) => {
1663
+ const sourceSequenceEdges = this.sequenceEdges.filter((e) => {
1668
1664
  const eSources = Array.isArray(e.from) ? e.from : [e.from];
1669
1665
  return eSources.includes(source);
1670
1666
  });
1671
1667
 
1672
1668
  /** Skip adding edge if source uses Command routing (has both types) */
1673
- if (sourceHandoffEdges.length > 0 && sourceDirectEdges.length > 0) {
1669
+ if (sourceTransferEdges.length > 0 && sourceSequenceEdges.length > 0) {
1674
1670
  continue;
1675
1671
  }
1676
1672