@agentforge/patterns 0.6.1 → 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 +111 -53
- package/dist/index.d.cts +72 -24
- package/dist/index.d.ts +72 -24
- package/dist/index.js +111 -53
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -873,6 +873,9 @@ function createExecutorNode(config) {
|
|
|
873
873
|
result = { message: "Step completed without tool execution" };
|
|
874
874
|
}
|
|
875
875
|
} catch (execError) {
|
|
876
|
+
if (execError && typeof execError === "object" && "constructor" in execError && execError.constructor.name === "GraphInterrupt") {
|
|
877
|
+
throw execError;
|
|
878
|
+
}
|
|
876
879
|
success = false;
|
|
877
880
|
error = execError instanceof Error ? execError.message : "Unknown execution error";
|
|
878
881
|
result = null;
|
|
@@ -1639,26 +1642,35 @@ var RoutingStrategySchema = import_zod7.z.enum([
|
|
|
1639
1642
|
]);
|
|
1640
1643
|
var RoutingDecisionSchema = import_zod7.z.object({
|
|
1641
1644
|
/**
|
|
1642
|
-
* Target agent to route to
|
|
1645
|
+
* Target agent to route to (single agent routing)
|
|
1646
|
+
* @deprecated Use targetAgents for parallel routing support
|
|
1647
|
+
*/
|
|
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
|
|
1643
1652
|
*/
|
|
1644
|
-
|
|
1653
|
+
targetAgents: import_zod7.z.array(import_zod7.z.string()).nullable().default(null).describe("Agents to route the task to (parallel routing)"),
|
|
1645
1654
|
/**
|
|
1646
1655
|
* Reasoning for the routing decision
|
|
1647
1656
|
*/
|
|
1648
|
-
reasoning: import_zod7.z.string().
|
|
1657
|
+
reasoning: import_zod7.z.string().default("").describe("Explanation for routing decision"),
|
|
1649
1658
|
/**
|
|
1650
1659
|
* Confidence in the routing decision (0-1)
|
|
1651
1660
|
*/
|
|
1652
|
-
confidence: import_zod7.z.number().min(0).max(1).
|
|
1661
|
+
confidence: import_zod7.z.number().min(0).max(1).default(0.8).describe("Confidence score"),
|
|
1653
1662
|
/**
|
|
1654
1663
|
* Strategy used for routing
|
|
1655
1664
|
*/
|
|
1656
|
-
strategy: RoutingStrategySchema.describe("Strategy used for this decision"),
|
|
1665
|
+
strategy: RoutingStrategySchema.default("llm-based").describe("Strategy used for this decision"),
|
|
1657
1666
|
/**
|
|
1658
1667
|
* Timestamp of the routing decision
|
|
1659
1668
|
*/
|
|
1660
|
-
timestamp: import_zod7.z.number().
|
|
1661
|
-
})
|
|
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
|
+
);
|
|
1662
1674
|
var WorkerCapabilitiesSchema = import_zod7.z.object({
|
|
1663
1675
|
/**
|
|
1664
1676
|
* Skills/capabilities the agent has
|
|
@@ -1926,16 +1938,33 @@ var DEFAULT_SUPERVISOR_SYSTEM_PROMPT = `You are a supervisor agent responsible f
|
|
|
1926
1938
|
Your job is to:
|
|
1927
1939
|
1. Analyze the current task and context
|
|
1928
1940
|
2. Review available worker capabilities
|
|
1929
|
-
3. Select the most appropriate worker for the task
|
|
1941
|
+
3. Select the most appropriate worker(s) for the task
|
|
1930
1942
|
4. Provide clear reasoning for your decision
|
|
1931
1943
|
|
|
1932
|
-
|
|
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:
|
|
1933
1952
|
{
|
|
1934
1953
|
"targetAgent": "worker_id",
|
|
1935
1954
|
"reasoning": "explanation of why this worker is best suited",
|
|
1936
1955
|
"confidence": 0.0-1.0,
|
|
1937
1956
|
"strategy": "llm-based"
|
|
1938
|
-
}
|
|
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.`;
|
|
1939
1968
|
var llmBasedRouting = {
|
|
1940
1969
|
name: "llm-based",
|
|
1941
1970
|
async route(state, config) {
|
|
@@ -1958,7 +1987,7 @@ var llmBasedRouting = {
|
|
|
1958
1987
|
Available workers:
|
|
1959
1988
|
${workerInfo}
|
|
1960
1989
|
|
|
1961
|
-
Select the best worker for this task and explain your reasoning.`;
|
|
1990
|
+
Select the best worker(s) for this task and explain your reasoning.`;
|
|
1962
1991
|
const conversationHistory = [];
|
|
1963
1992
|
let attempt = 0;
|
|
1964
1993
|
while (attempt < maxRetries) {
|
|
@@ -1980,19 +2009,33 @@ Select the best worker for this task and explain your reasoning.`;
|
|
|
1980
2009
|
attempt++;
|
|
1981
2010
|
continue;
|
|
1982
2011
|
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
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)}`);
|
|
1995
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;
|
|
1996
2039
|
}
|
|
1997
2040
|
throw new Error(`Max tool retries (${maxRetries}) exceeded without routing decision`);
|
|
1998
2041
|
}
|
|
@@ -2008,6 +2051,7 @@ var roundRobinRouting = {
|
|
|
2008
2051
|
const targetAgent = availableWorkers[lastRoutingIndex];
|
|
2009
2052
|
return {
|
|
2010
2053
|
targetAgent,
|
|
2054
|
+
targetAgents: null,
|
|
2011
2055
|
reasoning: `Round-robin selection: worker ${lastRoutingIndex + 1} of ${availableWorkers.length}`,
|
|
2012
2056
|
confidence: 1,
|
|
2013
2057
|
strategy: "round-robin",
|
|
@@ -2037,6 +2081,7 @@ var skillBasedRouting = {
|
|
|
2037
2081
|
}
|
|
2038
2082
|
return {
|
|
2039
2083
|
targetAgent: firstAvailable[0],
|
|
2084
|
+
targetAgents: null,
|
|
2040
2085
|
reasoning: "No skill matches found, using first available worker",
|
|
2041
2086
|
confidence: 0.5,
|
|
2042
2087
|
strategy: "skill-based",
|
|
@@ -2047,6 +2092,7 @@ var skillBasedRouting = {
|
|
|
2047
2092
|
const confidence = Math.min(best.score / 5, 1);
|
|
2048
2093
|
return {
|
|
2049
2094
|
targetAgent: best.id,
|
|
2095
|
+
targetAgents: null,
|
|
2050
2096
|
reasoning: `Best skill match with score ${best.score} (skills: ${best.skills.join(", ")})`,
|
|
2051
2097
|
confidence,
|
|
2052
2098
|
strategy: "skill-based",
|
|
@@ -2066,6 +2112,7 @@ var loadBalancedRouting = {
|
|
|
2066
2112
|
const confidence = targetWorker.workload === 0 ? 1 : Math.max(0.5, 1 - targetWorker.workload / (avgWorkload * 2));
|
|
2067
2113
|
return {
|
|
2068
2114
|
targetAgent: targetWorker.id,
|
|
2115
|
+
targetAgents: null,
|
|
2069
2116
|
reasoning: `Lowest workload: ${targetWorker.workload} tasks (avg: ${avgWorkload.toFixed(1)})`,
|
|
2070
2117
|
confidence,
|
|
2071
2118
|
strategy: "load-balanced",
|
|
@@ -2121,10 +2168,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
|
|
|
2121
2168
|
);
|
|
2122
2169
|
if (!currentAssignment) {
|
|
2123
2170
|
logger.debug("No active assignment found", { workerId });
|
|
2124
|
-
return {
|
|
2125
|
-
currentAgent: "supervisor",
|
|
2126
|
-
status: "routing"
|
|
2127
|
-
};
|
|
2171
|
+
return {};
|
|
2128
2172
|
}
|
|
2129
2173
|
const result = await agent.invoke(
|
|
2130
2174
|
{
|
|
@@ -2156,9 +2200,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
|
|
|
2156
2200
|
}
|
|
2157
2201
|
};
|
|
2158
2202
|
return {
|
|
2159
|
-
completedTasks: [taskResult]
|
|
2160
|
-
currentAgent: "supervisor",
|
|
2161
|
-
status: "routing"
|
|
2203
|
+
completedTasks: [taskResult]
|
|
2162
2204
|
};
|
|
2163
2205
|
} catch (error) {
|
|
2164
2206
|
if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
|
|
@@ -2229,7 +2271,7 @@ function createSupervisorNode(config) {
|
|
|
2229
2271
|
};
|
|
2230
2272
|
}
|
|
2231
2273
|
const allCompleted = state.activeAssignments.every(
|
|
2232
|
-
(
|
|
2274
|
+
(assignment) => state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
|
|
2233
2275
|
);
|
|
2234
2276
|
if (allCompleted && state.activeAssignments.length > 0) {
|
|
2235
2277
|
if (verbose) {
|
|
@@ -2242,20 +2284,29 @@ function createSupervisorNode(config) {
|
|
|
2242
2284
|
}
|
|
2243
2285
|
const routingImpl = getRoutingStrategy(strategy);
|
|
2244
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
|
+
}
|
|
2245
2291
|
if (verbose) {
|
|
2246
|
-
|
|
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
|
+
}
|
|
2247
2297
|
}
|
|
2248
|
-
const
|
|
2298
|
+
const task = state.messages[state.messages.length - 1]?.content || state.input;
|
|
2299
|
+
const assignments = targetAgents.map((workerId) => ({
|
|
2249
2300
|
id: `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
2250
|
-
workerId
|
|
2251
|
-
task
|
|
2301
|
+
workerId,
|
|
2302
|
+
task,
|
|
2252
2303
|
priority: 5,
|
|
2253
2304
|
assignedAt: Date.now()
|
|
2254
|
-
};
|
|
2255
|
-
const
|
|
2305
|
+
}));
|
|
2306
|
+
const messages = assignments.map((assignment) => ({
|
|
2256
2307
|
id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
2257
2308
|
from: "supervisor",
|
|
2258
|
-
to: [
|
|
2309
|
+
to: [assignment.workerId],
|
|
2259
2310
|
type: "task_assignment",
|
|
2260
2311
|
content: assignment.task,
|
|
2261
2312
|
timestamp: Date.now(),
|
|
@@ -2263,13 +2314,15 @@ function createSupervisorNode(config) {
|
|
|
2263
2314
|
assignmentId: assignment.id,
|
|
2264
2315
|
priority: assignment.priority
|
|
2265
2316
|
}
|
|
2266
|
-
};
|
|
2317
|
+
}));
|
|
2267
2318
|
return {
|
|
2268
|
-
currentAgent:
|
|
2319
|
+
currentAgent: targetAgents.join(","),
|
|
2320
|
+
// Store all agents (for backward compat)
|
|
2269
2321
|
status: "executing",
|
|
2270
2322
|
routingHistory: [decision],
|
|
2271
|
-
activeAssignments:
|
|
2272
|
-
|
|
2323
|
+
activeAssignments: assignments,
|
|
2324
|
+
// Multiple assignments for parallel execution!
|
|
2325
|
+
messages,
|
|
2273
2326
|
iteration: state.iteration + 1
|
|
2274
2327
|
};
|
|
2275
2328
|
} catch (error) {
|
|
@@ -2304,10 +2357,7 @@ function createWorkerNode(config) {
|
|
|
2304
2357
|
if (verbose) {
|
|
2305
2358
|
console.log(`[Worker:${id}] No active assignment found`);
|
|
2306
2359
|
}
|
|
2307
|
-
return {
|
|
2308
|
-
currentAgent: "supervisor",
|
|
2309
|
-
status: "routing"
|
|
2310
|
-
};
|
|
2360
|
+
return {};
|
|
2311
2361
|
}
|
|
2312
2362
|
if (executeFn) {
|
|
2313
2363
|
if (verbose) {
|
|
@@ -2382,9 +2432,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
|
|
|
2382
2432
|
return {
|
|
2383
2433
|
completedTasks: [taskResult],
|
|
2384
2434
|
messages: [message],
|
|
2385
|
-
workers: updatedWorkers
|
|
2386
|
-
currentAgent: "supervisor",
|
|
2387
|
-
status: "routing"
|
|
2435
|
+
workers: updatedWorkers
|
|
2388
2436
|
};
|
|
2389
2437
|
} catch (error) {
|
|
2390
2438
|
if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
|
|
@@ -2497,10 +2545,16 @@ function createMultiAgentSystem(config) {
|
|
|
2497
2545
|
} = config;
|
|
2498
2546
|
const workflow = new import_langgraph4.StateGraph(MultiAgentState);
|
|
2499
2547
|
let supervisorConfig = { ...supervisor, maxIterations, verbose };
|
|
2500
|
-
if (supervisor.model
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
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;
|
|
2504
2558
|
}
|
|
2505
2559
|
const supervisorNode = createSupervisorNode(supervisorConfig);
|
|
2506
2560
|
workflow.addNode("supervisor", supervisorNode);
|
|
@@ -2528,6 +2582,10 @@ function createMultiAgentSystem(config) {
|
|
|
2528
2582
|
return "aggregator";
|
|
2529
2583
|
}
|
|
2530
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
|
+
}
|
|
2531
2589
|
return state.currentAgent;
|
|
2532
2590
|
}
|
|
2533
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.
|
|
1886
|
+
reasoning: z.ZodDefault<z.ZodString>;
|
|
1873
1887
|
/**
|
|
1874
1888
|
* Confidence in the routing decision (0-1)
|
|
1875
1889
|
*/
|
|
1876
|
-
confidence: z.
|
|
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.
|
|
1898
|
+
timestamp: z.ZodDefault<z.ZodNumber>;
|
|
1885
1899
|
}, "strip", z.ZodTypeAny, {
|
|
1886
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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\
|
|
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.
|
|
1886
|
+
reasoning: z.ZodDefault<z.ZodString>;
|
|
1873
1887
|
/**
|
|
1874
1888
|
* Confidence in the routing decision (0-1)
|
|
1875
1889
|
*/
|
|
1876
|
-
confidence: z.
|
|
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.
|
|
1898
|
+
timestamp: z.ZodDefault<z.ZodNumber>;
|
|
1885
1899
|
}, "strip", z.ZodTypeAny, {
|
|
1886
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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\
|
|
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
|
@@ -774,6 +774,9 @@ function createExecutorNode(config) {
|
|
|
774
774
|
result = { message: "Step completed without tool execution" };
|
|
775
775
|
}
|
|
776
776
|
} catch (execError) {
|
|
777
|
+
if (execError && typeof execError === "object" && "constructor" in execError && execError.constructor.name === "GraphInterrupt") {
|
|
778
|
+
throw execError;
|
|
779
|
+
}
|
|
777
780
|
success = false;
|
|
778
781
|
error = execError instanceof Error ? execError.message : "Unknown execution error";
|
|
779
782
|
result = null;
|
|
@@ -1540,26 +1543,35 @@ var RoutingStrategySchema = z7.enum([
|
|
|
1540
1543
|
]);
|
|
1541
1544
|
var RoutingDecisionSchema = z7.object({
|
|
1542
1545
|
/**
|
|
1543
|
-
* Target agent to route to
|
|
1546
|
+
* Target agent to route to (single agent routing)
|
|
1547
|
+
* @deprecated Use targetAgents for parallel routing support
|
|
1548
|
+
*/
|
|
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
|
|
1544
1553
|
*/
|
|
1545
|
-
|
|
1554
|
+
targetAgents: z7.array(z7.string()).nullable().default(null).describe("Agents to route the task to (parallel routing)"),
|
|
1546
1555
|
/**
|
|
1547
1556
|
* Reasoning for the routing decision
|
|
1548
1557
|
*/
|
|
1549
|
-
reasoning: z7.string().
|
|
1558
|
+
reasoning: z7.string().default("").describe("Explanation for routing decision"),
|
|
1550
1559
|
/**
|
|
1551
1560
|
* Confidence in the routing decision (0-1)
|
|
1552
1561
|
*/
|
|
1553
|
-
confidence: z7.number().min(0).max(1).
|
|
1562
|
+
confidence: z7.number().min(0).max(1).default(0.8).describe("Confidence score"),
|
|
1554
1563
|
/**
|
|
1555
1564
|
* Strategy used for routing
|
|
1556
1565
|
*/
|
|
1557
|
-
strategy: RoutingStrategySchema.describe("Strategy used for this decision"),
|
|
1566
|
+
strategy: RoutingStrategySchema.default("llm-based").describe("Strategy used for this decision"),
|
|
1558
1567
|
/**
|
|
1559
1568
|
* Timestamp of the routing decision
|
|
1560
1569
|
*/
|
|
1561
|
-
timestamp: z7.number().
|
|
1562
|
-
})
|
|
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
|
+
);
|
|
1563
1575
|
var WorkerCapabilitiesSchema = z7.object({
|
|
1564
1576
|
/**
|
|
1565
1577
|
* Skills/capabilities the agent has
|
|
@@ -1827,16 +1839,33 @@ var DEFAULT_SUPERVISOR_SYSTEM_PROMPT = `You are a supervisor agent responsible f
|
|
|
1827
1839
|
Your job is to:
|
|
1828
1840
|
1. Analyze the current task and context
|
|
1829
1841
|
2. Review available worker capabilities
|
|
1830
|
-
3. Select the most appropriate worker for the task
|
|
1842
|
+
3. Select the most appropriate worker(s) for the task
|
|
1831
1843
|
4. Provide clear reasoning for your decision
|
|
1832
1844
|
|
|
1833
|
-
|
|
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:
|
|
1834
1853
|
{
|
|
1835
1854
|
"targetAgent": "worker_id",
|
|
1836
1855
|
"reasoning": "explanation of why this worker is best suited",
|
|
1837
1856
|
"confidence": 0.0-1.0,
|
|
1838
1857
|
"strategy": "llm-based"
|
|
1839
|
-
}
|
|
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.`;
|
|
1840
1869
|
var llmBasedRouting = {
|
|
1841
1870
|
name: "llm-based",
|
|
1842
1871
|
async route(state, config) {
|
|
@@ -1859,7 +1888,7 @@ var llmBasedRouting = {
|
|
|
1859
1888
|
Available workers:
|
|
1860
1889
|
${workerInfo}
|
|
1861
1890
|
|
|
1862
|
-
Select the best worker for this task and explain your reasoning.`;
|
|
1891
|
+
Select the best worker(s) for this task and explain your reasoning.`;
|
|
1863
1892
|
const conversationHistory = [];
|
|
1864
1893
|
let attempt = 0;
|
|
1865
1894
|
while (attempt < maxRetries) {
|
|
@@ -1881,19 +1910,33 @@ Select the best worker for this task and explain your reasoning.`;
|
|
|
1881
1910
|
attempt++;
|
|
1882
1911
|
continue;
|
|
1883
1912
|
}
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
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)}`);
|
|
1896
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;
|
|
1897
1940
|
}
|
|
1898
1941
|
throw new Error(`Max tool retries (${maxRetries}) exceeded without routing decision`);
|
|
1899
1942
|
}
|
|
@@ -1909,6 +1952,7 @@ var roundRobinRouting = {
|
|
|
1909
1952
|
const targetAgent = availableWorkers[lastRoutingIndex];
|
|
1910
1953
|
return {
|
|
1911
1954
|
targetAgent,
|
|
1955
|
+
targetAgents: null,
|
|
1912
1956
|
reasoning: `Round-robin selection: worker ${lastRoutingIndex + 1} of ${availableWorkers.length}`,
|
|
1913
1957
|
confidence: 1,
|
|
1914
1958
|
strategy: "round-robin",
|
|
@@ -1938,6 +1982,7 @@ var skillBasedRouting = {
|
|
|
1938
1982
|
}
|
|
1939
1983
|
return {
|
|
1940
1984
|
targetAgent: firstAvailable[0],
|
|
1985
|
+
targetAgents: null,
|
|
1941
1986
|
reasoning: "No skill matches found, using first available worker",
|
|
1942
1987
|
confidence: 0.5,
|
|
1943
1988
|
strategy: "skill-based",
|
|
@@ -1948,6 +1993,7 @@ var skillBasedRouting = {
|
|
|
1948
1993
|
const confidence = Math.min(best.score / 5, 1);
|
|
1949
1994
|
return {
|
|
1950
1995
|
targetAgent: best.id,
|
|
1996
|
+
targetAgents: null,
|
|
1951
1997
|
reasoning: `Best skill match with score ${best.score} (skills: ${best.skills.join(", ")})`,
|
|
1952
1998
|
confidence,
|
|
1953
1999
|
strategy: "skill-based",
|
|
@@ -1967,6 +2013,7 @@ var loadBalancedRouting = {
|
|
|
1967
2013
|
const confidence = targetWorker.workload === 0 ? 1 : Math.max(0.5, 1 - targetWorker.workload / (avgWorkload * 2));
|
|
1968
2014
|
return {
|
|
1969
2015
|
targetAgent: targetWorker.id,
|
|
2016
|
+
targetAgents: null,
|
|
1970
2017
|
reasoning: `Lowest workload: ${targetWorker.workload} tasks (avg: ${avgWorkload.toFixed(1)})`,
|
|
1971
2018
|
confidence,
|
|
1972
2019
|
strategy: "load-balanced",
|
|
@@ -2022,10 +2069,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
|
|
|
2022
2069
|
);
|
|
2023
2070
|
if (!currentAssignment) {
|
|
2024
2071
|
logger.debug("No active assignment found", { workerId });
|
|
2025
|
-
return {
|
|
2026
|
-
currentAgent: "supervisor",
|
|
2027
|
-
status: "routing"
|
|
2028
|
-
};
|
|
2072
|
+
return {};
|
|
2029
2073
|
}
|
|
2030
2074
|
const result = await agent.invoke(
|
|
2031
2075
|
{
|
|
@@ -2057,9 +2101,7 @@ function wrapReActAgent(workerId, agent, verbose = false) {
|
|
|
2057
2101
|
}
|
|
2058
2102
|
};
|
|
2059
2103
|
return {
|
|
2060
|
-
completedTasks: [taskResult]
|
|
2061
|
-
currentAgent: "supervisor",
|
|
2062
|
-
status: "routing"
|
|
2104
|
+
completedTasks: [taskResult]
|
|
2063
2105
|
};
|
|
2064
2106
|
} catch (error) {
|
|
2065
2107
|
if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
|
|
@@ -2130,7 +2172,7 @@ function createSupervisorNode(config) {
|
|
|
2130
2172
|
};
|
|
2131
2173
|
}
|
|
2132
2174
|
const allCompleted = state.activeAssignments.every(
|
|
2133
|
-
(
|
|
2175
|
+
(assignment) => state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
|
|
2134
2176
|
);
|
|
2135
2177
|
if (allCompleted && state.activeAssignments.length > 0) {
|
|
2136
2178
|
if (verbose) {
|
|
@@ -2143,20 +2185,29 @@ function createSupervisorNode(config) {
|
|
|
2143
2185
|
}
|
|
2144
2186
|
const routingImpl = getRoutingStrategy(strategy);
|
|
2145
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
|
+
}
|
|
2146
2192
|
if (verbose) {
|
|
2147
|
-
|
|
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
|
+
}
|
|
2148
2198
|
}
|
|
2149
|
-
const
|
|
2199
|
+
const task = state.messages[state.messages.length - 1]?.content || state.input;
|
|
2200
|
+
const assignments = targetAgents.map((workerId) => ({
|
|
2150
2201
|
id: `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
2151
|
-
workerId
|
|
2152
|
-
task
|
|
2202
|
+
workerId,
|
|
2203
|
+
task,
|
|
2153
2204
|
priority: 5,
|
|
2154
2205
|
assignedAt: Date.now()
|
|
2155
|
-
};
|
|
2156
|
-
const
|
|
2206
|
+
}));
|
|
2207
|
+
const messages = assignments.map((assignment) => ({
|
|
2157
2208
|
id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
2158
2209
|
from: "supervisor",
|
|
2159
|
-
to: [
|
|
2210
|
+
to: [assignment.workerId],
|
|
2160
2211
|
type: "task_assignment",
|
|
2161
2212
|
content: assignment.task,
|
|
2162
2213
|
timestamp: Date.now(),
|
|
@@ -2164,13 +2215,15 @@ function createSupervisorNode(config) {
|
|
|
2164
2215
|
assignmentId: assignment.id,
|
|
2165
2216
|
priority: assignment.priority
|
|
2166
2217
|
}
|
|
2167
|
-
};
|
|
2218
|
+
}));
|
|
2168
2219
|
return {
|
|
2169
|
-
currentAgent:
|
|
2220
|
+
currentAgent: targetAgents.join(","),
|
|
2221
|
+
// Store all agents (for backward compat)
|
|
2170
2222
|
status: "executing",
|
|
2171
2223
|
routingHistory: [decision],
|
|
2172
|
-
activeAssignments:
|
|
2173
|
-
|
|
2224
|
+
activeAssignments: assignments,
|
|
2225
|
+
// Multiple assignments for parallel execution!
|
|
2226
|
+
messages,
|
|
2174
2227
|
iteration: state.iteration + 1
|
|
2175
2228
|
};
|
|
2176
2229
|
} catch (error) {
|
|
@@ -2205,10 +2258,7 @@ function createWorkerNode(config) {
|
|
|
2205
2258
|
if (verbose) {
|
|
2206
2259
|
console.log(`[Worker:${id}] No active assignment found`);
|
|
2207
2260
|
}
|
|
2208
|
-
return {
|
|
2209
|
-
currentAgent: "supervisor",
|
|
2210
|
-
status: "routing"
|
|
2211
|
-
};
|
|
2261
|
+
return {};
|
|
2212
2262
|
}
|
|
2213
2263
|
if (executeFn) {
|
|
2214
2264
|
if (verbose) {
|
|
@@ -2283,9 +2333,7 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
|
|
|
2283
2333
|
return {
|
|
2284
2334
|
completedTasks: [taskResult],
|
|
2285
2335
|
messages: [message],
|
|
2286
|
-
workers: updatedWorkers
|
|
2287
|
-
currentAgent: "supervisor",
|
|
2288
|
-
status: "routing"
|
|
2336
|
+
workers: updatedWorkers
|
|
2289
2337
|
};
|
|
2290
2338
|
} catch (error) {
|
|
2291
2339
|
if (error && typeof error === "object" && "constructor" in error && error.constructor.name === "GraphInterrupt") {
|
|
@@ -2398,10 +2446,16 @@ function createMultiAgentSystem(config) {
|
|
|
2398
2446
|
} = config;
|
|
2399
2447
|
const workflow = new StateGraph4(MultiAgentState);
|
|
2400
2448
|
let supervisorConfig = { ...supervisor, maxIterations, verbose };
|
|
2401
|
-
if (supervisor.model
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
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;
|
|
2405
2459
|
}
|
|
2406
2460
|
const supervisorNode = createSupervisorNode(supervisorConfig);
|
|
2407
2461
|
workflow.addNode("supervisor", supervisorNode);
|
|
@@ -2429,6 +2483,10 @@ function createMultiAgentSystem(config) {
|
|
|
2429
2483
|
return "aggregator";
|
|
2430
2484
|
}
|
|
2431
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
|
+
}
|
|
2432
2490
|
return state.currentAgent;
|
|
2433
2491
|
}
|
|
2434
2492
|
return "supervisor";
|