@agentforge/patterns 0.4.1 → 0.5.1
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 +114 -2
- package/dist/index.d.cts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +114 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2046,6 +2046,90 @@ function getRoutingStrategy(name) {
|
|
|
2046
2046
|
}
|
|
2047
2047
|
}
|
|
2048
2048
|
|
|
2049
|
+
// src/multi-agent/utils.ts
|
|
2050
|
+
function isReActAgent(obj) {
|
|
2051
|
+
return obj && typeof obj === "object" && typeof obj.invoke === "function" && typeof obj.stream === "function" && // Additional check to ensure it's not just any object with invoke/stream
|
|
2052
|
+
(obj.constructor?.name === "CompiledGraph" || obj.constructor?.name === "CompiledStateGraph");
|
|
2053
|
+
}
|
|
2054
|
+
function wrapReActAgent(workerId, agent, verbose = false) {
|
|
2055
|
+
return async (state) => {
|
|
2056
|
+
try {
|
|
2057
|
+
if (verbose) {
|
|
2058
|
+
console.log(`[ReActWrapper:${workerId}] Wrapping ReAct agent execution`);
|
|
2059
|
+
}
|
|
2060
|
+
const task = state.messages[state.messages.length - 1]?.content || state.input;
|
|
2061
|
+
if (verbose) {
|
|
2062
|
+
console.log(`[ReActWrapper:${workerId}] Task:`, task.substring(0, 100) + "...");
|
|
2063
|
+
}
|
|
2064
|
+
const currentAssignment = state.activeAssignments.find(
|
|
2065
|
+
(assignment) => assignment.workerId === workerId && !state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
|
|
2066
|
+
);
|
|
2067
|
+
if (!currentAssignment) {
|
|
2068
|
+
if (verbose) {
|
|
2069
|
+
console.log(`[ReActWrapper:${workerId}] No active assignment found`);
|
|
2070
|
+
}
|
|
2071
|
+
return {
|
|
2072
|
+
currentAgent: "supervisor",
|
|
2073
|
+
status: "routing"
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
const result = await agent.invoke({
|
|
2077
|
+
messages: [{ role: "user", content: task }]
|
|
2078
|
+
});
|
|
2079
|
+
const response = result.messages?.[result.messages.length - 1]?.content || "No response";
|
|
2080
|
+
if (verbose) {
|
|
2081
|
+
console.log(`[ReActWrapper:${workerId}] Response:`, response.substring(0, 100) + "...");
|
|
2082
|
+
}
|
|
2083
|
+
const toolsUsed = result.actions?.map((action) => action.name).filter(Boolean) || [];
|
|
2084
|
+
const uniqueTools = [...new Set(toolsUsed)];
|
|
2085
|
+
if (verbose && uniqueTools.length > 0) {
|
|
2086
|
+
console.log(`[ReActWrapper:${workerId}] Tools used:`, uniqueTools.join(", "));
|
|
2087
|
+
}
|
|
2088
|
+
const taskResult = {
|
|
2089
|
+
assignmentId: currentAssignment.id,
|
|
2090
|
+
workerId,
|
|
2091
|
+
result: response,
|
|
2092
|
+
completedAt: Date.now(),
|
|
2093
|
+
success: true,
|
|
2094
|
+
metadata: {
|
|
2095
|
+
agent_type: "react",
|
|
2096
|
+
iterations: result.iteration || 0,
|
|
2097
|
+
tools_used: uniqueTools
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
return {
|
|
2101
|
+
completedTasks: [taskResult],
|
|
2102
|
+
currentAgent: "supervisor",
|
|
2103
|
+
status: "routing"
|
|
2104
|
+
};
|
|
2105
|
+
} catch (error) {
|
|
2106
|
+
console.error(`[ReActWrapper:${workerId}] Error:`, error);
|
|
2107
|
+
const currentAssignment = state.activeAssignments.find(
|
|
2108
|
+
(assignment) => assignment.workerId === workerId
|
|
2109
|
+
);
|
|
2110
|
+
if (currentAssignment) {
|
|
2111
|
+
const errorResult = {
|
|
2112
|
+
assignmentId: currentAssignment.id,
|
|
2113
|
+
workerId,
|
|
2114
|
+
success: false,
|
|
2115
|
+
result: "",
|
|
2116
|
+
error: error instanceof Error ? error.message : "Unknown error in ReAct agent",
|
|
2117
|
+
completedAt: Date.now()
|
|
2118
|
+
};
|
|
2119
|
+
return {
|
|
2120
|
+
completedTasks: [errorResult],
|
|
2121
|
+
currentAgent: "supervisor",
|
|
2122
|
+
status: "routing"
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
return {
|
|
2126
|
+
status: "failed",
|
|
2127
|
+
error: error instanceof Error ? error.message : `Unknown error in ReAct wrapper for ${workerId}`
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2049
2133
|
// src/multi-agent/nodes.ts
|
|
2050
2134
|
var import_messages5 = require("@langchain/core/messages");
|
|
2051
2135
|
var import_core7 = require("@agentforge/core");
|
|
@@ -2139,7 +2223,8 @@ function createWorkerNode(config) {
|
|
|
2139
2223
|
tools = [],
|
|
2140
2224
|
systemPrompt,
|
|
2141
2225
|
verbose = false,
|
|
2142
|
-
executeFn
|
|
2226
|
+
executeFn,
|
|
2227
|
+
agent
|
|
2143
2228
|
} = config;
|
|
2144
2229
|
return async (state) => {
|
|
2145
2230
|
try {
|
|
@@ -2159,10 +2244,26 @@ function createWorkerNode(config) {
|
|
|
2159
2244
|
};
|
|
2160
2245
|
}
|
|
2161
2246
|
if (executeFn) {
|
|
2247
|
+
if (verbose) {
|
|
2248
|
+
console.log(`[Worker:${id}] Using custom executeFn`);
|
|
2249
|
+
}
|
|
2162
2250
|
return await executeFn(state);
|
|
2163
2251
|
}
|
|
2252
|
+
if (agent) {
|
|
2253
|
+
if (isReActAgent(agent)) {
|
|
2254
|
+
if (verbose) {
|
|
2255
|
+
console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
|
|
2256
|
+
}
|
|
2257
|
+
const wrappedFn = wrapReActAgent(id, agent, verbose);
|
|
2258
|
+
return await wrappedFn(state);
|
|
2259
|
+
} else {
|
|
2260
|
+
console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2164
2263
|
if (!model) {
|
|
2165
|
-
throw new Error(
|
|
2264
|
+
throw new Error(
|
|
2265
|
+
`Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
|
|
2266
|
+
);
|
|
2166
2267
|
}
|
|
2167
2268
|
const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
|
|
2168
2269
|
Skills: ${capabilities.skills.join(", ")}
|
|
@@ -2386,6 +2487,17 @@ function createMultiAgentSystem(config) {
|
|
|
2386
2487
|
};
|
|
2387
2488
|
return originalInvoke(mergedInput, config2);
|
|
2388
2489
|
};
|
|
2490
|
+
const originalStream = compiled.stream.bind(compiled);
|
|
2491
|
+
compiled.stream = async function(input, config2) {
|
|
2492
|
+
const mergedInput = {
|
|
2493
|
+
...input,
|
|
2494
|
+
workers: {
|
|
2495
|
+
...workerCapabilities,
|
|
2496
|
+
...input.workers || {}
|
|
2497
|
+
}
|
|
2498
|
+
};
|
|
2499
|
+
return originalStream(mergedInput, config2);
|
|
2500
|
+
};
|
|
2389
2501
|
return compiled;
|
|
2390
2502
|
}
|
|
2391
2503
|
var MultiAgentSystemBuilder = class {
|
package/dist/index.d.cts
CHANGED
|
@@ -2313,8 +2313,34 @@ interface WorkerConfig {
|
|
|
2313
2313
|
verbose?: boolean;
|
|
2314
2314
|
/**
|
|
2315
2315
|
* Custom execution function
|
|
2316
|
+
*
|
|
2317
|
+
* If provided, this function will be used to execute tasks for this worker.
|
|
2318
|
+
* Takes precedence over the `agent` property.
|
|
2316
2319
|
*/
|
|
2317
2320
|
executeFn?: (state: MultiAgentStateType) => Promise<Partial<MultiAgentStateType>>;
|
|
2321
|
+
/**
|
|
2322
|
+
* ReAct agent instance
|
|
2323
|
+
*
|
|
2324
|
+
* If provided, the Multi-Agent pattern will automatically wrap this ReAct agent
|
|
2325
|
+
* to work as a worker. The agent should be a compiled LangGraph StateGraph
|
|
2326
|
+
* (e.g., created with `createReActAgent()`).
|
|
2327
|
+
*
|
|
2328
|
+
* Note: `executeFn` takes precedence over `agent` if both are provided.
|
|
2329
|
+
*
|
|
2330
|
+
* @example
|
|
2331
|
+
* ```typescript
|
|
2332
|
+
* const hrAgent = createReActAgent({ model, tools, systemPrompt });
|
|
2333
|
+
*
|
|
2334
|
+
* const system = createMultiAgentSystem({
|
|
2335
|
+
* workers: [{
|
|
2336
|
+
* id: 'hr',
|
|
2337
|
+
* capabilities: { skills: ['hr'], ... },
|
|
2338
|
+
* agent: hrAgent, // Automatically wrapped!
|
|
2339
|
+
* }]
|
|
2340
|
+
* });
|
|
2341
|
+
* ```
|
|
2342
|
+
*/
|
|
2343
|
+
agent?: CompiledStateGraph<any, any>;
|
|
2318
2344
|
}
|
|
2319
2345
|
/**
|
|
2320
2346
|
* Configuration for the aggregator node
|
package/dist/index.d.ts
CHANGED
|
@@ -2313,8 +2313,34 @@ interface WorkerConfig {
|
|
|
2313
2313
|
verbose?: boolean;
|
|
2314
2314
|
/**
|
|
2315
2315
|
* Custom execution function
|
|
2316
|
+
*
|
|
2317
|
+
* If provided, this function will be used to execute tasks for this worker.
|
|
2318
|
+
* Takes precedence over the `agent` property.
|
|
2316
2319
|
*/
|
|
2317
2320
|
executeFn?: (state: MultiAgentStateType) => Promise<Partial<MultiAgentStateType>>;
|
|
2321
|
+
/**
|
|
2322
|
+
* ReAct agent instance
|
|
2323
|
+
*
|
|
2324
|
+
* If provided, the Multi-Agent pattern will automatically wrap this ReAct agent
|
|
2325
|
+
* to work as a worker. The agent should be a compiled LangGraph StateGraph
|
|
2326
|
+
* (e.g., created with `createReActAgent()`).
|
|
2327
|
+
*
|
|
2328
|
+
* Note: `executeFn` takes precedence over `agent` if both are provided.
|
|
2329
|
+
*
|
|
2330
|
+
* @example
|
|
2331
|
+
* ```typescript
|
|
2332
|
+
* const hrAgent = createReActAgent({ model, tools, systemPrompt });
|
|
2333
|
+
*
|
|
2334
|
+
* const system = createMultiAgentSystem({
|
|
2335
|
+
* workers: [{
|
|
2336
|
+
* id: 'hr',
|
|
2337
|
+
* capabilities: { skills: ['hr'], ... },
|
|
2338
|
+
* agent: hrAgent, // Automatically wrapped!
|
|
2339
|
+
* }]
|
|
2340
|
+
* });
|
|
2341
|
+
* ```
|
|
2342
|
+
*/
|
|
2343
|
+
agent?: CompiledStateGraph<any, any>;
|
|
2318
2344
|
}
|
|
2319
2345
|
/**
|
|
2320
2346
|
* Configuration for the aggregator node
|
package/dist/index.js
CHANGED
|
@@ -1947,6 +1947,90 @@ function getRoutingStrategy(name) {
|
|
|
1947
1947
|
}
|
|
1948
1948
|
}
|
|
1949
1949
|
|
|
1950
|
+
// src/multi-agent/utils.ts
|
|
1951
|
+
function isReActAgent(obj) {
|
|
1952
|
+
return obj && typeof obj === "object" && typeof obj.invoke === "function" && typeof obj.stream === "function" && // Additional check to ensure it's not just any object with invoke/stream
|
|
1953
|
+
(obj.constructor?.name === "CompiledGraph" || obj.constructor?.name === "CompiledStateGraph");
|
|
1954
|
+
}
|
|
1955
|
+
function wrapReActAgent(workerId, agent, verbose = false) {
|
|
1956
|
+
return async (state) => {
|
|
1957
|
+
try {
|
|
1958
|
+
if (verbose) {
|
|
1959
|
+
console.log(`[ReActWrapper:${workerId}] Wrapping ReAct agent execution`);
|
|
1960
|
+
}
|
|
1961
|
+
const task = state.messages[state.messages.length - 1]?.content || state.input;
|
|
1962
|
+
if (verbose) {
|
|
1963
|
+
console.log(`[ReActWrapper:${workerId}] Task:`, task.substring(0, 100) + "...");
|
|
1964
|
+
}
|
|
1965
|
+
const currentAssignment = state.activeAssignments.find(
|
|
1966
|
+
(assignment) => assignment.workerId === workerId && !state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
|
|
1967
|
+
);
|
|
1968
|
+
if (!currentAssignment) {
|
|
1969
|
+
if (verbose) {
|
|
1970
|
+
console.log(`[ReActWrapper:${workerId}] No active assignment found`);
|
|
1971
|
+
}
|
|
1972
|
+
return {
|
|
1973
|
+
currentAgent: "supervisor",
|
|
1974
|
+
status: "routing"
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
const result = await agent.invoke({
|
|
1978
|
+
messages: [{ role: "user", content: task }]
|
|
1979
|
+
});
|
|
1980
|
+
const response = result.messages?.[result.messages.length - 1]?.content || "No response";
|
|
1981
|
+
if (verbose) {
|
|
1982
|
+
console.log(`[ReActWrapper:${workerId}] Response:`, response.substring(0, 100) + "...");
|
|
1983
|
+
}
|
|
1984
|
+
const toolsUsed = result.actions?.map((action) => action.name).filter(Boolean) || [];
|
|
1985
|
+
const uniqueTools = [...new Set(toolsUsed)];
|
|
1986
|
+
if (verbose && uniqueTools.length > 0) {
|
|
1987
|
+
console.log(`[ReActWrapper:${workerId}] Tools used:`, uniqueTools.join(", "));
|
|
1988
|
+
}
|
|
1989
|
+
const taskResult = {
|
|
1990
|
+
assignmentId: currentAssignment.id,
|
|
1991
|
+
workerId,
|
|
1992
|
+
result: response,
|
|
1993
|
+
completedAt: Date.now(),
|
|
1994
|
+
success: true,
|
|
1995
|
+
metadata: {
|
|
1996
|
+
agent_type: "react",
|
|
1997
|
+
iterations: result.iteration || 0,
|
|
1998
|
+
tools_used: uniqueTools
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
return {
|
|
2002
|
+
completedTasks: [taskResult],
|
|
2003
|
+
currentAgent: "supervisor",
|
|
2004
|
+
status: "routing"
|
|
2005
|
+
};
|
|
2006
|
+
} catch (error) {
|
|
2007
|
+
console.error(`[ReActWrapper:${workerId}] Error:`, error);
|
|
2008
|
+
const currentAssignment = state.activeAssignments.find(
|
|
2009
|
+
(assignment) => assignment.workerId === workerId
|
|
2010
|
+
);
|
|
2011
|
+
if (currentAssignment) {
|
|
2012
|
+
const errorResult = {
|
|
2013
|
+
assignmentId: currentAssignment.id,
|
|
2014
|
+
workerId,
|
|
2015
|
+
success: false,
|
|
2016
|
+
result: "",
|
|
2017
|
+
error: error instanceof Error ? error.message : "Unknown error in ReAct agent",
|
|
2018
|
+
completedAt: Date.now()
|
|
2019
|
+
};
|
|
2020
|
+
return {
|
|
2021
|
+
completedTasks: [errorResult],
|
|
2022
|
+
currentAgent: "supervisor",
|
|
2023
|
+
status: "routing"
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
return {
|
|
2027
|
+
status: "failed",
|
|
2028
|
+
error: error instanceof Error ? error.message : `Unknown error in ReAct wrapper for ${workerId}`
|
|
2029
|
+
};
|
|
2030
|
+
}
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
|
|
1950
2034
|
// src/multi-agent/nodes.ts
|
|
1951
2035
|
import { HumanMessage as HumanMessage5, SystemMessage as SystemMessage5 } from "@langchain/core/messages";
|
|
1952
2036
|
import { toLangChainTools as toLangChainTools2 } from "@agentforge/core";
|
|
@@ -2040,7 +2124,8 @@ function createWorkerNode(config) {
|
|
|
2040
2124
|
tools = [],
|
|
2041
2125
|
systemPrompt,
|
|
2042
2126
|
verbose = false,
|
|
2043
|
-
executeFn
|
|
2127
|
+
executeFn,
|
|
2128
|
+
agent
|
|
2044
2129
|
} = config;
|
|
2045
2130
|
return async (state) => {
|
|
2046
2131
|
try {
|
|
@@ -2060,10 +2145,26 @@ function createWorkerNode(config) {
|
|
|
2060
2145
|
};
|
|
2061
2146
|
}
|
|
2062
2147
|
if (executeFn) {
|
|
2148
|
+
if (verbose) {
|
|
2149
|
+
console.log(`[Worker:${id}] Using custom executeFn`);
|
|
2150
|
+
}
|
|
2063
2151
|
return await executeFn(state);
|
|
2064
2152
|
}
|
|
2153
|
+
if (agent) {
|
|
2154
|
+
if (isReActAgent(agent)) {
|
|
2155
|
+
if (verbose) {
|
|
2156
|
+
console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
|
|
2157
|
+
}
|
|
2158
|
+
const wrappedFn = wrapReActAgent(id, agent, verbose);
|
|
2159
|
+
return await wrappedFn(state);
|
|
2160
|
+
} else {
|
|
2161
|
+
console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2065
2164
|
if (!model) {
|
|
2066
|
-
throw new Error(
|
|
2165
|
+
throw new Error(
|
|
2166
|
+
`Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
|
|
2167
|
+
);
|
|
2067
2168
|
}
|
|
2068
2169
|
const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
|
|
2069
2170
|
Skills: ${capabilities.skills.join(", ")}
|
|
@@ -2287,6 +2388,17 @@ function createMultiAgentSystem(config) {
|
|
|
2287
2388
|
};
|
|
2288
2389
|
return originalInvoke(mergedInput, config2);
|
|
2289
2390
|
};
|
|
2391
|
+
const originalStream = compiled.stream.bind(compiled);
|
|
2392
|
+
compiled.stream = async function(input, config2) {
|
|
2393
|
+
const mergedInput = {
|
|
2394
|
+
...input,
|
|
2395
|
+
workers: {
|
|
2396
|
+
...workerCapabilities,
|
|
2397
|
+
...input.workers || {}
|
|
2398
|
+
}
|
|
2399
|
+
};
|
|
2400
|
+
return originalStream(mergedInput, config2);
|
|
2401
|
+
};
|
|
2290
2402
|
return compiled;
|
|
2291
2403
|
}
|
|
2292
2404
|
var MultiAgentSystemBuilder = class {
|