@illuma-ai/agents 1.1.14 → 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 (66) hide show
  1. package/dist/cjs/common/enum.cjs +14 -3
  2. package/dist/cjs/common/enum.cjs.map +1 -1
  3. package/dist/cjs/graphs/MultiAgentGraph.cjs +304 -106
  4. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  5. package/dist/cjs/main.cjs +2 -0
  6. package/dist/cjs/main.cjs.map +1 -1
  7. package/dist/cjs/types/graph.cjs.map +1 -1
  8. package/dist/esm/common/enum.mjs +12 -4
  9. package/dist/esm/common/enum.mjs.map +1 -1
  10. package/dist/esm/graphs/MultiAgentGraph.mjs +306 -108
  11. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  12. package/dist/esm/main.mjs +1 -1
  13. package/dist/esm/types/graph.mjs.map +1 -1
  14. package/dist/types/common/enum.d.ts +11 -3
  15. package/dist/types/graphs/MultiAgentGraph.d.ts +72 -18
  16. package/dist/types/types/graph.d.ts +17 -5
  17. package/package.json +1 -1
  18. package/src/common/__tests__/enum.test.ts +15 -7
  19. package/src/common/enum.ts +13 -3
  20. package/src/graphs/MultiAgentGraph.ts +385 -107
  21. package/src/graphs/__tests__/multi-agent-delegate.test.ts +208 -0
  22. package/src/graphs/__tests__/multi-agent-edges.test.ts +98 -61
  23. package/src/scripts/multi-agent-chain.js +1 -1
  24. package/src/scripts/multi-agent-chain.ts +1 -1
  25. package/src/scripts/multi-agent-document-review-chain.js +1 -1
  26. package/src/scripts/multi-agent-document-review-chain.ts +1 -1
  27. package/src/scripts/multi-agent-hybrid-flow.js +3 -3
  28. package/src/scripts/multi-agent-hybrid-flow.ts +3 -3
  29. package/src/scripts/multi-agent-parallel.js +2 -2
  30. package/src/scripts/multi-agent-parallel.ts +2 -2
  31. package/src/scripts/multi-agent-sequence.js +2 -2
  32. package/src/scripts/multi-agent-sequence.ts +2 -2
  33. package/src/scripts/multi-agent-supervisor.js +5 -5
  34. package/src/scripts/multi-agent-supervisor.ts +5 -5
  35. package/src/scripts/poc-multi-agent-comprehensive.ts +7 -7
  36. package/src/scripts/sequential-full-metadata-test.js +1 -1
  37. package/src/scripts/sequential-full-metadata-test.ts +1 -1
  38. package/src/scripts/test-custom-prompt-key.js +3 -3
  39. package/src/scripts/test-custom-prompt-key.ts +3 -3
  40. package/src/scripts/test-handoff-input.js +1 -1
  41. package/src/scripts/test-handoff-input.ts +1 -1
  42. package/src/scripts/test-handoff-preamble.js +1 -1
  43. package/src/scripts/test-handoff-preamble.ts +1 -1
  44. package/src/scripts/test-handoff-steering.js +3 -3
  45. package/src/scripts/test-handoff-steering.ts +3 -3
  46. package/src/scripts/test-multi-agent-list-handoff.js +1 -1
  47. package/src/scripts/test-multi-agent-list-handoff.ts +1 -1
  48. package/src/scripts/test-parallel-agent-labeling.js +2 -2
  49. package/src/scripts/test-parallel-agent-labeling.ts +2 -2
  50. package/src/scripts/test-parallel-handoffs.js +2 -2
  51. package/src/scripts/test-parallel-handoffs.ts +2 -2
  52. package/src/scripts/test-thinking-handoff-bedrock.js +1 -1
  53. package/src/scripts/test-thinking-handoff-bedrock.ts +1 -1
  54. package/src/scripts/test-thinking-handoff.js +1 -1
  55. package/src/scripts/test-thinking-handoff.ts +1 -1
  56. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js +1 -1
  57. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +1 -1
  58. package/src/scripts/test-tool-before-handoff-role-order.js +1 -1
  59. package/src/scripts/test-tool-before-handoff-role-order.ts +1 -1
  60. package/src/scripts/test-tools-before-handoff.js +1 -1
  61. package/src/scripts/test-tools-before-handoff.ts +1 -1
  62. package/src/specs/agent-handoffs-bedrock.integration.test.ts +6 -6
  63. package/src/specs/agent-handoffs.test.ts +35 -35
  64. package/src/specs/thinking-handoff.test.ts +9 -9
  65. package/src/tools/search/search.test.ts +173 -0
  66. package/src/types/graph.ts +17 -5
