@librechat/agents 3.0.0-rc1 → 3.0.0-rc2

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.
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { tool } from '@langchain/core/tools';
3
- import { ToolMessage, HumanMessage } from '@langchain/core/messages';
3
+ import { ToolMessage, getBufferString, HumanMessage } from '@langchain/core/messages';
4
+ import { ChatPromptTemplate } from '@langchain/core/prompts';
4
5
  import { getCurrentTaskInput, Command, Annotation, messagesStateReducer, StateGraph, END, START } from '@langchain/langgraph';
5
6
  import { StandardGraph } from './Graph.mjs';
6
7
 
@@ -115,19 +116,23 @@ class MultiAgentGraph extends StandardGraph {
115
116
  createHandoffToolsForEdge(edge) {
116
117
  const tools = [];
117
118
  const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];
118
- // If there's a condition, create a single conditional handoff tool
119
+ /** If there's a condition, create a single conditional handoff tool */
119
120
  if (edge.condition != null) {
120
121
  const toolName = 'conditional_transfer';
121
122
  const toolDescription = edge.description ?? 'Conditionally transfer control based on state';
122
- tools.push(tool(async (_, config) => {
123
+ /** Check if we have a prompt for handoff input */
124
+ const hasHandoffInput = edge.prompt != null && typeof edge.prompt === 'string';
125
+ const handoffInputDescription = hasHandoffInput ? edge.prompt : undefined;
126
+ const promptKey = edge.promptKey ?? 'instructions';
127
+ tools.push(tool(async (input, config) => {
123
128
  const state = getCurrentTaskInput();
124
129
  const toolCallId = config?.toolCall?.id ??
125
130
  'unknown';
126
- // Evaluate condition
131
+ /** Evaluated condition */
127
132
  const result = edge.condition(state);
128
133
  let destination;
129
134
  if (typeof result === 'boolean') {
130
- // If true, use first destination; if false, don't transfer
135
+ /** If true, use first destination; if false, don't transfer */
131
136
  if (!result)
132
137
  return null;
133
138
  destination = destinations[0];
@@ -136,11 +141,17 @@ class MultiAgentGraph extends StandardGraph {
136
141
  destination = result;
137
142
  }
138
143
  else {
139
- // Array of destinations - for now, use the first
144
+ /** Array of destinations - for now, use the first */
140
145
  destination = Array.isArray(result) ? result[0] : destinations[0];
141
146
  }
147
+ let content = `Conditionally transferred to ${destination}`;
148
+ if (hasHandoffInput &&
149
+ promptKey in input &&
150
+ input[promptKey] != null) {
151
+ content += `\n\n${promptKey.charAt(0).toUpperCase() + promptKey.slice(1)}: ${input[promptKey]}`;
152
+ }
142
153
  const toolMessage = new ToolMessage({
143
- content: `Conditionally transferred to ${destination}`,
154
+ content,
144
155
  name: toolName,
145
156
  tool_call_id: toolCallId,
146
157
  });
@@ -151,20 +162,39 @@ class MultiAgentGraph extends StandardGraph {
151
162
  });
152
163
  }, {
153
164
  name: toolName,
154
- schema: z.object({}),
165
+ schema: hasHandoffInput
166
+ ? z.object({
167
+ [promptKey]: z
168
+ .string()
169
+ .optional()
170
+ .describe(handoffInputDescription),
171
+ })
172
+ : z.object({}),
155
173
  description: toolDescription,
156
174
  }));
157
175
  }
158
176
  else {
159
- // Create individual tools for each destination
177
+ /** Create individual tools for each destination */
160
178
  for (const destination of destinations) {
161
179
  const toolName = `transfer_to_${destination}`;
162
180
  const toolDescription = edge.description ?? `Transfer control to agent '${destination}'`;
163
- tools.push(tool(async (_, config) => {
181
+ /** Check if we have a prompt for handoff input */
182
+ const hasHandoffInput = edge.prompt != null && typeof edge.prompt === 'string';
183
+ const handoffInputDescription = hasHandoffInput
184
+ ? edge.prompt
185
+ : undefined;
186
+ const promptKey = edge.promptKey ?? 'instructions';
187
+ tools.push(tool(async (input, config) => {
164
188
  const toolCallId = config?.toolCall?.id ??
165
189
  'unknown';
190
+ let content = `Successfully transferred to ${destination}`;
191
+ if (hasHandoffInput &&
192
+ promptKey in input &&
193
+ input[promptKey] != null) {
194
+ content += `\n\n${promptKey.charAt(0).toUpperCase() + promptKey.slice(1)}: ${input[promptKey]}`;
195
+ }
166
196
  const toolMessage = new ToolMessage({
167
- content: `Successfully transferred to ${destination}`,
197
+ content,
168
198
  name: toolName,
169
199
  tool_call_id: toolCallId,
170
200
  });
@@ -176,7 +206,14 @@ class MultiAgentGraph extends StandardGraph {
176
206
  });
177
207
  }, {
178
208
  name: toolName,
179
- schema: z.object({}),
209
+ schema: hasHandoffInput
210
+ ? z.object({
211
+ [promptKey]: z
212
+ .string()
213
+ .optional()
214
+ .describe(handoffInputDescription),
215
+ })
216
+ : z.object({}),
180
217
  description: toolDescription,
181
218
  }));
182
219
  }
@@ -187,7 +224,7 @@ class MultiAgentGraph extends StandardGraph {
187
224
  * Create a complete agent subgraph (similar to createReactAgent)
188
225
  */
189
226
  createAgentSubgraph(agentId) {
190
- // This is essentially the same as createAgentNode from StandardGraph
227
+ /** This is essentially the same as `createAgentNode` from `StandardGraph` */
191
228
  return this.createAgentNode(agentId);
192
229
  }
193
230
  /**
@@ -206,6 +243,12 @@ class MultiAgentGraph extends StandardGraph {
206
243
  },
207
244
  default: () => [],
208
245
  }),
246
+ /** Channel for passing filtered messages to agents when excludeResults is true */
247
+ agentMessages: Annotation({
248
+ /** Replaces state entirely */
249
+ reducer: (a, b) => b,
250
+ default: () => [],
251
+ }),
209
252
  });
210
253
  const builder = new StateGraph(StateAnnotation);
211
254
  // Add all agents as complete subgraphs
@@ -229,16 +272,36 @@ class MultiAgentGraph extends StandardGraph {
229
272
  dests.forEach((dest) => directDestinations.add(dest));
230
273
  }
231
274
  }
232
- // If agent has handoff destinations, add END to possible ends
233
- // If agent only has direct destinations, it naturally ends without explicit END
275
+ /** If agent has handoff destinations, add END to possible ends
276
+ * If agent only has direct destinations, it naturally ends without explicit END
277
+ */
234
278
  const destinations = new Set([...handoffDestinations]);
235
279
  if (handoffDestinations.size > 0 || directDestinations.size === 0) {
236
280
  destinations.add(END);
237
281
  }
238
- // Create the agent subgraph (includes agent + tools)
282
+ /** Agent subgraph (includes agent + tools) */
239
283
  const agentSubgraph = this.createAgentSubgraph(agentId);
240
- // Add the agent as a node with its possible destinations
241
- builder.addNode(agentId, agentSubgraph, {
284
+ /** Wrapper function that handles agentMessages channel */
285
+ const agentWrapper = async (state) => {
286
+ if (state.agentMessages != null && state.agentMessages.length > 0) {
287
+ /** Temporary state with messages replaced by `agentMessages` */
288
+ const transformedState = {
289
+ ...state,
290
+ messages: state.agentMessages,
291
+ };
292
+ const result = await agentSubgraph.invoke(transformedState);
293
+ return {
294
+ ...result,
295
+ /** Clear agentMessages for next agent */
296
+ agentMessages: [],
297
+ };
298
+ }
299
+ else {
300
+ return await agentSubgraph.invoke(state);
301
+ }
302
+ };
303
+ /** Wrapped agent as a node with its possible destinations */
304
+ builder.addNode(agentId, agentWrapper, {
242
305
  ends: Array.from(destinations),
243
306
  });
244
307
  }
@@ -248,7 +311,8 @@ class MultiAgentGraph extends StandardGraph {
248
311
  /** @ts-ignore */
249
312
  builder.addEdge(START, startNode);
250
313
  }
251
- /** Add direct edges for automatic transitions
314
+ /**
315
+ * Add direct edges for automatic transitions
252
316
  * Group edges by destination to handle fan-in scenarios
253
317
  */
254
318
  const edgesByDestination = new Map();
@@ -263,30 +327,66 @@ class MultiAgentGraph extends StandardGraph {
263
327
  }
264
328
  for (const [destination, edges] of edgesByDestination) {
265
329
  /** Checks if this is a fan-in scenario with prompt instructions */
266
- const edgesWithPrompt = edges.filter((edge) => edge.promptInstructions != null && edge.promptInstructions !== '');
330
+ const edgesWithPrompt = edges.filter((edge) => edge.prompt != null && edge.prompt !== '');
267
331
  if (edgesWithPrompt.length > 0) {
268
- // Fan-in with prompt: create a single wrapper node for this destination
332
+ /**
333
+ * Single wrapper node for destination (Fan-in with prompt)
334
+ */
269
335
  const wrapperNodeId = `fan_in_${destination}_prompt`;
270
- // Use the first edge's prompt instructions (they should all be the same for fan-in)
271
- const promptInstructions = edgesWithPrompt[0].promptInstructions;
336
+ /**
337
+ * First edge's `prompt`
338
+ * (they should all be the same for fan-in)
339
+ */
340
+ const prompt = edgesWithPrompt[0].prompt;
341
+ /**
342
+ * First edge's `excludeResults` flag
343
+ * (they should all be the same for fan-in)
344
+ */
345
+ const excludeResults = edgesWithPrompt[0].excludeResults;
272
346
  builder.addNode(wrapperNodeId, async (state) => {
273
347
  let promptText;
274
- if (typeof promptInstructions === 'function') {
275
- promptText = promptInstructions(state.messages);
348
+ let effectiveExcludeResults = excludeResults;
349
+ if (typeof prompt === 'function') {
350
+ promptText = prompt(state.messages, this.startIndex);
276
351
  }
277
- else {
278
- promptText = promptInstructions;
352
+ else if (prompt != null) {
353
+ if (prompt.includes('{results}')) {
354
+ const resultsMessages = state.messages.slice(this.startIndex);
355
+ const resultsString = getBufferString(resultsMessages);
356
+ const promptTemplate = ChatPromptTemplate.fromTemplate(prompt);
357
+ const formattedPromptValue = await promptTemplate.invoke({
358
+ results: resultsString,
359
+ });
360
+ promptText = formattedPromptValue.messages[0].content.toString();
361
+ effectiveExcludeResults =
362
+ excludeResults !== false && promptText !== '';
363
+ }
364
+ else {
365
+ promptText = prompt;
366
+ }
279
367
  }
280
368
  if (promptText != null && promptText !== '') {
281
- // Return state with the prompt message added
369
+ if (effectiveExcludeResults == null ||
370
+ effectiveExcludeResults === false) {
371
+ return {
372
+ messages: [new HumanMessage(promptText)],
373
+ };
374
+ }
375
+ /** When `excludeResults` is true, use agentMessages channel
376
+ * to pass filtered messages + prompt to the destination agent
377
+ */
378
+ const filteredMessages = state.messages.slice(0, this.startIndex);
282
379
  return {
283
- messages: [...state.messages, new HumanMessage(promptText)],
380
+ messages: [new HumanMessage(promptText)],
381
+ agentMessages: messagesStateReducer(filteredMessages, [
382
+ new HumanMessage(promptText),
383
+ ]),
284
384
  };
285
385
  }
286
- // No prompt needed, return empty update
386
+ /** No prompt needed, return empty update */
287
387
  return {};
288
388
  });
289
- // Add edges from all sources to the wrapper, then wrapper to destination
389
+ /** Add edges from all sources to the wrapper, then wrapper to destination */
290
390
  for (const edge of edges) {
291
391
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
292
392
  for (const source of sources) {
@@ -295,13 +395,13 @@ class MultiAgentGraph extends StandardGraph {
295
395
  builder.addEdge(source, wrapperNodeId);
296
396
  }
297
397
  }
298
- // Single edge from wrapper to destination
398
+ /** Single edge from wrapper to destination */
299
399
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
300
400
  /** @ts-ignore */
301
401
  builder.addEdge(wrapperNodeId, destination);
302
402
  }
303
403
  else {
304
- // No prompt instructions, add direct edges
404
+ /** No prompt instructions, add direct edges */
305
405
  for (const edge of edges) {
306
406
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
307
407
  for (const source of sources) {
@@ -1 +1 @@
1
- {"version":3,"file":"MultiAgentGraph.mjs","sources":["../../../src/graphs/MultiAgentGraph.ts"],"sourcesContent":["import { z } from 'zod';\nimport { tool } from '@langchain/core/tools';\nimport { ToolMessage, HumanMessage } from '@langchain/core/messages';\nimport {\n END,\n START,\n Command,\n StateGraph,\n Annotation,\n getCurrentTaskInput,\n messagesStateReducer,\n} from '@langchain/langgraph';\nimport type { ToolRunnableConfig } from '@langchain/core/tools';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type * as t from '@/types';\nimport { StandardGraph } from './Graph';\n\n/**\n * MultiAgentGraph extends StandardGraph to support dynamic multi-agent workflows\n * with handoffs, fan-in/fan-out, and other composable patterns\n */\nexport class MultiAgentGraph extends StandardGraph {\n private edges: t.GraphEdge[];\n private startingNodes: Set<string> = new Set();\n private directEdges: t.GraphEdge[] = [];\n private handoffEdges: t.GraphEdge[] = [];\n\n constructor(input: t.MultiAgentGraphInput) {\n super(input);\n this.edges = input.edges;\n this.categorizeEdges();\n this.analyzeGraph();\n this.createHandoffTools();\n }\n\n /**\n * Categorize edges into handoff and direct types\n */\n private categorizeEdges(): void {\n for (const edge of this.edges) {\n // Default behavior: edges with conditions or explicit 'handoff' type are handoff edges\n // Edges with explicit 'direct' type or multi-destination without conditions are direct edges\n if (edge.edgeType === 'direct') {\n this.directEdges.push(edge);\n } else if (edge.edgeType === 'handoff' || edge.condition != null) {\n this.handoffEdges.push(edge);\n } else {\n // Default: single-to-single edges are handoff, single-to-multiple are direct\n const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n\n if (sources.length === 1 && destinations.length > 1) {\n // Fan-out pattern defaults to direct\n this.directEdges.push(edge);\n } else {\n // Everything else defaults to handoff\n this.handoffEdges.push(edge);\n }\n }\n }\n }\n\n /**\n * Analyze graph structure to determine starting nodes and connections\n */\n private analyzeGraph(): void {\n const hasIncomingEdge = new Set<string>();\n\n // Track all nodes that have incoming edges\n for (const edge of this.edges) {\n const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];\n destinations.forEach((dest) => hasIncomingEdge.add(dest));\n }\n\n // Starting nodes are those without incoming edges\n for (const agentId of this.agentContexts.keys()) {\n if (!hasIncomingEdge.has(agentId)) {\n this.startingNodes.add(agentId);\n }\n }\n\n // If no starting nodes found, use the first agent\n if (this.startingNodes.size === 0 && this.agentContexts.size > 0) {\n this.startingNodes.add(this.agentContexts.keys().next().value!);\n }\n }\n\n /**\n * Create handoff tools for agents based on handoff edges only\n */\n private createHandoffTools(): void {\n // Group handoff edges by source agent(s)\n const handoffsByAgent = new Map<string, t.GraphEdge[]>();\n\n // Only process handoff edges for tool creation\n for (const edge of this.handoffEdges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n sources.forEach((source) => {\n if (!handoffsByAgent.has(source)) {\n handoffsByAgent.set(source, []);\n }\n handoffsByAgent.get(source)!.push(edge);\n });\n }\n\n // Create handoff tools for each agent\n for (const [agentId, edges] of handoffsByAgent) {\n const agentContext = this.agentContexts.get(agentId);\n if (!agentContext) continue;\n\n // Create handoff tools for this agent's outgoing edges\n const handoffTools: t.GenericTool[] = [];\n for (const edge of edges) {\n handoffTools.push(...this.createHandoffToolsForEdge(edge));\n }\n\n // Add handoff tools to the agent's existing tools\n if (!agentContext.tools) {\n agentContext.tools = [];\n }\n agentContext.tools.push(...handoffTools);\n\n // Update tool map\n for (const tool of handoffTools) {\n if (!agentContext.toolMap) {\n agentContext.toolMap = new Map();\n }\n agentContext.toolMap.set(tool.name, tool);\n }\n }\n }\n\n /**\n * Create handoff tools for an edge (handles multiple destinations)\n */\n private createHandoffToolsForEdge(edge: t.GraphEdge): t.GenericTool[] {\n const tools: t.GenericTool[] = [];\n const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];\n\n // If there's a condition, create a single conditional handoff tool\n if (edge.condition != null) {\n const toolName = 'conditional_transfer';\n const toolDescription =\n edge.description ?? 'Conditionally transfer control based on state';\n\n tools.push(\n tool(\n async (_, config) => {\n const state = getCurrentTaskInput() as t.BaseGraphState;\n const toolCallId =\n (config as ToolRunnableConfig | undefined)?.toolCall?.id ??\n 'unknown';\n\n // Evaluate condition\n const result = edge.condition!(state);\n let destination: string;\n\n if (typeof result === 'boolean') {\n // If true, use first destination; if false, don't transfer\n if (!result) return null;\n destination = destinations[0];\n } else if (typeof result === 'string') {\n destination = result;\n } else {\n // Array of destinations - for now, use the first\n destination = Array.isArray(result) ? result[0] : destinations[0];\n }\n\n const toolMessage = new ToolMessage({\n content: `Conditionally transferred to ${destination}`,\n name: toolName,\n tool_call_id: toolCallId,\n });\n\n return new Command({\n goto: destination,\n update: { messages: state.messages.concat(toolMessage) },\n graph: Command.PARENT,\n });\n },\n {\n name: toolName,\n schema: z.object({}),\n description: toolDescription,\n }\n )\n );\n } else {\n // Create individual tools for each destination\n for (const destination of destinations) {\n const toolName = `transfer_to_${destination}`;\n const toolDescription =\n edge.description ?? `Transfer control to agent '${destination}'`;\n\n tools.push(\n tool(\n async (_, config) => {\n const toolCallId =\n (config as ToolRunnableConfig | undefined)?.toolCall?.id ??\n 'unknown';\n const toolMessage = new ToolMessage({\n content: `Successfully transferred to ${destination}`,\n name: toolName,\n tool_call_id: toolCallId,\n });\n\n const state = getCurrentTaskInput() as t.BaseGraphState;\n\n return new Command({\n goto: destination,\n update: { messages: state.messages.concat(toolMessage) },\n graph: Command.PARENT,\n });\n },\n {\n name: toolName,\n schema: z.object({}),\n description: toolDescription,\n }\n )\n );\n }\n }\n\n return tools;\n }\n\n /**\n * Create a complete agent subgraph (similar to createReactAgent)\n */\n private createAgentSubgraph(agentId: string): t.CompiledAgentWorfklow {\n // This is essentially the same as createAgentNode from StandardGraph\n return this.createAgentNode(agentId);\n }\n\n /**\n * Create the multi-agent workflow with dynamic handoffs\n */\n override createWorkflow(): t.CompiledStateWorkflow {\n const StateAnnotation = Annotation.Root({\n messages: Annotation<BaseMessage[]>({\n reducer: (a, b) => {\n if (!a.length) {\n this.startIndex = a.length + b.length;\n }\n const result = messagesStateReducer(a, b);\n this.messages = result;\n return result;\n },\n default: () => [],\n }),\n });\n\n const builder = new StateGraph(StateAnnotation);\n\n // Add all agents as complete subgraphs\n for (const [agentId] of this.agentContexts) {\n // Get all possible destinations for this agent\n const handoffDestinations = new Set<string>();\n const directDestinations = new Set<string>();\n\n // Check handoff edges for destinations\n for (const edge of this.handoffEdges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n if (sources.includes(agentId) === true) {\n const dests = Array.isArray(edge.to) ? edge.to : [edge.to];\n dests.forEach((dest) => handoffDestinations.add(dest));\n }\n }\n\n // Check direct edges for destinations\n for (const edge of this.directEdges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n if (sources.includes(agentId) === true) {\n const dests = Array.isArray(edge.to) ? edge.to : [edge.to];\n dests.forEach((dest) => directDestinations.add(dest));\n }\n }\n\n // If agent has handoff destinations, add END to possible ends\n // If agent only has direct destinations, it naturally ends without explicit END\n const destinations = new Set([...handoffDestinations]);\n if (handoffDestinations.size > 0 || directDestinations.size === 0) {\n destinations.add(END);\n }\n\n // Create the agent subgraph (includes agent + tools)\n const agentSubgraph = this.createAgentSubgraph(agentId);\n\n // Add the agent as a node with its possible destinations\n builder.addNode(agentId, agentSubgraph, {\n ends: Array.from(destinations),\n });\n }\n\n // Add starting edges for all starting nodes\n for (const startNode of this.startingNodes) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n /** @ts-ignore */\n builder.addEdge(START, startNode);\n }\n\n /** Add direct edges for automatic transitions\n * Group edges by destination to handle fan-in scenarios\n */\n const edgesByDestination = new Map<string, t.GraphEdge[]>();\n\n for (const edge of this.directEdges) {\n const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];\n for (const destination of destinations) {\n if (!edgesByDestination.has(destination)) {\n edgesByDestination.set(destination, []);\n }\n edgesByDestination.get(destination)!.push(edge);\n }\n }\n\n for (const [destination, edges] of edgesByDestination) {\n /** Checks if this is a fan-in scenario with prompt instructions */\n const edgesWithPrompt = edges.filter(\n (edge) =>\n edge.promptInstructions != null && edge.promptInstructions !== ''\n );\n\n if (edgesWithPrompt.length > 0) {\n // Fan-in with prompt: create a single wrapper node for this destination\n const wrapperNodeId = `fan_in_${destination}_prompt`;\n\n // Use the first edge's prompt instructions (they should all be the same for fan-in)\n const promptInstructions = edgesWithPrompt[0].promptInstructions;\n\n builder.addNode(wrapperNodeId, async (state: t.BaseGraphState) => {\n let promptText: string | undefined;\n\n if (typeof promptInstructions === 'function') {\n promptText = promptInstructions(state.messages);\n } else {\n promptText = promptInstructions;\n }\n\n if (promptText != null && promptText !== '') {\n // Return state with the prompt message added\n return {\n messages: [...state.messages, new HumanMessage(promptText)],\n };\n }\n\n // No prompt needed, return empty update\n return {};\n });\n\n // Add edges from all sources to the wrapper, then wrapper to destination\n for (const edge of edges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n for (const source of sources) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n /** @ts-ignore */\n builder.addEdge(source, wrapperNodeId);\n }\n }\n\n // Single edge from wrapper to destination\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n /** @ts-ignore */\n builder.addEdge(wrapperNodeId, destination);\n } else {\n // No prompt instructions, add direct edges\n for (const edge of edges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n for (const source of sources) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n /** @ts-ignore */\n builder.addEdge(source, destination);\n }\n }\n }\n }\n\n return builder.compile(this.compileOptions as unknown as never);\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MultiAgentGraph.mjs","sources":["../../../src/graphs/MultiAgentGraph.ts"],"sourcesContent":["import { z } from 'zod';\nimport { tool } from '@langchain/core/tools';\nimport {\n ToolMessage,\n HumanMessage,\n getBufferString,\n} from '@langchain/core/messages';\nimport { ChatPromptTemplate } from '@langchain/core/prompts';\nimport {\n END,\n START,\n Command,\n StateGraph,\n Annotation,\n getCurrentTaskInput,\n messagesStateReducer,\n} from '@langchain/langgraph';\nimport type { ToolRunnableConfig } from '@langchain/core/tools';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type * as t from '@/types';\nimport { StandardGraph } from './Graph';\n\n/**\n * MultiAgentGraph extends StandardGraph to support dynamic multi-agent workflows\n * with handoffs, fan-in/fan-out, and other composable patterns\n */\nexport class MultiAgentGraph extends StandardGraph {\n private edges: t.GraphEdge[];\n private startingNodes: Set<string> = new Set();\n private directEdges: t.GraphEdge[] = [];\n private handoffEdges: t.GraphEdge[] = [];\n\n constructor(input: t.MultiAgentGraphInput) {\n super(input);\n this.edges = input.edges;\n this.categorizeEdges();\n this.analyzeGraph();\n this.createHandoffTools();\n }\n\n /**\n * Categorize edges into handoff and direct types\n */\n private categorizeEdges(): void {\n for (const edge of this.edges) {\n // Default behavior: edges with conditions or explicit 'handoff' type are handoff edges\n // Edges with explicit 'direct' type or multi-destination without conditions are direct edges\n if (edge.edgeType === 'direct') {\n this.directEdges.push(edge);\n } else if (edge.edgeType === 'handoff' || edge.condition != null) {\n this.handoffEdges.push(edge);\n } else {\n // Default: single-to-single edges are handoff, single-to-multiple are direct\n const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n\n if (sources.length === 1 && destinations.length > 1) {\n // Fan-out pattern defaults to direct\n this.directEdges.push(edge);\n } else {\n // Everything else defaults to handoff\n this.handoffEdges.push(edge);\n }\n }\n }\n }\n\n /**\n * Analyze graph structure to determine starting nodes and connections\n */\n private analyzeGraph(): void {\n const hasIncomingEdge = new Set<string>();\n\n // Track all nodes that have incoming edges\n for (const edge of this.edges) {\n const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];\n destinations.forEach((dest) => hasIncomingEdge.add(dest));\n }\n\n // Starting nodes are those without incoming edges\n for (const agentId of this.agentContexts.keys()) {\n if (!hasIncomingEdge.has(agentId)) {\n this.startingNodes.add(agentId);\n }\n }\n\n // If no starting nodes found, use the first agent\n if (this.startingNodes.size === 0 && this.agentContexts.size > 0) {\n this.startingNodes.add(this.agentContexts.keys().next().value!);\n }\n }\n\n /**\n * Create handoff tools for agents based on handoff edges only\n */\n private createHandoffTools(): void {\n // Group handoff edges by source agent(s)\n const handoffsByAgent = new Map<string, t.GraphEdge[]>();\n\n // Only process handoff edges for tool creation\n for (const edge of this.handoffEdges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n sources.forEach((source) => {\n if (!handoffsByAgent.has(source)) {\n handoffsByAgent.set(source, []);\n }\n handoffsByAgent.get(source)!.push(edge);\n });\n }\n\n // Create handoff tools for each agent\n for (const [agentId, edges] of handoffsByAgent) {\n const agentContext = this.agentContexts.get(agentId);\n if (!agentContext) continue;\n\n // Create handoff tools for this agent's outgoing edges\n const handoffTools: t.GenericTool[] = [];\n for (const edge of edges) {\n handoffTools.push(...this.createHandoffToolsForEdge(edge));\n }\n\n // Add handoff tools to the agent's existing tools\n if (!agentContext.tools) {\n agentContext.tools = [];\n }\n agentContext.tools.push(...handoffTools);\n\n // Update tool map\n for (const tool of handoffTools) {\n if (!agentContext.toolMap) {\n agentContext.toolMap = new Map();\n }\n agentContext.toolMap.set(tool.name, tool);\n }\n }\n }\n\n /**\n * Create handoff tools for an edge (handles multiple destinations)\n */\n private createHandoffToolsForEdge(edge: t.GraphEdge): t.GenericTool[] {\n const tools: t.GenericTool[] = [];\n const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];\n\n /** If there's a condition, create a single conditional handoff tool */\n if (edge.condition != null) {\n const toolName = 'conditional_transfer';\n const toolDescription =\n edge.description ?? 'Conditionally transfer control based on state';\n\n /** Check if we have a prompt for handoff input */\n const hasHandoffInput =\n edge.prompt != null && typeof edge.prompt === 'string';\n const handoffInputDescription = hasHandoffInput ? edge.prompt : undefined;\n const promptKey = edge.promptKey ?? 'instructions';\n\n tools.push(\n tool(\n async (input: Record<string, unknown>, config) => {\n const state = getCurrentTaskInput() as t.BaseGraphState;\n const toolCallId =\n (config as ToolRunnableConfig | undefined)?.toolCall?.id ??\n 'unknown';\n\n /** Evaluated condition */\n const result = edge.condition!(state);\n let destination: string;\n\n if (typeof result === 'boolean') {\n /** If true, use first destination; if false, don't transfer */\n if (!result) return null;\n destination = destinations[0];\n } else if (typeof result === 'string') {\n destination = result;\n } else {\n /** Array of destinations - for now, use the first */\n destination = Array.isArray(result) ? result[0] : destinations[0];\n }\n\n let content = `Conditionally transferred to ${destination}`;\n if (\n hasHandoffInput &&\n promptKey in input &&\n input[promptKey] != null\n ) {\n content += `\\n\\n${promptKey.charAt(0).toUpperCase() + promptKey.slice(1)}: ${input[promptKey]}`;\n }\n\n const toolMessage = new ToolMessage({\n content,\n name: toolName,\n tool_call_id: toolCallId,\n });\n\n return new Command({\n goto: destination,\n update: { messages: state.messages.concat(toolMessage) },\n graph: Command.PARENT,\n });\n },\n {\n name: toolName,\n schema: hasHandoffInput\n ? z.object({\n [promptKey]: z\n .string()\n .optional()\n .describe(handoffInputDescription as string),\n })\n : z.object({}),\n description: toolDescription,\n }\n )\n );\n } else {\n /** Create individual tools for each destination */\n for (const destination of destinations) {\n const toolName = `transfer_to_${destination}`;\n const toolDescription =\n edge.description ?? `Transfer control to agent '${destination}'`;\n\n /** Check if we have a prompt for handoff input */\n const hasHandoffInput =\n edge.prompt != null && typeof edge.prompt === 'string';\n const handoffInputDescription = hasHandoffInput\n ? edge.prompt\n : undefined;\n const promptKey = edge.promptKey ?? 'instructions';\n\n tools.push(\n tool(\n async (input: Record<string, unknown>, config) => {\n const toolCallId =\n (config as ToolRunnableConfig | undefined)?.toolCall?.id ??\n 'unknown';\n\n let content = `Successfully transferred to ${destination}`;\n if (\n hasHandoffInput &&\n promptKey in input &&\n input[promptKey] != null\n ) {\n content += `\\n\\n${promptKey.charAt(0).toUpperCase() + promptKey.slice(1)}: ${input[promptKey]}`;\n }\n\n const toolMessage = new ToolMessage({\n content,\n name: toolName,\n tool_call_id: toolCallId,\n });\n\n const state = getCurrentTaskInput() as t.BaseGraphState;\n\n return new Command({\n goto: destination,\n update: { messages: state.messages.concat(toolMessage) },\n graph: Command.PARENT,\n });\n },\n {\n name: toolName,\n schema: hasHandoffInput\n ? z.object({\n [promptKey]: z\n .string()\n .optional()\n .describe(handoffInputDescription as string),\n })\n : z.object({}),\n description: toolDescription,\n }\n )\n );\n }\n }\n\n return tools;\n }\n\n /**\n * Create a complete agent subgraph (similar to createReactAgent)\n */\n private createAgentSubgraph(agentId: string): t.CompiledAgentWorfklow {\n /** This is essentially the same as `createAgentNode` from `StandardGraph` */\n return this.createAgentNode(agentId);\n }\n\n /**\n * Create the multi-agent workflow with dynamic handoffs\n */\n override createWorkflow(): t.CompiledMultiAgentWorkflow {\n const StateAnnotation = Annotation.Root({\n messages: Annotation<BaseMessage[]>({\n reducer: (a, b) => {\n if (!a.length) {\n this.startIndex = a.length + b.length;\n }\n const result = messagesStateReducer(a, b);\n this.messages = result;\n return result;\n },\n default: () => [],\n }),\n /** Channel for passing filtered messages to agents when excludeResults is true */\n agentMessages: Annotation<BaseMessage[]>({\n /** Replaces state entirely */\n reducer: (a, b) => b,\n default: () => [],\n }),\n });\n\n const builder = new StateGraph(StateAnnotation);\n\n // Add all agents as complete subgraphs\n for (const [agentId] of this.agentContexts) {\n // Get all possible destinations for this agent\n const handoffDestinations = new Set<string>();\n const directDestinations = new Set<string>();\n\n // Check handoff edges for destinations\n for (const edge of this.handoffEdges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n if (sources.includes(agentId) === true) {\n const dests = Array.isArray(edge.to) ? edge.to : [edge.to];\n dests.forEach((dest) => handoffDestinations.add(dest));\n }\n }\n\n // Check direct edges for destinations\n for (const edge of this.directEdges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n if (sources.includes(agentId) === true) {\n const dests = Array.isArray(edge.to) ? edge.to : [edge.to];\n dests.forEach((dest) => directDestinations.add(dest));\n }\n }\n\n /** If agent has handoff destinations, add END to possible ends\n * If agent only has direct destinations, it naturally ends without explicit END\n */\n const destinations = new Set([...handoffDestinations]);\n if (handoffDestinations.size > 0 || directDestinations.size === 0) {\n destinations.add(END);\n }\n\n /** Agent subgraph (includes agent + tools) */\n const agentSubgraph = this.createAgentSubgraph(agentId);\n\n /** Wrapper function that handles agentMessages channel */\n const agentWrapper = async (\n state: t.MultiAgentGraphState\n ): Promise<t.MultiAgentGraphState> => {\n if (state.agentMessages != null && state.agentMessages.length > 0) {\n /** Temporary state with messages replaced by `agentMessages` */\n const transformedState: t.MultiAgentGraphState = {\n ...state,\n messages: state.agentMessages,\n };\n const result = await agentSubgraph.invoke(transformedState);\n return {\n ...result,\n /** Clear agentMessages for next agent */\n agentMessages: [],\n };\n } else {\n return await agentSubgraph.invoke(state);\n }\n };\n\n /** Wrapped agent as a node with its possible destinations */\n builder.addNode(agentId, agentWrapper, {\n ends: Array.from(destinations),\n });\n }\n\n // Add starting edges for all starting nodes\n for (const startNode of this.startingNodes) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n /** @ts-ignore */\n builder.addEdge(START, startNode);\n }\n\n /**\n * Add direct edges for automatic transitions\n * Group edges by destination to handle fan-in scenarios\n */\n const edgesByDestination = new Map<string, t.GraphEdge[]>();\n\n for (const edge of this.directEdges) {\n const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];\n for (const destination of destinations) {\n if (!edgesByDestination.has(destination)) {\n edgesByDestination.set(destination, []);\n }\n edgesByDestination.get(destination)!.push(edge);\n }\n }\n\n for (const [destination, edges] of edgesByDestination) {\n /** Checks if this is a fan-in scenario with prompt instructions */\n const edgesWithPrompt = edges.filter(\n (edge) => edge.prompt != null && edge.prompt !== ''\n );\n\n if (edgesWithPrompt.length > 0) {\n /**\n * Single wrapper node for destination (Fan-in with prompt)\n */\n const wrapperNodeId = `fan_in_${destination}_prompt`;\n /**\n * First edge's `prompt`\n * (they should all be the same for fan-in)\n */\n const prompt = edgesWithPrompt[0].prompt;\n /**\n * First edge's `excludeResults` flag\n * (they should all be the same for fan-in)\n */\n const excludeResults = edgesWithPrompt[0].excludeResults;\n\n builder.addNode(wrapperNodeId, async (state: t.BaseGraphState) => {\n let promptText: string | undefined;\n let effectiveExcludeResults = excludeResults;\n\n if (typeof prompt === 'function') {\n promptText = prompt(state.messages, this.startIndex);\n } else if (prompt != null) {\n if (prompt.includes('{results}')) {\n const resultsMessages = state.messages.slice(this.startIndex);\n const resultsString = getBufferString(resultsMessages);\n const promptTemplate = ChatPromptTemplate.fromTemplate(prompt);\n const formattedPromptValue = await promptTemplate.invoke({\n results: resultsString,\n });\n promptText = formattedPromptValue.messages[0].content.toString();\n effectiveExcludeResults =\n excludeResults !== false && promptText !== '';\n } else {\n promptText = prompt;\n }\n }\n\n if (promptText != null && promptText !== '') {\n if (\n effectiveExcludeResults == null ||\n effectiveExcludeResults === false\n ) {\n return {\n messages: [new HumanMessage(promptText)],\n };\n }\n\n /** When `excludeResults` is true, use agentMessages channel\n * to pass filtered messages + prompt to the destination agent\n */\n const filteredMessages = state.messages.slice(0, this.startIndex);\n return {\n messages: [new HumanMessage(promptText)],\n agentMessages: messagesStateReducer(filteredMessages, [\n new HumanMessage(promptText),\n ]),\n };\n }\n\n /** No prompt needed, return empty update */\n return {};\n });\n\n /** Add edges from all sources to the wrapper, then wrapper to destination */\n for (const edge of edges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n for (const source of sources) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n /** @ts-ignore */\n builder.addEdge(source, wrapperNodeId);\n }\n }\n\n /** Single edge from wrapper to destination */\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n /** @ts-ignore */\n builder.addEdge(wrapperNodeId, destination);\n } else {\n /** No prompt instructions, add direct edges */\n for (const edge of edges) {\n const sources = Array.isArray(edge.from) ? edge.from : [edge.from];\n for (const source of sources) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n /** @ts-ignore */\n builder.addEdge(source, destination);\n }\n }\n }\n }\n\n return builder.compile(this.compileOptions as unknown as never);\n }\n}\n"],"names":[],"mappings":"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"}
@@ -33,5 +33,5 @@ export declare class MultiAgentGraph extends StandardGraph {
33
33
  /**
34
34
  * Create the multi-agent workflow with dynamic handoffs
35
35
  */
36
- createWorkflow(): t.CompiledStateWorkflow;
36
+ createWorkflow(): t.CompiledMultiAgentWorkflow;
37
37
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
@@ -28,6 +28,9 @@ export type SystemCallbacks = {
28
28
  export type BaseGraphState = {
29
29
  messages: BaseMessage[];
30
30
  };
31
+ export type MultiAgentGraphState = BaseGraphState & {
32
+ agentMessages?: BaseMessage[];
33
+ };
31
34
  export type IState = BaseGraphState;
32
35
  export interface EventHandler {
33
36
  handle(event: string, data: StreamEventData | ModelEndData | RunStep | RunStepDeltaEvent | MessageDeltaEvent | ReasoningDeltaEvent | {
@@ -46,6 +49,19 @@ export type CompiledStateWorkflow = CompiledStateGraph<StateType<{
46
49
  }, {
47
50
  messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
48
51
  }, StateDefinition>;
52
+ export type CompiledMultiAgentWorkflow = CompiledStateGraph<StateType<{
53
+ messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
54
+ agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
55
+ }>, UpdateType<{
56
+ messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
57
+ agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
58
+ }>, string, {
59
+ messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
60
+ agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
61
+ }, {
62
+ messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
63
+ agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
64
+ }, StateDefinition>;
49
65
  export type CompiledAgentWorfklow = CompiledStateGraph<{
50
66
  messages: BaseMessage[];
51
67
  }, {
@@ -185,17 +201,35 @@ export type StandardGraphInput = {
185
201
  indexTokenCountMap?: Record<string, number>;
186
202
  };
187
203
  export type GraphEdge = {
188
- /** Use a list for multiple sources */
204
+ /** Agent ID, use a list for multiple sources */
189
205
  from: string | string[];
190
- /** Use a list for multiple destinations */
206
+ /** Agent ID, use a list for multiple destinations */
191
207
  to: string | string[];
192
208
  description?: string;
193
209
  /** Can return boolean or specific destination(s) */
194
210
  condition?: (state: BaseGraphState) => boolean | string | string[];
195
211
  /** 'handoff' creates tools for dynamic routing, 'direct' creates direct edges, which also allow parallel execution */
196
212
  edgeType?: 'handoff' | 'direct';
197
- /** Optional prompt to add when transitioning through this edge */
198
- promptInstructions?: string | ((messages: BaseMessage[]) => string | undefined);
213
+ /**
214
+ * For direct edges: Optional prompt to add when transitioning through this edge.
215
+ * String prompts can include variables like {results} which will be replaced with
216
+ * messages from startIndex onwards. When {results} is used, excludeResults defaults to true.
217
+ *
218
+ * For handoff edges: Description for the input parameter that the handoff tool accepts,
219
+ * allowing the supervisor to pass specific instructions/context to the transferred agent.
220
+ */
221
+ prompt?: string | ((messages: BaseMessage[], runStartIndex: number) => string | undefined);
222
+ /**
223
+ * When true, excludes messages from startIndex when adding prompt.
224
+ * Automatically set to true when {results} variable is used in prompt.
225
+ */
226
+ excludeResults?: boolean;
227
+ /**
228
+ * For handoff edges: Customizes the parameter name for the handoff input.
229
+ * Defaults to "instructions" if not specified.
230
+ * Only applies when prompt is provided for handoff edges.
231
+ */
232
+ promptKey?: string;
199
233
  };
200
234
  export type MultiAgentGraphInput = StandardGraphInput & {
201
235
  edges: GraphEdge[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.0.00-rc1",
3
+ "version": "3.0.00-rc2",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -60,6 +60,10 @@
60
60
  "multi-agent-parallel": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-parallel.ts",
61
61
  "multi-agent-sequence": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-sequence.ts",
62
62
  "multi-agent-conditional": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-conditional.ts",
63
+ "multi-agent-supervisor": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-supervisor.ts",
64
+ "multi-agent-list-handoff": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-multi-agent-list-handoff.ts",
65
+ "test-handoff-input": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-handoff-input.ts",
66
+ "test-custom-prompt-key": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-custom-prompt-key.ts",
63
67
  "script2": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/proto/example_test.ts",
64
68
  "script3": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/proto/example_test_anthropic.ts",
65
69
  "script4": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/cli4.ts --name 'Jo' --location 'New York, NY'",