@agentforge/patterns 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1642,26 +1642,35 @@ var RoutingStrategySchema = import_zod7.z.enum([
1642
1642
  ]);
1643
1643
  var RoutingDecisionSchema = import_zod7.z.object({
1644
1644
  /**
1645
- * Target agent to route to
1645
+ * Target agent to route to (single agent routing)
1646
+ * @deprecated Use targetAgents for parallel routing support
1646
1647
  */
1647
- targetAgent: import_zod7.z.string().describe("Agent to route the task to"),
1648
+ targetAgent: import_zod7.z.string().nullable().default(null).describe("Agent to route the task to (single routing)"),
1649
+ /**
1650
+ * Target agents to route to (parallel routing)
1651
+ * When multiple agents are specified, they execute in parallel
1652
+ */
1653
+ targetAgents: import_zod7.z.array(import_zod7.z.string()).nullable().default(null).describe("Agents to route the task to (parallel routing)"),
1648
1654
  /**
1649
1655
  * Reasoning for the routing decision
1650
1656
  */
1651
- reasoning: import_zod7.z.string().optional().describe("Explanation for routing decision"),
1657
+ reasoning: import_zod7.z.string().default("").describe("Explanation for routing decision"),
1652
1658
  /**
1653
1659
  * Confidence in the routing decision (0-1)
1654
1660
  */
1655
- confidence: import_zod7.z.number().min(0).max(1).optional().describe("Confidence score"),
1661
+ confidence: import_zod7.z.number().min(0).max(1).default(0.8).describe("Confidence score"),
1656
1662
  /**
1657
1663
  * Strategy used for routing
1658
1664
  */
1659
- strategy: RoutingStrategySchema.describe("Strategy used for this decision"),
1665
+ strategy: RoutingStrategySchema.default("llm-based").describe("Strategy used for this decision"),
1660
1666
  /**
1661
1667
  * Timestamp of the routing decision
1662
1668
  */
1663
- timestamp: import_zod7.z.number().optional().describe("Timestamp of the decision")
1664
- });
1669
+ timestamp: import_zod7.z.number().default(() => Date.now()).describe("Timestamp of the decision")
1670
+ }).refine(
1671
+ (data) => data.targetAgent || data.targetAgents && data.targetAgents.length > 0,
1672
+ { message: "Either targetAgent or targetAgents must be provided" }
1673
+ );
1665
1674
  var WorkerCapabilitiesSchema = import_zod7.z.object({
1666
1675
  /**
1667
1676
  * Skills/capabilities the agent has
@@ -1929,16 +1938,33 @@ var DEFAULT_SUPERVISOR_SYSTEM_PROMPT = `You are a supervisor agent responsible f
1929
1938
  Your job is to:
1930
1939
  1. Analyze the current task and context
1931
1940
  2. Review available worker capabilities
1932
- 3. Select the most appropriate worker for the task
1941
+ 3. Select the most appropriate worker(s) for the task
1933
1942
  4. Provide clear reasoning for your decision
1934
1943
 
1935
- Respond with a JSON object containing:
1944
+ **IMPORTANT: You can route to MULTIPLE workers for parallel execution when:**
1945
+ - The task requires information from multiple domains (e.g., code + documentation)
1946
+ - Multiple workers have complementary expertise
1947
+ - Parallel execution would provide a more comprehensive answer
1948
+
1949
+ **Response Format:**
1950
+
1951
+ For SINGLE worker routing:
1936
1952
  {
1937
1953
  "targetAgent": "worker_id",
1938
1954
  "reasoning": "explanation of why this worker is best suited",
1939
1955
  "confidence": 0.0-1.0,
1940
1956
  "strategy": "llm-based"
1941
- }`;
1957
+ }
1958
+
1959
+ For PARALLEL multi-worker routing:
1960
+ {
1961
+ "targetAgents": ["worker_id_1", "worker_id_2", ...],
1962
+ "reasoning": "explanation of why these workers should work in parallel",
1963
+ "confidence": 0.0-1.0,
1964
+ "strategy": "llm-based"
1965
+ }
1966
+
1967
+ Choose parallel routing when the task benefits from multiple perspectives or data sources.`;
1942
1968
  var llmBasedRouting = {
1943
1969
  name: "llm-based",
1944
1970
  async route(state, config) {
@@ -1961,7 +1987,7 @@ var llmBasedRouting = {
1961
1987
  Available workers:
1962
1988
  ${workerInfo}
1963
1989
 
1964
- Select the best worker for this task and explain your reasoning.`;
1990
+ Select the best worker(s) for this task and explain your reasoning.`;
1965
1991
  const conversationHistory = [];
1966
1992
  let attempt = 0;
1967
1993
  while (attempt < maxRetries) {
@@ -1983,19 +2009,33 @@ Select the best worker for this task and explain your reasoning.`;
1983
2009
  attempt++;
1984
2010
  continue;
1985
2011
  }
1986
- const content = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
1987
- try {
1988
- const decision = JSON.parse(content);
1989
- return {
1990
- targetAgent: decision.targetAgent,
1991
- reasoning: decision.reasoning,
1992
- confidence: decision.confidence,
1993
- strategy: "llm-based",
1994
- timestamp: Date.now()
1995
- };
1996
- } catch (error) {
1997
- throw new Error(`Failed to parse routing decision from LLM: ${error}`);
2012
+ let decision;
2013
+ if (response && typeof response === "object" && ("targetAgent" in response || "targetAgents" in response)) {
2014
+ decision = response;
2015
+ } else if (response.content) {
2016
+ if (typeof response.content === "string") {
2017
+ try {
2018
+ decision = JSON.parse(response.content);
2019
+ } catch (error) {
2020
+ throw new Error(`Failed to parse routing decision from LLM. Expected JSON but got: ${response.content}`);
2021
+ }
2022
+ } else if (typeof response.content === "object") {
2023
+ decision = response.content;
2024
+ } else {
2025
+ throw new Error(`Unexpected response content type: ${typeof response.content}`);
2026
+ }
2027
+ } else {
2028
+ throw new Error(`Unexpected response format: ${JSON.stringify(response)}`);
1998
2029
  }
2030
+ const result = {
2031
+ targetAgent: decision.targetAgent,
2032
+ targetAgents: decision.targetAgents,
2033
+ reasoning: decision.reasoning,
2034
+ confidence: decision.confidence,
2035
+ strategy: "llm-based",
2036
+ timestamp: Date.now()
2037
+ };
2038
+ return result;
1999
2039
  }
2000
2040
  throw new Error(`Max tool retries (${maxRetries}) exceeded without routing decision`);
2001
2041
  }
@@ -2011,6 +2051,7 @@ var roundRobinRouting = {
2011
2051
  const targetAgent = availableWorkers[lastRoutingIndex];
2012
2052
  return {
2013
2053
  targetAgent,
2054
+ targetAgents: null,
2014
2055
  reasoning: `Round-robin selection: worker ${lastRoutingIndex + 1} of ${availableWorkers.length}`,
2015
2056
  confidence: 1,
2016
2057
  strategy: "round-robin",
@@ -2040,6 +2081,7 @@ var skillBasedRouting = {
2040
2081
  }
2041
2082
  return {
2042
2083
  targetAgent: firstAvailable[0],
2084
+ targetAgents: null,
2043
2085
  reasoning: "No skill matches found, using first available worker",
2044
2086
  confidence: 0.5,
2045
2087
  strategy: "skill-based",
@@ -2050,6 +2092,7 @@ var skillBasedRouting = {
2050
2092
  const confidence = Math.min(best.score / 5, 1);
2051
2093
  return {
2052
2094
  targetAgent: best.id,
2095
+ targetAgents: null,
2053
2096
  reasoning: `Best skill match with score ${best.score} (skills: ${best.skills.join(", ")})`,
2054
2097
  confidence,
2055
2098
  strategy: "skill-based",
@@ -2069,6 +2112,7 @@ var loadBalancedRouting = {
2069
2112
  const confidence = targetWorker.workload === 0 ? 1 : Math.max(0.5, 1 - targetWorker.workload / (avgWorkload * 2));
2070
2113
  return {
2071
2114
  targetAgent: targetWorker.id,
2115
+ targetAgents: null,
2072
2116
  reasoning: `Lowest workload: ${targetWorker.workload} tasks (avg: ${avgWorkload.toFixed(1)})`,
2073
2117
  confidence,
2074
2118
  strategy: "load-balanced",
@@ -2124,10 +2168,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2124
2168
  );
2125
2169
  if (!currentAssignment) {
2126
2170
  logger.debug("No active assignment found", { workerId });
2127
- return {
2128
- currentAgent: "supervisor",
2129
- status: "routing"
2130
- };
2171
+ return {};
2131
2172
  }
2132
2173
  const result = await agent.invoke(
2133
2174
  {
@@ -2159,9 +2200,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2159
2200
  }
2160
2201
  };
2161
2202
  return {
2162
- completedTasks: [taskResult],
2163
- currentAgent: "supervisor",
2164
- status: "routing"
2203
+ completedTasks: [taskResult]
2165
2204
  };
2166
2205
  } catch (error) {
2167
2206
  if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
@@ -2232,7 +2271,7 @@ function createSupervisorNode(config) {
2232
2271
  };
2233
2272
  }
2234
2273
  const allCompleted = state.activeAssignments.every(
2235
- (assignment2) => state.completedTasks.some((task) => task.assignmentId === assignment2.id)
2274
+ (assignment) => state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2236
2275
  );
2237
2276
  if (allCompleted && state.activeAssignments.length > 0) {
2238
2277
  if (verbose) {
@@ -2245,20 +2284,29 @@ function createSupervisorNode(config) {
2245
2284
  }
2246
2285
  const routingImpl = getRoutingStrategy(strategy);
2247
2286
  const decision = await routingImpl.route(state, config);
2287
+ const targetAgents = decision.targetAgents && decision.targetAgents.length > 0 ? decision.targetAgents : decision.targetAgent ? [decision.targetAgent] : [];
2288
+ if (targetAgents.length === 0) {
2289
+ throw new Error("Routing decision must specify at least one target agent");
2290
+ }
2248
2291
  if (verbose) {
2249
- console.log(`[Supervisor] Routing to ${decision.targetAgent}: ${decision.reasoning}`);
2292
+ if (targetAgents.length === 1) {
2293
+ console.log(`[Supervisor] Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2294
+ } else {
2295
+ console.log(`[Supervisor] Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`);
2296
+ }
2250
2297
  }
2251
- const assignment = {
2298
+ const task = state.messages[state.messages.length - 1]?.content || state.input;
2299
+ const assignments = targetAgents.map((workerId) => ({
2252
2300
  id: `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2253
- workerId: decision.targetAgent,
2254
- task: state.messages[state.messages.length - 1]?.content || state.input,
2301
+ workerId,
2302
+ task,
2255
2303
  priority: 5,
2256
2304
  assignedAt: Date.now()
2257
- };
2258
- const message = {
2305
+ }));
2306
+ const messages = assignments.map((assignment) => ({
2259
2307
  id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2260
2308
  from: "supervisor",
2261
- to: [decision.targetAgent],
2309
+ to: [assignment.workerId],
2262
2310
  type: "task_assignment",
2263
2311
  content: assignment.task,
2264
2312
  timestamp: Date.now(),
@@ -2266,13 +2314,15 @@ function createSupervisorNode(config) {
2266
2314
  assignmentId: assignment.id,
2267
2315
  priority: assignment.priority
2268
2316
  }
2269
- };
2317
+ }));
2270
2318
  return {
2271
- currentAgent: decision.targetAgent,
2319
+ currentAgent: targetAgents.join(","),
2320
+ // Store all agents (for backward compat)
2272
2321
  status: "executing",
2273
2322
  routingHistory: [decision],
2274
- activeAssignments: [assignment],
2275
- messages: [message],
2323
+ activeAssignments: assignments,
2324
+ // Multiple assignments for parallel execution!
2325
+ messages,
2276
2326
  iteration: state.iteration + 1
2277
2327
  };
2278
2328
  } catch (error) {
@@ -2307,10 +2357,7 @@ function createWorkerNode(config) {
2307
2357
  if (verbose) {
2308
2358
  console.log(`[Worker:${id}] No active assignment found`);
2309
2359
  }
2310
- return {
2311
- currentAgent: "supervisor",
2312
- status: "routing"
2313
- };
2360
+ return {};
2314
2361
  }
2315
2362
  if (executeFn) {
2316
2363
  if (verbose) {
@@ -2385,9 +2432,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2385
2432
  return {
2386
2433
  completedTasks: [taskResult],
2387
2434
  messages: [message],
2388
- workers: updatedWorkers,
2389
- currentAgent: "supervisor",
2390
- status: "routing"
2435
+ workers: updatedWorkers
2391
2436
  };
2392
2437
  } catch (error) {
2393
2438
  if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
@@ -2500,10 +2545,16 @@ function createMultiAgentSystem(config) {
2500
2545
  } = config;
2501
2546
  const workflow = new import_langgraph4.StateGraph(MultiAgentState);
2502
2547
  let supervisorConfig = { ...supervisor, maxIterations, verbose };
2503
- if (supervisor.model && supervisor.tools && supervisor.tools.length > 0) {
2504
- const langchainTools = (0, import_core9.toLangChainTools)(supervisor.tools);
2505
- const modelWithTools = supervisor.model.bindTools(langchainTools);
2506
- supervisorConfig.model = modelWithTools;
2548
+ if (supervisor.model) {
2549
+ let configuredModel = supervisor.model;
2550
+ if (supervisor.strategy === "llm-based") {
2551
+ configuredModel = configuredModel.withStructuredOutput(RoutingDecisionSchema);
2552
+ }
2553
+ if (supervisor.tools && supervisor.tools.length > 0) {
2554
+ const langchainTools = (0, import_core9.toLangChainTools)(supervisor.tools);
2555
+ configuredModel = configuredModel.bindTools(langchainTools);
2556
+ }
2557
+ supervisorConfig.model = configuredModel;
2507
2558
  }
2508
2559
  const supervisorNode = createSupervisorNode(supervisorConfig);
2509
2560
  workflow.addNode("supervisor", supervisorNode);
@@ -2531,6 +2582,10 @@ function createMultiAgentSystem(config) {
2531
2582
  return "aggregator";
2532
2583
  }
2533
2584
  if (state.currentAgent && state.currentAgent !== "supervisor") {
2585
+ if (state.currentAgent.includes(",")) {
2586
+ const agents = state.currentAgent.split(",").map((a) => a.trim());
2587
+ return agents;
2588
+ }
2534
2589
  return state.currentAgent;
2535
2590
  }
2536
2591
  return "supervisor";
package/dist/index.d.cts CHANGED
@@ -1860,40 +1860,70 @@ declare const RoutingStrategySchema: z.ZodEnum<["llm-based", "rule-based", "roun
1860
1860
  type RoutingStrategy = z.infer<typeof RoutingStrategySchema>;
1861
1861
  /**
1862
1862
  * Schema for routing decision
1863
+ *
1864
+ * Supports both single-agent and parallel multi-agent routing:
1865
+ * - Single: Use `targetAgent` field
1866
+ * - Parallel: Use `targetAgents` array field
1867
+ *
1868
+ * If both are provided, `targetAgents` takes precedence.
1869
+ *
1870
+ * Note: Uses .nullable() instead of .optional() for OpenAI structured output compatibility
1863
1871
  */
1864
- declare const RoutingDecisionSchema: z.ZodObject<{
1872
+ declare const RoutingDecisionSchema: z.ZodEffects<z.ZodObject<{
1865
1873
  /**
1866
- * Target agent to route to
1874
+ * Target agent to route to (single agent routing)
1875
+ * @deprecated Use targetAgents for parallel routing support
1867
1876
  */
1868
- targetAgent: z.ZodString;
1877
+ targetAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
1878
+ /**
1879
+ * Target agents to route to (parallel routing)
1880
+ * When multiple agents are specified, they execute in parallel
1881
+ */
1882
+ targetAgents: z.ZodDefault<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
1869
1883
  /**
1870
1884
  * Reasoning for the routing decision
1871
1885
  */
1872
- reasoning: z.ZodOptional<z.ZodString>;
1886
+ reasoning: z.ZodDefault<z.ZodString>;
1873
1887
  /**
1874
1888
  * Confidence in the routing decision (0-1)
1875
1889
  */
1876
- confidence: z.ZodOptional<z.ZodNumber>;
1890
+ confidence: z.ZodDefault<z.ZodNumber>;
1877
1891
  /**
1878
1892
  * Strategy used for routing
1879
1893
  */
1880
- strategy: z.ZodEnum<["llm-based", "rule-based", "round-robin", "skill-based", "load-balanced"]>;
1894
+ strategy: z.ZodDefault<z.ZodEnum<["llm-based", "rule-based", "round-robin", "skill-based", "load-balanced"]>>;
1881
1895
  /**
1882
1896
  * Timestamp of the routing decision
1883
1897
  */
1884
- timestamp: z.ZodOptional<z.ZodNumber>;
1898
+ timestamp: z.ZodDefault<z.ZodNumber>;
1885
1899
  }, "strip", z.ZodTypeAny, {
1886
- targetAgent: string;
1900
+ timestamp: number;
1901
+ reasoning: string;
1902
+ confidence: number;
1903
+ targetAgent: string | null;
1904
+ targetAgents: string[] | null;
1887
1905
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
1906
+ }, {
1888
1907
  timestamp?: number | undefined;
1889
1908
  reasoning?: string | undefined;
1890
1909
  confidence?: number | undefined;
1891
- }, {
1892
- targetAgent: string;
1910
+ targetAgent?: string | null | undefined;
1911
+ targetAgents?: string[] | null | undefined;
1912
+ strategy?: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced" | undefined;
1913
+ }>, {
1914
+ timestamp: number;
1915
+ reasoning: string;
1916
+ confidence: number;
1917
+ targetAgent: string | null;
1918
+ targetAgents: string[] | null;
1893
1919
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
1920
+ }, {
1894
1921
  timestamp?: number | undefined;
1895
1922
  reasoning?: string | undefined;
1896
1923
  confidence?: number | undefined;
1924
+ targetAgent?: string | null | undefined;
1925
+ targetAgents?: string[] | null | undefined;
1926
+ strategy?: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced" | undefined;
1897
1927
  }>;
1898
1928
  type RoutingDecision = z.infer<typeof RoutingDecisionSchema>;
1899
1929
  /**
@@ -2166,31 +2196,49 @@ declare const MultiAgentStateConfig: {
2166
2196
  * Accumulates all routing decisions
2167
2197
  */
2168
2198
  routingHistory: {
2169
- schema: z.ZodArray<z.ZodObject<{
2170
- targetAgent: z.ZodString;
2171
- reasoning: z.ZodOptional<z.ZodString>;
2172
- confidence: z.ZodOptional<z.ZodNumber>;
2173
- strategy: z.ZodEnum<["llm-based", "rule-based", "round-robin", "skill-based", "load-balanced"]>;
2174
- timestamp: z.ZodOptional<z.ZodNumber>;
2199
+ schema: z.ZodArray<z.ZodEffects<z.ZodObject<{
2200
+ targetAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
2201
+ targetAgents: z.ZodDefault<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
2202
+ reasoning: z.ZodDefault<z.ZodString>;
2203
+ confidence: z.ZodDefault<z.ZodNumber>;
2204
+ strategy: z.ZodDefault<z.ZodEnum<["llm-based", "rule-based", "round-robin", "skill-based", "load-balanced"]>>;
2205
+ timestamp: z.ZodDefault<z.ZodNumber>;
2175
2206
  }, "strip", z.ZodTypeAny, {
2176
- targetAgent: string;
2207
+ timestamp: number;
2208
+ reasoning: string;
2209
+ confidence: number;
2210
+ targetAgent: string | null;
2211
+ targetAgents: string[] | null;
2177
2212
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
2213
+ }, {
2178
2214
  timestamp?: number | undefined;
2179
2215
  reasoning?: string | undefined;
2180
2216
  confidence?: number | undefined;
2181
- }, {
2182
- targetAgent: string;
2217
+ targetAgent?: string | null | undefined;
2218
+ targetAgents?: string[] | null | undefined;
2219
+ strategy?: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced" | undefined;
2220
+ }>, {
2221
+ timestamp: number;
2222
+ reasoning: string;
2223
+ confidence: number;
2224
+ targetAgent: string | null;
2225
+ targetAgents: string[] | null;
2183
2226
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
2227
+ }, {
2184
2228
  timestamp?: number | undefined;
2185
2229
  reasoning?: string | undefined;
2186
2230
  confidence?: number | undefined;
2231
+ targetAgent?: string | null | undefined;
2232
+ targetAgents?: string[] | null | undefined;
2233
+ strategy?: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced" | undefined;
2187
2234
  }>, "many">;
2188
2235
  reducer: (left: RoutingDecision[], right: RoutingDecision[]) => {
2189
- targetAgent: string;
2236
+ timestamp: number;
2237
+ reasoning: string;
2238
+ confidence: number;
2239
+ targetAgent: string | null;
2240
+ targetAgents: string[] | null;
2190
2241
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
2191
- timestamp?: number | undefined;
2192
- reasoning?: string | undefined;
2193
- confidence?: number | undefined;
2194
2242
  }[];
2195
2243
  default: () => never[];
2196
2244
  description: string;
@@ -2606,7 +2654,7 @@ interface RoutingStrategyImpl {
2606
2654
  /**
2607
2655
  * Default system prompt for LLM-based routing
2608
2656
  */
2609
- declare const DEFAULT_SUPERVISOR_SYSTEM_PROMPT = "You are a supervisor agent responsible for routing tasks to specialized worker agents.\n\nYour job is to:\n1. Analyze the current task and context\n2. Review available worker capabilities\n3. Select the most appropriate worker for the task\n4. Provide clear reasoning for your decision\n\nRespond with a JSON object containing:\n{\n \"targetAgent\": \"worker_id\",\n \"reasoning\": \"explanation of why this worker is best suited\",\n \"confidence\": 0.0-1.0,\n \"strategy\": \"llm-based\"\n}";
2657
+ declare const DEFAULT_SUPERVISOR_SYSTEM_PROMPT = "You are a supervisor agent responsible for routing tasks to specialized worker agents.\n\nYour job is to:\n1. Analyze the current task and context\n2. Review available worker capabilities\n3. Select the most appropriate worker(s) for the task\n4. Provide clear reasoning for your decision\n\n**IMPORTANT: You can route to MULTIPLE workers for parallel execution when:**\n- The task requires information from multiple domains (e.g., code + documentation)\n- Multiple workers have complementary expertise\n- Parallel execution would provide a more comprehensive answer\n\n**Response Format:**\n\nFor SINGLE worker routing:\n{\n \"targetAgent\": \"worker_id\",\n \"reasoning\": \"explanation of why this worker is best suited\",\n \"confidence\": 0.0-1.0,\n \"strategy\": \"llm-based\"\n}\n\nFor PARALLEL multi-worker routing:\n{\n \"targetAgents\": [\"worker_id_1\", \"worker_id_2\", ...],\n \"reasoning\": \"explanation of why these workers should work in parallel\",\n \"confidence\": 0.0-1.0,\n \"strategy\": \"llm-based\"\n}\n\nChoose parallel routing when the task benefits from multiple perspectives or data sources.";
2610
2658
  /**
2611
2659
  * LLM-based routing strategy
2612
2660
  * Uses an LLM to intelligently route tasks based on worker capabilities
package/dist/index.d.ts CHANGED
@@ -1860,40 +1860,70 @@ declare const RoutingStrategySchema: z.ZodEnum<["llm-based", "rule-based", "roun
1860
1860
  type RoutingStrategy = z.infer<typeof RoutingStrategySchema>;
1861
1861
  /**
1862
1862
  * Schema for routing decision
1863
+ *
1864
+ * Supports both single-agent and parallel multi-agent routing:
1865
+ * - Single: Use `targetAgent` field
1866
+ * - Parallel: Use `targetAgents` array field
1867
+ *
1868
+ * If both are provided, `targetAgents` takes precedence.
1869
+ *
1870
+ * Note: Uses .nullable() instead of .optional() for OpenAI structured output compatibility
1863
1871
  */
1864
- declare const RoutingDecisionSchema: z.ZodObject<{
1872
+ declare const RoutingDecisionSchema: z.ZodEffects<z.ZodObject<{
1865
1873
  /**
1866
- * Target agent to route to
1874
+ * Target agent to route to (single agent routing)
1875
+ * @deprecated Use targetAgents for parallel routing support
1867
1876
  */
1868
- targetAgent: z.ZodString;
1877
+ targetAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
1878
+ /**
1879
+ * Target agents to route to (parallel routing)
1880
+ * When multiple agents are specified, they execute in parallel
1881
+ */
1882
+ targetAgents: z.ZodDefault<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
1869
1883
  /**
1870
1884
  * Reasoning for the routing decision
1871
1885
  */
1872
- reasoning: z.ZodOptional<z.ZodString>;
1886
+ reasoning: z.ZodDefault<z.ZodString>;
1873
1887
  /**
1874
1888
  * Confidence in the routing decision (0-1)
1875
1889
  */
1876
- confidence: z.ZodOptional<z.ZodNumber>;
1890
+ confidence: z.ZodDefault<z.ZodNumber>;
1877
1891
  /**
1878
1892
  * Strategy used for routing
1879
1893
  */
1880
- strategy: z.ZodEnum<["llm-based", "rule-based", "round-robin", "skill-based", "load-balanced"]>;
1894
+ strategy: z.ZodDefault<z.ZodEnum<["llm-based", "rule-based", "round-robin", "skill-based", "load-balanced"]>>;
1881
1895
  /**
1882
1896
  * Timestamp of the routing decision
1883
1897
  */
1884
- timestamp: z.ZodOptional<z.ZodNumber>;
1898
+ timestamp: z.ZodDefault<z.ZodNumber>;
1885
1899
  }, "strip", z.ZodTypeAny, {
1886
- targetAgent: string;
1900
+ timestamp: number;
1901
+ reasoning: string;
1902
+ confidence: number;
1903
+ targetAgent: string | null;
1904
+ targetAgents: string[] | null;
1887
1905
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
1906
+ }, {
1888
1907
  timestamp?: number | undefined;
1889
1908
  reasoning?: string | undefined;
1890
1909
  confidence?: number | undefined;
1891
- }, {
1892
- targetAgent: string;
1910
+ targetAgent?: string | null | undefined;
1911
+ targetAgents?: string[] | null | undefined;
1912
+ strategy?: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced" | undefined;
1913
+ }>, {
1914
+ timestamp: number;
1915
+ reasoning: string;
1916
+ confidence: number;
1917
+ targetAgent: string | null;
1918
+ targetAgents: string[] | null;
1893
1919
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
1920
+ }, {
1894
1921
  timestamp?: number | undefined;
1895
1922
  reasoning?: string | undefined;
1896
1923
  confidence?: number | undefined;
1924
+ targetAgent?: string | null | undefined;
1925
+ targetAgents?: string[] | null | undefined;
1926
+ strategy?: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced" | undefined;
1897
1927
  }>;
1898
1928
  type RoutingDecision = z.infer<typeof RoutingDecisionSchema>;
1899
1929
  /**
@@ -2166,31 +2196,49 @@ declare const MultiAgentStateConfig: {
2166
2196
  * Accumulates all routing decisions
2167
2197
  */
2168
2198
  routingHistory: {
2169
- schema: z.ZodArray<z.ZodObject<{
2170
- targetAgent: z.ZodString;
2171
- reasoning: z.ZodOptional<z.ZodString>;
2172
- confidence: z.ZodOptional<z.ZodNumber>;
2173
- strategy: z.ZodEnum<["llm-based", "rule-based", "round-robin", "skill-based", "load-balanced"]>;
2174
- timestamp: z.ZodOptional<z.ZodNumber>;
2199
+ schema: z.ZodArray<z.ZodEffects<z.ZodObject<{
2200
+ targetAgent: z.ZodDefault<z.ZodNullable<z.ZodString>>;
2201
+ targetAgents: z.ZodDefault<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
2202
+ reasoning: z.ZodDefault<z.ZodString>;
2203
+ confidence: z.ZodDefault<z.ZodNumber>;
2204
+ strategy: z.ZodDefault<z.ZodEnum<["llm-based", "rule-based", "round-robin", "skill-based", "load-balanced"]>>;
2205
+ timestamp: z.ZodDefault<z.ZodNumber>;
2175
2206
  }, "strip", z.ZodTypeAny, {
2176
- targetAgent: string;
2207
+ timestamp: number;
2208
+ reasoning: string;
2209
+ confidence: number;
2210
+ targetAgent: string | null;
2211
+ targetAgents: string[] | null;
2177
2212
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
2213
+ }, {
2178
2214
  timestamp?: number | undefined;
2179
2215
  reasoning?: string | undefined;
2180
2216
  confidence?: number | undefined;
2181
- }, {
2182
- targetAgent: string;
2217
+ targetAgent?: string | null | undefined;
2218
+ targetAgents?: string[] | null | undefined;
2219
+ strategy?: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced" | undefined;
2220
+ }>, {
2221
+ timestamp: number;
2222
+ reasoning: string;
2223
+ confidence: number;
2224
+ targetAgent: string | null;
2225
+ targetAgents: string[] | null;
2183
2226
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
2227
+ }, {
2184
2228
  timestamp?: number | undefined;
2185
2229
  reasoning?: string | undefined;
2186
2230
  confidence?: number | undefined;
2231
+ targetAgent?: string | null | undefined;
2232
+ targetAgents?: string[] | null | undefined;
2233
+ strategy?: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced" | undefined;
2187
2234
  }>, "many">;
2188
2235
  reducer: (left: RoutingDecision[], right: RoutingDecision[]) => {
2189
- targetAgent: string;
2236
+ timestamp: number;
2237
+ reasoning: string;
2238
+ confidence: number;
2239
+ targetAgent: string | null;
2240
+ targetAgents: string[] | null;
2190
2241
  strategy: "llm-based" | "rule-based" | "round-robin" | "skill-based" | "load-balanced";
2191
- timestamp?: number | undefined;
2192
- reasoning?: string | undefined;
2193
- confidence?: number | undefined;
2194
2242
  }[];
2195
2243
  default: () => never[];
2196
2244
  description: string;
@@ -2606,7 +2654,7 @@ interface RoutingStrategyImpl {
2606
2654
  /**
2607
2655
  * Default system prompt for LLM-based routing
2608
2656
  */
2609
- declare const DEFAULT_SUPERVISOR_SYSTEM_PROMPT = "You are a supervisor agent responsible for routing tasks to specialized worker agents.\n\nYour job is to:\n1. Analyze the current task and context\n2. Review available worker capabilities\n3. Select the most appropriate worker for the task\n4. Provide clear reasoning for your decision\n\nRespond with a JSON object containing:\n{\n \"targetAgent\": \"worker_id\",\n \"reasoning\": \"explanation of why this worker is best suited\",\n \"confidence\": 0.0-1.0,\n \"strategy\": \"llm-based\"\n}";
2657
+ declare const DEFAULT_SUPERVISOR_SYSTEM_PROMPT = "You are a supervisor agent responsible for routing tasks to specialized worker agents.\n\nYour job is to:\n1. Analyze the current task and context\n2. Review available worker capabilities\n3. Select the most appropriate worker(s) for the task\n4. Provide clear reasoning for your decision\n\n**IMPORTANT: You can route to MULTIPLE workers for parallel execution when:**\n- The task requires information from multiple domains (e.g., code + documentation)\n- Multiple workers have complementary expertise\n- Parallel execution would provide a more comprehensive answer\n\n**Response Format:**\n\nFor SINGLE worker routing:\n{\n \"targetAgent\": \"worker_id\",\n \"reasoning\": \"explanation of why this worker is best suited\",\n \"confidence\": 0.0-1.0,\n \"strategy\": \"llm-based\"\n}\n\nFor PARALLEL multi-worker routing:\n{\n \"targetAgents\": [\"worker_id_1\", \"worker_id_2\", ...],\n \"reasoning\": \"explanation of why these workers should work in parallel\",\n \"confidence\": 0.0-1.0,\n \"strategy\": \"llm-based\"\n}\n\nChoose parallel routing when the task benefits from multiple perspectives or data sources.";
2610
2658
  /**
2611
2659
  * LLM-based routing strategy
2612
2660
  * Uses an LLM to intelligently route tasks based on worker capabilities
package/dist/index.js CHANGED
@@ -1543,26 +1543,35 @@ var RoutingStrategySchema = z7.enum([
1543
1543
  ]);
1544
1544
  var RoutingDecisionSchema = z7.object({
1545
1545
  /**
1546
- * Target agent to route to
1546
+ * Target agent to route to (single agent routing)
1547
+ * @deprecated Use targetAgents for parallel routing support
1547
1548
  */
1548
- targetAgent: z7.string().describe("Agent to route the task to"),
1549
+ targetAgent: z7.string().nullable().default(null).describe("Agent to route the task to (single routing)"),
1550
+ /**
1551
+ * Target agents to route to (parallel routing)
1552
+ * When multiple agents are specified, they execute in parallel
1553
+ */
1554
+ targetAgents: z7.array(z7.string()).nullable().default(null).describe("Agents to route the task to (parallel routing)"),
1549
1555
  /**
1550
1556
  * Reasoning for the routing decision
1551
1557
  */
1552
- reasoning: z7.string().optional().describe("Explanation for routing decision"),
1558
+ reasoning: z7.string().default("").describe("Explanation for routing decision"),
1553
1559
  /**
1554
1560
  * Confidence in the routing decision (0-1)
1555
1561
  */
1556
- confidence: z7.number().min(0).max(1).optional().describe("Confidence score"),
1562
+ confidence: z7.number().min(0).max(1).default(0.8).describe("Confidence score"),
1557
1563
  /**
1558
1564
  * Strategy used for routing
1559
1565
  */
1560
- strategy: RoutingStrategySchema.describe("Strategy used for this decision"),
1566
+ strategy: RoutingStrategySchema.default("llm-based").describe("Strategy used for this decision"),
1561
1567
  /**
1562
1568
  * Timestamp of the routing decision
1563
1569
  */
1564
- timestamp: z7.number().optional().describe("Timestamp of the decision")
1565
- });
1570
+ timestamp: z7.number().default(() => Date.now()).describe("Timestamp of the decision")
1571
+ }).refine(
1572
+ (data) => data.targetAgent || data.targetAgents && data.targetAgents.length > 0,
1573
+ { message: "Either targetAgent or targetAgents must be provided" }
1574
+ );
1566
1575
  var WorkerCapabilitiesSchema = z7.object({
1567
1576
  /**
1568
1577
  * Skills/capabilities the agent has
@@ -1830,16 +1839,33 @@ var DEFAULT_SUPERVISOR_SYSTEM_PROMPT = `You are a supervisor agent responsible f
1830
1839
  Your job is to:
1831
1840
  1. Analyze the current task and context
1832
1841
  2. Review available worker capabilities
1833
- 3. Select the most appropriate worker for the task
1842
+ 3. Select the most appropriate worker(s) for the task
1834
1843
  4. Provide clear reasoning for your decision
1835
1844
 
1836
- Respond with a JSON object containing:
1845
+ **IMPORTANT: You can route to MULTIPLE workers for parallel execution when:**
1846
+ - The task requires information from multiple domains (e.g., code + documentation)
1847
+ - Multiple workers have complementary expertise
1848
+ - Parallel execution would provide a more comprehensive answer
1849
+
1850
+ **Response Format:**
1851
+
1852
+ For SINGLE worker routing:
1837
1853
  {
1838
1854
  "targetAgent": "worker_id",
1839
1855
  "reasoning": "explanation of why this worker is best suited",
1840
1856
  "confidence": 0.0-1.0,
1841
1857
  "strategy": "llm-based"
1842
- }`;
1858
+ }
1859
+
1860
+ For PARALLEL multi-worker routing:
1861
+ {
1862
+ "targetAgents": ["worker_id_1", "worker_id_2", ...],
1863
+ "reasoning": "explanation of why these workers should work in parallel",
1864
+ "confidence": 0.0-1.0,
1865
+ "strategy": "llm-based"
1866
+ }
1867
+
1868
+ Choose parallel routing when the task benefits from multiple perspectives or data sources.`;
1843
1869
  var llmBasedRouting = {
1844
1870
  name: "llm-based",
1845
1871
  async route(state, config) {
@@ -1862,7 +1888,7 @@ var llmBasedRouting = {
1862
1888
  Available workers:
1863
1889
  ${workerInfo}
1864
1890
 
1865
- Select the best worker for this task and explain your reasoning.`;
1891
+ Select the best worker(s) for this task and explain your reasoning.`;
1866
1892
  const conversationHistory = [];
1867
1893
  let attempt = 0;
1868
1894
  while (attempt < maxRetries) {
@@ -1884,19 +1910,33 @@ Select the best worker for this task and explain your reasoning.`;
1884
1910
  attempt++;
1885
1911
  continue;
1886
1912
  }
1887
- const content = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
1888
- try {
1889
- const decision = JSON.parse(content);
1890
- return {
1891
- targetAgent: decision.targetAgent,
1892
- reasoning: decision.reasoning,
1893
- confidence: decision.confidence,
1894
- strategy: "llm-based",
1895
- timestamp: Date.now()
1896
- };
1897
- } catch (error) {
1898
- throw new Error(`Failed to parse routing decision from LLM: ${error}`);
1913
+ let decision;
1914
+ if (response && typeof response === "object" && ("targetAgent" in response || "targetAgents" in response)) {
1915
+ decision = response;
1916
+ } else if (response.content) {
1917
+ if (typeof response.content === "string") {
1918
+ try {
1919
+ decision = JSON.parse(response.content);
1920
+ } catch (error) {
1921
+ throw new Error(`Failed to parse routing decision from LLM. Expected JSON but got: ${response.content}`);
1922
+ }
1923
+ } else if (typeof response.content === "object") {
1924
+ decision = response.content;
1925
+ } else {
1926
+ throw new Error(`Unexpected response content type: ${typeof response.content}`);
1927
+ }
1928
+ } else {
1929
+ throw new Error(`Unexpected response format: ${JSON.stringify(response)}`);
1899
1930
  }
1931
+ const result = {
1932
+ targetAgent: decision.targetAgent,
1933
+ targetAgents: decision.targetAgents,
1934
+ reasoning: decision.reasoning,
1935
+ confidence: decision.confidence,
1936
+ strategy: "llm-based",
1937
+ timestamp: Date.now()
1938
+ };
1939
+ return result;
1900
1940
  }
1901
1941
  throw new Error(`Max tool retries (${maxRetries}) exceeded without routing decision`);
1902
1942
  }
@@ -1912,6 +1952,7 @@ var roundRobinRouting = {
1912
1952
  const targetAgent = availableWorkers[lastRoutingIndex];
1913
1953
  return {
1914
1954
  targetAgent,
1955
+ targetAgents: null,
1915
1956
  reasoning: `Round-robin selection: worker ${lastRoutingIndex + 1} of ${availableWorkers.length}`,
1916
1957
  confidence: 1,
1917
1958
  strategy: "round-robin",
@@ -1941,6 +1982,7 @@ var skillBasedRouting = {
1941
1982
  }
1942
1983
  return {
1943
1984
  targetAgent: firstAvailable[0],
1985
+ targetAgents: null,
1944
1986
  reasoning: "No skill matches found, using first available worker",
1945
1987
  confidence: 0.5,
1946
1988
  strategy: "skill-based",
@@ -1951,6 +1993,7 @@ var skillBasedRouting = {
1951
1993
  const confidence = Math.min(best.score / 5, 1);
1952
1994
  return {
1953
1995
  targetAgent: best.id,
1996
+ targetAgents: null,
1954
1997
  reasoning: `Best skill match with score ${best.score} (skills: ${best.skills.join(", ")})`,
1955
1998
  confidence,
1956
1999
  strategy: "skill-based",
@@ -1970,6 +2013,7 @@ var loadBalancedRouting = {
1970
2013
  const confidence = targetWorker.workload === 0 ? 1 : Math.max(0.5, 1 - targetWorker.workload / (avgWorkload * 2));
1971
2014
  return {
1972
2015
  targetAgent: targetWorker.id,
2016
+ targetAgents: null,
1973
2017
  reasoning: `Lowest workload: ${targetWorker.workload} tasks (avg: ${avgWorkload.toFixed(1)})`,
1974
2018
  confidence,
1975
2019
  strategy: "load-balanced",
@@ -2025,10 +2069,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2025
2069
  );
2026
2070
  if (!currentAssignment) {
2027
2071
  logger.debug("No active assignment found", { workerId });
2028
- return {
2029
- currentAgent: "supervisor",
2030
- status: "routing"
2031
- };
2072
+ return {};
2032
2073
  }
2033
2074
  const result = await agent.invoke(
2034
2075
  {
@@ -2060,9 +2101,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2060
2101
  }
2061
2102
  };
2062
2103
  return {
2063
- completedTasks: [taskResult],
2064
- currentAgent: "supervisor",
2065
- status: "routing"
2104
+ completedTasks: [taskResult]
2066
2105
  };
2067
2106
  } catch (error) {
2068
2107
  if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
@@ -2133,7 +2172,7 @@ function createSupervisorNode(config) {
2133
2172
  };
2134
2173
  }
2135
2174
  const allCompleted = state.activeAssignments.every(
2136
- (assignment2) => state.completedTasks.some((task) => task.assignmentId === assignment2.id)
2175
+ (assignment) => state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2137
2176
  );
2138
2177
  if (allCompleted && state.activeAssignments.length > 0) {
2139
2178
  if (verbose) {
@@ -2146,20 +2185,29 @@ function createSupervisorNode(config) {
2146
2185
  }
2147
2186
  const routingImpl = getRoutingStrategy(strategy);
2148
2187
  const decision = await routingImpl.route(state, config);
2188
+ const targetAgents = decision.targetAgents && decision.targetAgents.length > 0 ? decision.targetAgents : decision.targetAgent ? [decision.targetAgent] : [];
2189
+ if (targetAgents.length === 0) {
2190
+ throw new Error("Routing decision must specify at least one target agent");
2191
+ }
2149
2192
  if (verbose) {
2150
- console.log(`[Supervisor] Routing to ${decision.targetAgent}: ${decision.reasoning}`);
2193
+ if (targetAgents.length === 1) {
2194
+ console.log(`[Supervisor] Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2195
+ } else {
2196
+ console.log(`[Supervisor] Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`);
2197
+ }
2151
2198
  }
2152
- const assignment = {
2199
+ const task = state.messages[state.messages.length - 1]?.content || state.input;
2200
+ const assignments = targetAgents.map((workerId) => ({
2153
2201
  id: `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2154
- workerId: decision.targetAgent,
2155
- task: state.messages[state.messages.length - 1]?.content || state.input,
2202
+ workerId,
2203
+ task,
2156
2204
  priority: 5,
2157
2205
  assignedAt: Date.now()
2158
- };
2159
- const message = {
2206
+ }));
2207
+ const messages = assignments.map((assignment) => ({
2160
2208
  id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2161
2209
  from: "supervisor",
2162
- to: [decision.targetAgent],
2210
+ to: [assignment.workerId],
2163
2211
  type: "task_assignment",
2164
2212
  content: assignment.task,
2165
2213
  timestamp: Date.now(),
@@ -2167,13 +2215,15 @@ function createSupervisorNode(config) {
2167
2215
  assignmentId: assignment.id,
2168
2216
  priority: assignment.priority
2169
2217
  }
2170
- };
2218
+ }));
2171
2219
  return {
2172
- currentAgent: decision.targetAgent,
2220
+ currentAgent: targetAgents.join(","),
2221
+ // Store all agents (for backward compat)
2173
2222
  status: "executing",
2174
2223
  routingHistory: [decision],
2175
- activeAssignments: [assignment],
2176
- messages: [message],
2224
+ activeAssignments: assignments,
2225
+ // Multiple assignments for parallel execution!
2226
+ messages,
2177
2227
  iteration: state.iteration + 1
2178
2228
  };
2179
2229
  } catch (error) {
@@ -2208,10 +2258,7 @@ function createWorkerNode(config) {
2208
2258
  if (verbose) {
2209
2259
  console.log(`[Worker:${id}] No active assignment found`);
2210
2260
  }
2211
- return {
2212
- currentAgent: "supervisor",
2213
- status: "routing"
2214
- };
2261
+ return {};
2215
2262
  }
2216
2263
  if (executeFn) {
2217
2264
  if (verbose) {
@@ -2286,9 +2333,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2286
2333
  return {
2287
2334
  completedTasks: [taskResult],
2288
2335
  messages: [message],
2289
- workers: updatedWorkers,
2290
- currentAgent: "supervisor",
2291
- status: "routing"
2336
+ workers: updatedWorkers
2292
2337
  };
2293
2338
  } catch (error) {
2294
2339
  if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
@@ -2401,10 +2446,16 @@ function createMultiAgentSystem(config) {
2401
2446
  } = config;
2402
2447
  const workflow = new StateGraph4(MultiAgentState);
2403
2448
  let supervisorConfig = { ...supervisor, maxIterations, verbose };
2404
- if (supervisor.model && supervisor.tools && supervisor.tools.length > 0) {
2405
- const langchainTools = toLangChainTools3(supervisor.tools);
2406
- const modelWithTools = supervisor.model.bindTools(langchainTools);
2407
- supervisorConfig.model = modelWithTools;
2449
+ if (supervisor.model) {
2450
+ let configuredModel = supervisor.model;
2451
+ if (supervisor.strategy === "llm-based") {
2452
+ configuredModel = configuredModel.withStructuredOutput(RoutingDecisionSchema);
2453
+ }
2454
+ if (supervisor.tools && supervisor.tools.length > 0) {
2455
+ const langchainTools = toLangChainTools3(supervisor.tools);
2456
+ configuredModel = configuredModel.bindTools(langchainTools);
2457
+ }
2458
+ supervisorConfig.model = configuredModel;
2408
2459
  }
2409
2460
  const supervisorNode = createSupervisorNode(supervisorConfig);
2410
2461
  workflow.addNode("supervisor", supervisorNode);
@@ -2432,6 +2483,10 @@ function createMultiAgentSystem(config) {
2432
2483
  return "aggregator";
2433
2484
  }
2434
2485
  if (state.currentAgent && state.currentAgent !== "supervisor") {
2486
+ if (state.currentAgent.includes(",")) {
2487
+ const agents = state.currentAgent.split(",").map((a) => a.trim());
2488
+ return agents;
2489
+ }
2435
2490
  return state.currentAgent;
2436
2491
  }
2437
2492
  return "supervisor";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/patterns",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Agent patterns (ReAct, Planner-Executor) for AgentForge framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",