@@ -75,10 +75,12 @@ export declare enum Providers {
75
75
  MOONSHOT = "moonshot"
76
76
  }
77
77
  export declare enum EdgeType {
78
- /** Creates handoff tools for dynamic agent routing (default for single-to-single edges) */
78
+ /** True agent handoff parent calls child agent inline, gets result back, continues orchestrating */
79
79
  HANDOFF = "handoff",
80
- /** Creates direct edges for automatic sequential/parallel transitions */
81
- DIRECT = "direct"
80
+ /** One-way transfer parent exits, child takes over and responds directly to user */
81
+ TRANSFER = "transfer",
82
+ /** Fixed graph edges for automatic sequential/parallel transitions */
83
+ SEQUENCE = "sequence"
82
84
  }
83
85
  export declare enum GraphNodeKeys {
84
86
  TOOLS = "tools=",
@@ -136,6 +138,8 @@ export declare enum Constants {
136
138
  WEB_SEARCH = "web_search",
137
139
  CONTENT_AND_ARTIFACT = "content_and_artifact",
138
140
  LC_TRANSFER_TO_ = "lc_transfer_to_",
141
+ /** Prefix for handoff tool names: lc_handoff_to_{agentId} */
142
+ LC_HANDOFF_TO_ = "lc_handoff_to_",
139
143
  /** Tool name for the AskUser structured question tool */
140
144
  ASK_USER = "ask_user",
141
145
  /** Delimiter for MCP tools: toolName_mcp_serverName */
@@ -183,3 +187,7 @@ export declare enum MessageTypes {
183
187
  DEVELOPER = "developer",
184
188
  REMOVE = "remove"
185
189
  }
190
+ /** Default max characters for handoff results returned to parent (~8192 tokens at ~4 chars/token) */
191
+ export declare const DEFAULT_HANDOFF_MAX_RESULT_CHARS = 32768;
192
+ /** Default timeout for handoff sub-agent execution in milliseconds (5 minutes) */
193
+ export declare const HANDOFF_TIMEOUT_MS = 300000;
@@ -1,3 +1,4 @@
1
+ import type { BaseMessage } from '@langchain/core/messages';
1
2
  import type * as t from '@/types';
2
3
  import { StandardGraph } from './Graph';
3
4
  /**
@@ -5,20 +6,29 @@ import { StandardGraph } from './Graph';
5
6
  * with handoffs, fan-in/fan-out, and other composable patterns.
6
7
  *
7
8
  * Key behavior:
8
- * - Agents with ONLY handoff edges: Can dynamically route to any handoff destination
9
- * - Agents with ONLY direct edges: Always follow their direct edges
10
- * - Agents with BOTH: Use Command for exclusive routing (handoff OR direct, not both)
11
- * - If handoff occurs: Only the handoff destination executes
12
- * - If no handoff: Direct edges execute (potentially in parallel)
9
+ * - Agents with ONLY transfer edges: Can dynamically route to any transfer destination
10
+ * - Agents with ONLY sequence edges: Always follow their sequence edges
11
+ * - Agents with BOTH: Use Command for exclusive routing (transfer OR sequence, not both)
12
+ * - If transfer occurs: Only the transfer destination executes
13
+ * - If no transfer: Sequence edges execute (potentially in parallel)
13
14
  *
14
- * This enables the common pattern where an agent either delegates (handoff)
15
- * OR continues its workflow (direct edges), but not both simultaneously.
15
+ * This enables the common pattern where an agent either transfers (one-way)
16
+ * OR continues its workflow (sequence edges), but not both simultaneously.
16
17
  */
17
18
  export declare class MultiAgentGraph extends StandardGraph {
18
19
  private edges;
19
20
  private startingNodes;
20
- private directEdges;
21
+ private sequenceEdges;
22
+ private transferEdges;
21
23
  private handoffEdges;
24
+ /**
25
+ * Lazily populated registry of compiled subgraphs, keyed by agentId.
26
+ * Handoff tools are created in the constructor but reference subgraphs
27
+ * that are only created in createWorkflow(). This Map bridges that gap —
28
+ * tools capture the Map reference in their closure, and createWorkflow()
29
+ * populates it before any tool invocation occurs.
30
+ */
31
+ private subgraphRegistry;
22
32
  /**
23
33
  * Map of agentId to parallel group info.
24
34
  * Contains groupId (incrementing number reflecting execution order) for agents in parallel groups.
@@ -37,7 +47,7 @@ export declare class MultiAgentGraph extends StandardGraph {
37
47
  private lastActiveAgentId;
38
48
  constructor(input: t.MultiAgentGraphInput);
39
49
  /**
40
- * Categorize edges into handoff and direct types
50
+ * Categorize edges into handoff, transfer, and sequence types
41
51
  */
42
52
  private categorizeEdges;
43
53
  /**
@@ -81,23 +91,67 @@ export declare class MultiAgentGraph extends StandardGraph {
81
91
  */
82
92
  protected getParallelGroupIdForAgent(agentId: string): number | undefined;
83
93
  /**
84
- * Create handoff tools for agents based on handoff edges only
94
+ * Create transfer tools for agents based on transfer edges only.
95
+ * Transfer tools return Command for one-way routing — parent exits, child takes over.
85
96
  */
86
- private createHandoffTools;
97
+ private createTransferTools;
87
98
  /**
88
- * Create handoff tools for an edge (handles multiple destinations)
89
- * @param edge - The graph edge defining the handoff
90
- * @param sourceAgentId - The ID of the agent that will perform the handoff
99
+ * Create transfer tools for an edge (handles multiple destinations).
100
+ * Transfer tools return Command for one-way routing parent exits, child takes over.
101
+ * @param edge - The graph edge defining the transfer
102
+ * @param sourceAgentId - The ID of the agent that will perform the transfer
91
103
  * @param sourceAgentName - The human-readable name of the source agent
92
104
  */
93
- private createHandoffToolsForEdge;
105
+ private createTransferToolsForEdge;
94
106
  /**
95
- * Builds a meaningful default description for a handoff tool when no explicit
107
+ * Builds a meaningful default description for a transfer tool when no explicit
96
108
  * edge.description is provided. Uses the destination agent's name and description
97
109
  * so the LLM can make informed routing decisions.
98
110
  * @param destContext - AgentContext of the destination agent (may be undefined)
99
111
  * @param destinationId - Raw agent ID (fallback when context unavailable)
100
112
  */
113
+ private buildDefaultTransferDescription;
114
+ /**
115
+ * Create handoff tools for agents based on handoff edges.
116
+ * Handoff tools invoke child agent subgraphs inline and return the result
117
+ * as a string to the parent agent's context. Unlike transfer tools (which
118
+ * return Command for one-way routing), handoff tools execute the child,
119
+ * extract the final text, and return it within the parent's agent loop.
120
+ *
121
+ * This enables the supervisor pattern: parent calls child → gets result → thinks → calls another.
122
+ */
123
+ private createHandoffTools;
124
+ /**
125
+ * Create handoff tools for an edge (handles multiple destinations).
126
+ * Each handoff tool invokes the child agent's compiled subgraph inline,
127
+ * extracts the final AI message text, truncates it, and returns it as
128
+ * a string (which becomes a ToolMessage in the parent's context).
129
+ *
130
+ * @param edge - The graph edge defining the handoff
131
+ * @param sourceAgentId - The ID of the parent/supervisor agent
132
+ */
133
+ private createHandoffToolsForEdge;
134
+ /**
135
+ * Extract the final text result from a child agent's output messages.
136
+ * Walks backwards to find the last AIMessage with text content.
137
+ * Handles both string content and array content (multi-modal messages).
138
+ * @param messages - The child agent's output messages
139
+ * @param agentId - The child agent ID (for fallback message)
140
+ */
141
+ static extractHandoffResult(messages: BaseMessage[], agentId: string): string;
142
+ /**
143
+ * Truncate handoff result using head/tail strategy (60/40 split).
144
+ * Preserves the beginning (key findings) and end (conclusions).
145
+ * Matches the TaskTool.truncateResult pattern from Ranger.
146
+ * @param result - The full result text
147
+ * @param maxChars - Maximum allowed characters
148
+ */
149
+ static truncateHandoffResult(result: string, maxChars: number): string;
150
+ /**
151
+ * Build a meaningful default description for a handoff tool.
152
+ * @param destContext - AgentContext of the destination agent
153
+ * @param destinationId - Raw agent ID (fallback)
154
+ */
101
155
  private buildDefaultHandoffDescription;
102
156
  /**
103
157
  * Create a complete agent subgraph (similar to createReactAgent)
@@ -115,9 +169,9 @@ export declare class MultiAgentGraph extends StandardGraph {
115
169
  * @param agentId - The agent ID to check for handoff reception
116
170
  * @returns Object with filtered messages, extracted instructions, source agent, and parallel siblings
117
171
  */
118
- private processHandoffReception;
172
+ private processTransferReception;
119
173
  /**
120
- * Create the multi-agent workflow with dynamic handoffs
174
+ * Create the multi-agent workflow with handoffs, transfers, and sequences
121
175
  */
122
176
  createWorkflow(): t.CompiledMultiAgentWorkflow;
123
177
  }
@@ -220,14 +220,18 @@ export type GraphEdge = {
220
220
  description?: string;
221
221
  /** Can return boolean or specific destination(s) */
222
222
  condition?: (state: BaseGraphState) => boolean | string | string[];
223
- /** EdgeType.HANDOFF creates tools for dynamic routing, EdgeType.DIRECT creates direct edges with parallel execution */
223
+ /**
224
+ * EdgeType.HANDOFF — true agent handoff, parent calls child inline and gets result back.
225
+ * EdgeType.TRANSFER — one-way transfer, parent exits and child takes over.
226
+ * EdgeType.SEQUENCE — fixed graph edges for sequential/parallel transitions.
227
+ */
224
228
  edgeType?: import('@/common').EdgeType;
225
229
  /**
226
- * For direct edges: Optional prompt to add when transitioning through this edge.
230
+ * For sequence edges: Optional prompt to add when transitioning through this edge.
227
231
  * String prompts can include variables like {results} which will be replaced with
228
232
  * messages from startIndex onwards. When {results} is used, excludeResults defaults to true.
229
233
  *
230
- * For handoff edges: Description for the input parameter that the handoff tool accepts,
234
+ * For transfer edges: Description for the input parameter that the transfer tool accepts,
231
235
  * allowing the supervisor to pass specific instructions/context to the transferred agent.
232
236
  */
233
237
  prompt?: string | ((messages: BaseMessage[], runStartIndex: number) => string | Promise<string> | undefined);
@@ -237,11 +241,19 @@ export type GraphEdge = {
237
241
  */
238
242
  excludeResults?: boolean;
239
243
  /**
240
- * For handoff edges: Customizes the parameter name for the handoff input.
244
+ * For transfer edges: Customizes the parameter name for the transfer input.
241
245
  * Defaults to "instructions" if not specified.
242
- * Only applies when prompt is provided for handoff edges.
246
+ * Only applies when prompt is provided for transfer edges.
247
+ *
248
+ * For handoff edges: Customizes the parameter name for the handoff instruction input.
243
249
  */
244
250
  promptKey?: string;
251
+ /**
252
+ * For handoff edges: Maximum characters for the result returned to the parent.
253
+ * Uses head/tail truncation (60/40 split) to preserve key findings and conclusions.
254
+ * Defaults to DEFAULT_HANDOFF_MAX_RESULT_CHARS (32768 chars, ~8192 tokens).
255
+ */
256
+ maxResultChars?: number;
245
257
  };
246
258
  export type MultiAgentGraphInput = StandardGraphInput & {
247
259
  edges: GraphEdge[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@illuma-ai/agents",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -18,18 +18,22 @@ import {
18
18
  } from '@/common';
19
19
 
20
20
  describe('EdgeType enum', () => {
21
- it('has correct HANDOFF value', () => {
21
+ it('has correct HANDOFF value (supervisor pattern)', () => {
22
22
  expect(EdgeType.HANDOFF).toBe('handoff');
23
23
  });
24
24
 
25
- it('has correct DIRECT value', () => {
26
- expect(EdgeType.DIRECT).toBe('direct');
25
+ it('has correct TRANSFER value (one-way fire-and-forget)', () => {
26
+ expect(EdgeType.TRANSFER).toBe('transfer');
27
27
  });
28
28
 
29
- it('only has two members', () => {
29
+ it('has correct SEQUENCE value (fixed graph edges)', () => {
30
+ expect(EdgeType.SEQUENCE).toBe('sequence');
31
+ });
32
+
33
+ it('has three members: handoff, transfer, sequence', () => {
30
34
  const values = Object.values(EdgeType);
31
- expect(values).toHaveLength(2);
32
- expect(values).toEqual(expect.arrayContaining(['handoff', 'direct']));
35
+ expect(values).toHaveLength(3);
36
+ expect(values).toEqual(expect.arrayContaining(['handoff', 'transfer', 'sequence']));
33
37
  });
34
38
  });
35
39
 
@@ -42,10 +46,14 @@ describe('Constants enum', () => {
42
46
  expect(Constants.EXECUTE_CODE).toBe('execute_code');
43
47
  });
44
48
 
45
- it('has LC_TRANSFER_TO_ prefix for LangChain handoff tools', () => {
49
+ it('has LC_TRANSFER_TO_ prefix for LangChain transfer tools', () => {
46
50
  expect(Constants.LC_TRANSFER_TO_).toBe('lc_transfer_to_');
47
51
  });
48
52
 
53
+ it('has LC_HANDOFF_TO_ prefix for LangChain handoff tools', () => {
54
+ expect(Constants.LC_HANDOFF_TO_).toBe('lc_handoff_to_');
55
+ });
56
+
49
57
  it('has MCP_DELIMITER for MCP tool naming', () => {
50
58
  expect(Constants.MCP_DELIMITER).toBe('_mcp_');
51
59
  });
@@ -96,10 +96,12 @@ export enum Providers {
96
96
  }
97
97
 
98
98
  export enum EdgeType {
99
- /** Creates handoff tools for dynamic agent routing (default for single-to-single edges) */
99
+ /** True agent handoff parent calls child agent inline, gets result back, continues orchestrating */
100
100
  HANDOFF = 'handoff',
101
- /** Creates direct edges for automatic sequential/parallel transitions */
102
- DIRECT = 'direct',
101
+ /** One-way transfer parent exits, child takes over and responds directly to user */
102
+ TRANSFER = 'transfer',
103
+ /** Fixed graph edges for automatic sequential/parallel transitions */
104
+ SEQUENCE = 'sequence',
103
105
  }
104
106
 
105
107
  export enum GraphNodeKeys {
@@ -182,6 +184,8 @@ export enum Constants {
182
184
  WEB_SEARCH = 'web_search',
183
185
  CONTENT_AND_ARTIFACT = 'content_and_artifact',
184
186
  LC_TRANSFER_TO_ = 'lc_transfer_to_',
187
+ /** Prefix for handoff tool names: lc_handoff_to_{agentId} */
188
+ LC_HANDOFF_TO_ = 'lc_handoff_to_',
185
189
  /** Tool name for the AskUser structured question tool */
186
190
  ASK_USER = 'ask_user',
187
191
  /** Delimiter for MCP tools: toolName_mcp_serverName */
@@ -233,3 +237,9 @@ export enum MessageTypes {
233
237
  DEVELOPER = 'developer',
234
238
  REMOVE = 'remove',
235
239
  }
240
+
241
+ /** Default max characters for handoff results returned to parent (~8192 tokens at ~4 chars/token) */
242
+ export const DEFAULT_HANDOFF_MAX_RESULT_CHARS = 32768;
243
+
244
+ /** Default timeout for handoff sub-agent execution in milliseconds (5 minutes) */
245
+ export const HANDOFF_TIMEOUT_MS = 300_000;