@agentforge/patterns 0.5.4 → 0.6.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 CHANGED
@@ -1891,6 +1891,33 @@ var MultiAgentState = (0, import_core6.createStateAnnotation)(MultiAgentStateCon
1891
1891
 
1892
1892
  // src/multi-agent/routing.ts
1893
1893
  var import_messages4 = require("@langchain/core/messages");
1894
+ async function executeTools(toolCalls, tools) {
1895
+ const results = [];
1896
+ for (const toolCall of toolCalls) {
1897
+ const tool = tools.find((t) => t.metadata.name === toolCall.name);
1898
+ if (!tool) {
1899
+ results.push(new import_messages4.ToolMessage({
1900
+ content: `Error: Tool '${toolCall.name}' not found`,
1901
+ tool_call_id: toolCall.id
1902
+ }));
1903
+ continue;
1904
+ }
1905
+ try {
1906
+ const result = await tool.execute(toolCall.args);
1907
+ const content = typeof result === "string" ? result : JSON.stringify(result);
1908
+ results.push(new import_messages4.ToolMessage({
1909
+ content,
1910
+ tool_call_id: toolCall.id
1911
+ }));
1912
+ } catch (error) {
1913
+ results.push(new import_messages4.ToolMessage({
1914
+ content: `Error executing tool: ${error.message}`,
1915
+ tool_call_id: toolCall.id
1916
+ }));
1917
+ }
1918
+ }
1919
+ return results;
1920
+ }
1894
1921
  var DEFAULT_SUPERVISOR_SYSTEM_PROMPT = `You are a supervisor agent responsible for routing tasks to specialized worker agents.
1895
1922
 
1896
1923
  Your job is to:
@@ -1913,11 +1940,13 @@ var llmBasedRouting = {
1913
1940
  throw new Error("LLM-based routing requires a model to be configured");
1914
1941
  }
1915
1942
  const systemPrompt = config.systemPrompt || DEFAULT_SUPERVISOR_SYSTEM_PROMPT;
1943
+ const maxRetries = config.maxToolRetries || 3;
1944
+ const tools = config.tools || [];
1916
1945
  const workerInfo = Object.entries(state.workers).map(([id, caps]) => {
1917
1946
  const skills = caps.skills.join(", ");
1918
- const tools = caps.tools.join(", ");
1947
+ const tools2 = caps.tools.join(", ");
1919
1948
  const available = caps.available ? "available" : "busy";
1920
- return `- ${id}: Skills: [${skills}], Tools: [${tools}], Status: ${available}, Workload: ${caps.currentWorkload}`;
1949
+ return `- ${id}: Skills: [${skills}], Tools: [${tools2}], Status: ${available}, Workload: ${caps.currentWorkload}`;
1921
1950
  }).join("\n");
1922
1951
  const lastMessage = state.messages[state.messages.length - 1];
1923
1952
  const taskContext = lastMessage?.content || state.input;
@@ -1927,24 +1956,42 @@ Available workers:
1927
1956
  ${workerInfo}
1928
1957
 
1929
1958
  Select the best worker for this task and explain your reasoning.`;
1930
- const messages = [
1931
- new import_messages4.SystemMessage(systemPrompt),
1932
- new import_messages4.HumanMessage(userPrompt)
1933
- ];
1934
- const response = await config.model.invoke(messages);
1935
- const content = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
1936
- try {
1937
- const decision = JSON.parse(content);
1938
- return {
1939
- targetAgent: decision.targetAgent,
1940
- reasoning: decision.reasoning,
1941
- confidence: decision.confidence,
1942
- strategy: "llm-based",
1943
- timestamp: Date.now()
1944
- };
1945
- } catch (error) {
1946
- throw new Error(`Failed to parse routing decision from LLM: ${error}`);
1959
+ const conversationHistory = [];
1960
+ let attempt = 0;
1961
+ while (attempt < maxRetries) {
1962
+ const messages = [
1963
+ new import_messages4.SystemMessage(systemPrompt),
1964
+ new import_messages4.HumanMessage(userPrompt),
1965
+ ...conversationHistory
1966
+ ];
1967
+ const response = await config.model.invoke(messages);
1968
+ if (response.tool_calls && response.tool_calls.length > 0) {
1969
+ if (tools.length === 0) {
1970
+ throw new Error("LLM requested tool calls but no tools are configured");
1971
+ }
1972
+ const toolResults = await executeTools(response.tool_calls, tools);
1973
+ conversationHistory.push(
1974
+ new import_messages4.AIMessage({ content: response.content || "", tool_calls: response.tool_calls }),
1975
+ ...toolResults
1976
+ );
1977
+ attempt++;
1978
+ continue;
1979
+ }
1980
+ const content = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
1981
+ try {
1982
+ const decision = JSON.parse(content);
1983
+ return {
1984
+ targetAgent: decision.targetAgent,
1985
+ reasoning: decision.reasoning,
1986
+ confidence: decision.confidence,
1987
+ strategy: "llm-based",
1988
+ timestamp: Date.now()
1989
+ };
1990
+ } catch (error) {
1991
+ throw new Error(`Failed to parse routing decision from LLM: ${error}`);
1992
+ }
1947
1993
  }
1994
+ throw new Error(`Max tool retries (${maxRetries}) exceeded without routing decision`);
1948
1995
  }
1949
1996
  };
