@agentforge/patterns 0.4.1 → 0.5.0
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 +97 -2
- package/dist/index.d.cts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +97 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2046,6 +2046,84 @@ 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 taskResult = {
|
|
2084
|
+
assignmentId: currentAssignment.id,
|
|
2085
|
+
workerId,
|
|
2086
|
+
result: response,
|
|
2087
|
+
completedAt: Date.now(),
|
|
2088
|
+
success: true,
|
|
2089
|
+
metadata: {
|
|
2090
|
+
agent_type: "react",
|
|
2091
|
+
iterations: result.iteration || 0
|
|
2092
|
+
}
|
|
2093
|
+
};
|
|
2094
|
+
return {
|
|
2095
|
+
completedTasks: [taskResult],
|
|
2096
|
+
currentAgent: "supervisor",
|
|
2097
|
+
status: "routing"
|
|
2098
|
+
};
|
|
2099
|
+
} catch (error) {
|
|
2100
|
+
console.error(`[ReActWrapper:${workerId}] Error:`, error);
|
|
2101
|
+
const currentAssignment = state.activeAssignments.find(
|
|
2102
|
+
(assignment) => assignment.workerId === workerId
|
|
2103
|
+
);
|
|
2104
|
+
if (currentAssignment) {
|
|
2105
|
+
const errorResult = {
|
|
2106
|
+
assignmentId: currentAssignment.id,
|
|
2107
|
+
workerId,
|
|
2108
|
+
success: false,
|
|
2109
|
+
result: "",
|
|
2110
|
+
error: error instanceof Error ? error.message : "Unknown error in ReAct agent",
|
|
2111
|
+
completedAt: Date.now()
|
|
2112
|
+
};
|
|
2113
|
+
return {
|
|
2114
|
+
completedTasks: [errorResult],
|
|
2115
|
+
currentAgent: "supervisor",
|
|
2116
|
+
status: "routing"
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
return {
|
|
2120
|
+
status: "failed",
|
|
2121
|
+
error: error instanceof Error ? error.message : `Unknown error in ReAct wrapper for ${workerId}`
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2049
2127
|
// src/multi-agent/nodes.ts
|
|
2050
2128
|
var import_messages5 = require("@langchain/core/messages");
|
|
2051
2129
|
var import_core7 = require("@agentforge/core");
|
|
@@ -2139,7 +2217,8 @@ function createWorkerNode(config) {
|
|
|
2139
2217
|
tools = [],
|
|
2140
2218
|
systemPrompt,
|
|
2141
2219
|
verbose = false,
|
|
2142
|
-
executeFn
|
|
2220
|
+
executeFn,
|
|
2221
|
+
agent
|
|
2143
2222
|
} = config;
|
|
2144
2223
|
return async (state) => {
|
|
2145
2224
|
try {
|
|
@@ -2159,10 +2238,26 @@ function createWorkerNode(config) {
|
|
|
2159
2238
|
};
|
|
2160
2239
|
}
|
|
2161
2240
|
if (executeFn) {
|
|
2241
|
+
if (verbose) {
|
|
2242
|
+
console.log(`[Worker:${id}] Using custom executeFn`);
|
|
2243
|
+
}
|
|
2162
2244
|
return await executeFn(state);
|
|
2163
2245
|
}
|
|
2246
|
+
if (agent) {
|
|
2247
|
+
if (isReActAgent(agent)) {
|
|
2248
|
+
if (verbose) {
|
|
2249
|
+
console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
|
|
2250
|
+
}
|
|
2251
|
+
const wrappedFn = wrapReActAgent(id, agent, verbose);
|
|
2252
|
+
return await wrappedFn(state);
|
|
2253
|
+
} else {
|
|
2254
|
+
console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2164
2257
|
if (!model) {
|
|
2165
|
-
throw new Error(
|
|
2258
|
+
throw new Error(
|
|
2259
|
+
`Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
|
|
2260
|
+
);
|
|
2166
2261
|
}
|
|
2167
2262
|
const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
|
|
2168
2263
|
Skills: ${capabilities.skills.join(", ")}
|
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,84 @@ 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 taskResult = {
|
|
1985
|
+
assignmentId: currentAssignment.id,
|
|
1986
|
+
workerId,
|
|
1987
|
+
result: response,
|
|
1988
|
+
completedAt: Date.now(),
|
|
1989
|
+
success: true,
|
|
1990
|
+
metadata: {
|
|
1991
|
+
agent_type: "react",
|
|
1992
|
+
iterations: result.iteration || 0
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
return {
|
|
1996
|
+
completedTasks: [taskResult],
|
|
1997
|
+
currentAgent: "supervisor",
|
|
1998
|
+
status: "routing"
|
|
1999
|
+
};
|
|
2000
|
+
} catch (error) {
|
|
2001
|
+
console.error(`[ReActWrapper:${workerId}] Error:`, error);
|
|
2002
|
+
const currentAssignment = state.activeAssignments.find(
|
|
2003
|
+
(assignment) => assignment.workerId === workerId
|
|
2004
|
+
);
|
|
2005
|
+
if (currentAssignment) {
|
|
2006
|
+
const errorResult = {
|
|
2007
|
+
assignmentId: currentAssignment.id,
|
|
2008
|
+
workerId,
|
|
2009
|
+
success: false,
|
|
2010
|
+
result: "",
|
|
2011
|
+
error: error instanceof Error ? error.message : "Unknown error in ReAct agent",
|
|
2012
|
+
completedAt: Date.now()
|
|
2013
|
+
};
|
|
2014
|
+
return {
|
|
2015
|
+
completedTasks: [errorResult],
|
|
2016
|
+
currentAgent: "supervisor",
|
|
2017
|
+
status: "routing"
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
return {
|
|
2021
|
+
status: "failed",
|
|
2022
|
+
error: error instanceof Error ? error.message : `Unknown error in ReAct wrapper for ${workerId}`
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
};
|
|
2026
|
+
}
|
|
2027
|
+
|
|
1950
2028
|
// src/multi-agent/nodes.ts
|
|
1951
2029
|
import { HumanMessage as HumanMessage5, SystemMessage as SystemMessage5 } from "@langchain/core/messages";
|
|
1952
2030
|
import { toLangChainTools as toLangChainTools2 } from "@agentforge/core";
|
|
@@ -2040,7 +2118,8 @@ function createWorkerNode(config) {
|
|
|
2040
2118
|
tools = [],
|
|
2041
2119
|
systemPrompt,
|
|
2042
2120
|
verbose = false,
|
|
2043
|
-
executeFn
|
|
2121
|
+
executeFn,
|
|
2122
|
+
agent
|
|
2044
2123
|
} = config;
|
|
2045
2124
|
return async (state) => {
|
|
2046
2125
|
try {
|
|
@@ -2060,10 +2139,26 @@ function createWorkerNode(config) {
|
|
|
2060
2139
|
};
|
|
2061
2140
|
}
|
|
2062
2141
|
if (executeFn) {
|
|
2142
|
+
if (verbose) {
|
|
2143
|
+
console.log(`[Worker:${id}] Using custom executeFn`);
|
|
2144
|
+
}
|
|
2063
2145
|
return await executeFn(state);
|
|
2064
2146
|
}
|
|
2147
|
+
if (agent) {
|
|
2148
|
+
if (isReActAgent(agent)) {
|
|
2149
|
+
if (verbose) {
|
|
2150
|
+
console.log(`[Worker:${id}] Using ReAct agent (auto-wrapped)`);
|
|
2151
|
+
}
|
|
2152
|
+
const wrappedFn = wrapReActAgent(id, agent, verbose);
|
|
2153
|
+
return await wrappedFn(state);
|
|
2154
|
+
} else {
|
|
2155
|
+
console.warn(`[Worker:${id}] Agent provided but does not appear to be a ReAct agent. Falling back to default execution.`);
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2065
2158
|
if (!model) {
|
|
2066
|
-
throw new Error(
|
|
2159
|
+
throw new Error(
|
|
2160
|
+
`Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
|
|
2161
|
+
);
|
|
2067
2162
|
}
|
|
2068
2163
|
const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
|
|
2069
2164
|
Skills: ${capabilities.skills.join(", ")}
|