1950
1997
  var roundRobinRouting = {
@@ -2419,6 +2466,7 @@ Please synthesize these results into a comprehensive response that addresses the
2419
2466
 
2420
2467
  // src/multi-agent/agent.ts
2421
2468
  var import_langgraph4 = require("@langchain/langgraph");
2469
+ var import_core8 = require("@agentforge/core");
2422
2470
  function createMultiAgentSystem(config) {
2423
2471
  const {
2424
2472
  supervisor,
@@ -2429,11 +2477,13 @@ function createMultiAgentSystem(config) {
2429
2477
  checkpointer
2430
2478
  } = config;
2431
2479
  const workflow = new import_langgraph4.StateGraph(MultiAgentState);
2432
- const supervisorNode = createSupervisorNode({
2433
- ...supervisor,
2434
- maxIterations,
2435
- verbose
2436
- });
2480
+ let supervisorConfig = { ...supervisor, maxIterations, verbose };
2481
+ if (supervisor.model && supervisor.tools && supervisor.tools.length > 0) {
2482
+ const langchainTools = (0, import_core8.toLangChainTools)(supervisor.tools);
2483
+ const modelWithTools = supervisor.model.bindTools(langchainTools);
2484
+ supervisorConfig.model = modelWithTools;
2485
+ }
2486
+ const supervisorNode = createSupervisorNode(supervisorConfig);
2437
2487
  workflow.addNode("supervisor", supervisorNode);
2438
2488
  const workerIds = [];
2439
2489
  const workerCapabilities = {};
package/dist/index.d.cts CHANGED
@@ -2411,6 +2411,37 @@ interface SupervisorConfig {
2411
2411
  * Maximum number of routing iterations
2412
2412
  */
2413
2413
  maxIterations?: number;
2414
+ /**
2415
+ * Optional tools the supervisor can use during routing
2416
+ *
2417
+ * Enables the supervisor to gather additional information before making routing decisions.
2418
+ * Common use case: askHuman tool for clarifying ambiguous queries.
2419
+ *
2420
+ * Note: Only works with LLM-based routing strategy.
2421
+ *
2422
+ * @example
2423
+ * ```typescript
2424
+ * import { createAskHumanTool } from '@agentforge/tools';
2425
+ *
2426
+ * const system = createMultiAgentSystem({
2427
+ * supervisor: {
2428
+ * strategy: 'llm-based',
2429
+ * model: chatModel,
2430
+ * tools: [createAskHumanTool()],
2431
+ * },
2432
+ * // ...
2433
+ * });
2434
+ * ```
2435
+ */
2436
+ tools?: Tool<any, any>[];
2437
+ /**
2438
+ * Maximum number of tool call retries before requiring routing decision
2439
+ *
2440
+ * Prevents infinite loops where the supervisor keeps calling tools without making a routing decision.
2441
+ *
2442
+ * @default 3
2443
+ */
2444
+ maxToolRetries?: number;
2414
2445
  }
2415
2446
  /**
2416
2447
  * Configuration for a worker agent node
@@ -2576,6 +2607,8 @@ declare const DEFAULT_SUPERVISOR_SYSTEM_PROMPT = "You are a supervisor agent res
2576
2607
  /**
2577
2608
  * LLM-based routing strategy
2578
2609
  * Uses an LLM to intelligently route tasks based on worker capabilities
2610
+ *
2611
+ * Supports tool calls (e.g., askHuman) for gathering additional information before routing.
2579
2612
  */
2580
2613
  declare const llmBasedRouting: RoutingStrategyImpl;
2581
2614
  /**
package/dist/index.d.ts CHANGED
@@ -2411,6 +2411,37 @@ interface SupervisorConfig {
2411
2411
  * Maximum number of routing iterations
2412
2412
  */
2413
2413
  maxIterations?: number;
2414
+ /**
2415
+ * Optional tools the supervisor can use during routing
2416
+ *
2417
+ * Enables the supervisor to gather additional information before making routing decisions.
2418
+ * Common use case: askHuman tool for clarifying ambiguous queries.
2419
+ *
2420
+ * Note: Only works with LLM-based routing strategy.
2421
+ *
2422
+ * @example
2423
+ * ```typescript
2424
+ * import { createAskHumanTool } from '@agentforge/tools';
2425
+ *
2426
+ * const system = createMultiAgentSystem({
2427
+ * supervisor: {
2428
+ * strategy: 'llm-based',
2429
+ * model: chatModel,
2430
+ * tools: [createAskHumanTool()],
2431
+ * },
2432
+ * // ...
2433
+ * });
2434
+ * ```
2435
+ */
2436
+ tools?: Tool<any, any>[];
2437
+ /**
2438
+ * Maximum number of tool call retries before requiring routing decision
2439
+ *
2440
+ * Prevents infinite loops where the supervisor keeps calling tools without making a routing decision.
2441
+ *
2442
+ * @default 3
2443
+ */
2444
+ maxToolRetries?: number;
2414
2445
  }
2415
2446
  /**
2416
2447
  * Configuration for a worker agent node
@@ -2576,6 +2607,8 @@ declare const DEFAULT_SUPERVISOR_SYSTEM_PROMPT = "You are a supervisor agent res
2576
2607
  /**
2577
2608
  * LLM-based routing strategy
2578
2609
  * Uses an LLM to intelligently route tasks based on worker capabilities
2610
+ *
2611
+ * Supports tool calls (e.g., askHuman) for gathering additional information before routing.
2579
2612
  */
2580
2613
  declare const llmBasedRouting: RoutingStrategyImpl;
2581
2614
  /**
package/dist/index.js CHANGED
@@ -1791,7 +1791,34 @@ var MultiAgentStateConfig = {
1791
1791
  var MultiAgentState = createStateAnnotation4(MultiAgentStateConfig);
1792
1792
 
1793
1793
  // src/multi-agent/routing.ts
1794
- import { HumanMessage as HumanMessage4, SystemMessage as SystemMessage4 } from "@langchain/core/messages";
1794
+ import { HumanMessage as HumanMessage4, SystemMessage as SystemMessage4, AIMessage as AIMessage2, ToolMessage as ToolMessage2 } from "@langchain/core/messages";
1795
+ async function executeTools(toolCalls, tools) {
1796
+ const results = [];
1797
+ for (const toolCall of toolCalls) {
1798
+ const tool = tools.find((t) => t.metadata.name === toolCall.name);
1799
+ if (!tool) {
1800
+ results.push(new ToolMessage2({
1801
+ content: `Error: Tool '${toolCall.name}' not found`,
1802
+ tool_call_id: toolCall.id
1803
+ }));
1804
+ continue;
1805
+ }
1806
+ try {
1807
+ const result = await tool.execute(toolCall.args);
1808
+ const content = typeof result === "string" ? result : JSON.stringify(result);
1809
+ results.push(new ToolMessage2({
1810
+ content,
1811
+ tool_call_id: toolCall.id
1812
+ }));
1813
+ } catch (error) {
1814
+ results.push(new ToolMessage2({
1815
+ content: `Error executing tool: ${error.message}`,
1816
+ tool_call_id: toolCall.id
1817
+ }));
1818
+ }
1819
+ }
1820
+ return results;
1821
+ }
1795
1822
  var DEFAULT_SUPERVISOR_SYSTEM_PROMPT = `You are a supervisor agent responsible for routing tasks to specialized worker agents.
1796
1823
 
1797
1824
  Your job is to:
@@ -1814,11 +1841,13 @@ var llmBasedRouting = {
1814
1841
  throw new Error("LLM-based routing requires a model to be configured");
1815
1842
  }
1816
1843
  const systemPrompt = config.systemPrompt || DEFAULT_SUPERVISOR_SYSTEM_PROMPT;
1844
+ const maxRetries = config.maxToolRetries || 3;
1845
+ const tools = config.tools || [];
1817
1846
  const workerInfo = Object.entries(state.workers).map(([id, caps]) => {
1818
1847
  const skills = caps.skills.join(", ");
1819
- const tools = caps.tools.join(", ");
1848
+ const tools2 = caps.tools.join(", ");
1820
1849
  const available = caps.available ? "available" : "busy";
1821
- return `- ${id}: Skills: [${skills}], Tools: [${tools}], Status: ${available}, Workload: ${caps.currentWorkload}`;
1850
+ return `- ${id}: Skills: [${skills}], Tools: [${tools2}], Status: ${available}, Workload: ${caps.currentWorkload}`;
1822
1851
  }).join("\n");
1823
1852
  const lastMessage = state.messages[state.messages.length - 1];
1824
1853
  const taskContext = lastMessage?.content || state.input;
@@ -1828,24 +1857,42 @@ Available workers:
1828
1857
  ${workerInfo}
1829
1858
 
1830
1859
  Select the best worker for this task and explain your reasoning.`;
1831
- const messages = [
1832
- new SystemMessage4(systemPrompt),
1833
- new HumanMessage4(userPrompt)
1834
- ];
1835
- const response = await config.model.invoke(messages);
1836
- const content = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
1837
- try {
1838
- const decision = JSON.parse(content);
1839
- return {
1840
- targetAgent: decision.targetAgent,
1841
- reasoning: decision.reasoning,
1842
- confidence: decision.confidence,
1843
- strategy: "llm-based",
1844
- timestamp: Date.now()
1845
- };
1846
- } catch (error) {
1847
- throw new Error(`Failed to parse routing decision from LLM: ${error}`);
1860
+ const conversationHistory = [];
1861
+ let attempt = 0;
1862
+ while (attempt < maxRetries) {
1863
+ const messages = [
1864
+ new SystemMessage4(systemPrompt),
1865
+ new HumanMessage4(userPrompt),
1866
+ ...conversationHistory
1867
+ ];
1868
+ const response = await config.model.invoke(messages);
1869
+ if (response.tool_calls && response.tool_calls.length > 0) {
1870
+ if (tools.length === 0) {
1871
+ throw new Error("LLM requested tool calls but no tools are configured");
1872
+ }
1873
+ const toolResults = await executeTools(response.tool_calls, tools);
1874
+ conversationHistory.push(
1875
+ new AIMessage2({ content: response.content || "", tool_calls: response.tool_calls }),
1876
+ ...toolResults
1877
+ );
1878
+ attempt++;
1879
+ continue;
1880
+ }
1881
+ const content = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
1882
+ try {
1883
+ const decision = JSON.parse(content);
1884
+ return {
1885
+ targetAgent: decision.targetAgent,
1886
+ reasoning: decision.reasoning,
1887
+ confidence: decision.confidence,
1888
+ strategy: "llm-based",
1889
+ timestamp: Date.now()
1890
+ };
1891
+ } catch (error) {
1892
+ throw new Error(`Failed to parse routing decision from LLM: ${error}`);
1893
+ }
1848
1894
  }
1895
+ throw new Error(`Max tool retries (${maxRetries}) exceeded without routing decision`);
1849
1896
  }
1850
1897
  };
1851
1898
  var roundRobinRouting = {
@@ -2320,6 +2367,7 @@ Please synthesize these results into a comprehensive response that addresses the
2320
2367
 
2321
2368
  // src/multi-agent/agent.ts
2322
2369
  import { StateGraph as StateGraph4, END as END4 } from "@langchain/langgraph";
2370
+ import { toLangChainTools as toLangChainTools3 } from "@agentforge/core";
2323
2371
  function createMultiAgentSystem(config) {
2324
2372
  const {
2325
2373
  supervisor,
@@ -2330,11 +2378,13 @@ function createMultiAgentSystem(config) {
2330
2378
  checkpointer
2331
2379
  } = config;
2332
2380
  const workflow = new StateGraph4(MultiAgentState);
2333
- const supervisorNode = createSupervisorNode({
2334
- ...supervisor,
2335
- maxIterations,
2336
- verbose
2337
- });
2381
+ let supervisorConfig = { ...supervisor, maxIterations, verbose };
2382
+ if (supervisor.model && supervisor.tools && supervisor.tools.length > 0) {
2383
+ const langchainTools = toLangChainTools3(supervisor.tools);
2384
+ const modelWithTools = supervisor.model.bindTools(langchainTools);
2385
+ supervisorConfig.model = modelWithTools;
2386
+ }
2387
+ const supervisorNode = createSupervisorNode(supervisorConfig);
2338
2388
  workflow.addNode("supervisor", supervisorNode);
2339
2389
  const workerIds = [];
2340
2390
  const workerCapabilities = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/patterns",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
4
4
  "description": "Agent patterns (ReAct, Planner-Executor) for AgentForge framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",