@librechat/agents 2.4.322 → 3.0.0-rc2

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.
Files changed (266) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +218 -0
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -0
  3. package/dist/cjs/common/enum.cjs +14 -5
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/events.cjs +10 -6
  6. package/dist/cjs/events.cjs.map +1 -1
  7. package/dist/cjs/graphs/Graph.cjs +309 -212
  8. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  9. package/dist/cjs/graphs/MultiAgentGraph.cjs +422 -0
  10. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -0
  11. package/dist/cjs/llm/anthropic/index.cjs +54 -9
  12. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  13. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  14. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +52 -6
  15. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  16. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +22 -2
  17. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  18. package/dist/cjs/llm/anthropic/utils/tools.cjs +29 -0
  19. package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -0
  20. package/dist/cjs/llm/google/index.cjs +144 -0
  21. package/dist/cjs/llm/google/index.cjs.map +1 -0
  22. package/dist/cjs/llm/google/utils/common.cjs +477 -0
  23. package/dist/cjs/llm/google/utils/common.cjs.map +1 -0
  24. package/dist/cjs/llm/ollama/index.cjs +67 -0
  25. package/dist/cjs/llm/ollama/index.cjs.map +1 -0
  26. package/dist/cjs/llm/ollama/utils.cjs +158 -0
  27. package/dist/cjs/llm/ollama/utils.cjs.map +1 -0
  28. package/dist/cjs/llm/openai/index.cjs +389 -3
  29. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  30. package/dist/cjs/llm/openai/utils/index.cjs +672 -0
  31. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -0
  32. package/dist/cjs/llm/providers.cjs +15 -15
  33. package/dist/cjs/llm/providers.cjs.map +1 -1
  34. package/dist/cjs/llm/text.cjs +14 -3
  35. package/dist/cjs/llm/text.cjs.map +1 -1
  36. package/dist/cjs/llm/vertexai/index.cjs +330 -0
  37. package/dist/cjs/llm/vertexai/index.cjs.map +1 -0
  38. package/dist/cjs/main.cjs +11 -0
  39. package/dist/cjs/main.cjs.map +1 -1
  40. package/dist/cjs/run.cjs +120 -81
  41. package/dist/cjs/run.cjs.map +1 -1
  42. package/dist/cjs/stream.cjs +85 -51
  43. package/dist/cjs/stream.cjs.map +1 -1
  44. package/dist/cjs/tools/ToolNode.cjs +10 -4
  45. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  46. package/dist/cjs/tools/handlers.cjs +119 -13
  47. package/dist/cjs/tools/handlers.cjs.map +1 -1
  48. package/dist/cjs/tools/search/anthropic.cjs +40 -0
  49. package/dist/cjs/tools/search/anthropic.cjs.map +1 -0
  50. package/dist/cjs/tools/search/firecrawl.cjs +55 -9
  51. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  52. package/dist/cjs/tools/search/format.cjs +6 -6
  53. package/dist/cjs/tools/search/format.cjs.map +1 -1
  54. package/dist/cjs/tools/search/rerankers.cjs +7 -29
  55. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  56. package/dist/cjs/tools/search/search.cjs +86 -16
  57. package/dist/cjs/tools/search/search.cjs.map +1 -1
  58. package/dist/cjs/tools/search/tool.cjs +4 -2
  59. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  60. package/dist/cjs/tools/search/utils.cjs +1 -1
  61. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  62. package/dist/cjs/utils/events.cjs +31 -0
  63. package/dist/cjs/utils/events.cjs.map +1 -0
  64. package/dist/cjs/utils/title.cjs +57 -21
  65. package/dist/cjs/utils/title.cjs.map +1 -1
  66. package/dist/cjs/utils/tokens.cjs +54 -7
  67. package/dist/cjs/utils/tokens.cjs.map +1 -1
  68. package/dist/esm/agents/AgentContext.mjs +216 -0
  69. package/dist/esm/agents/AgentContext.mjs.map +1 -0
  70. package/dist/esm/common/enum.mjs +15 -6
  71. package/dist/esm/common/enum.mjs.map +1 -1
  72. package/dist/esm/events.mjs +10 -6
  73. package/dist/esm/events.mjs.map +1 -1
  74. package/dist/esm/graphs/Graph.mjs +311 -214
  75. package/dist/esm/graphs/Graph.mjs.map +1 -1
  76. package/dist/esm/graphs/MultiAgentGraph.mjs +420 -0
  77. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -0
  78. package/dist/esm/llm/anthropic/index.mjs +54 -9
  79. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  80. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  81. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +52 -6
  82. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  83. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +22 -2
  84. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  85. package/dist/esm/llm/anthropic/utils/tools.mjs +27 -0
  86. package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -0
  87. package/dist/esm/llm/google/index.mjs +142 -0
  88. package/dist/esm/llm/google/index.mjs.map +1 -0
  89. package/dist/esm/llm/google/utils/common.mjs +471 -0
  90. package/dist/esm/llm/google/utils/common.mjs.map +1 -0
  91. package/dist/esm/llm/ollama/index.mjs +65 -0
  92. package/dist/esm/llm/ollama/index.mjs.map +1 -0
  93. package/dist/esm/llm/ollama/utils.mjs +155 -0
  94. package/dist/esm/llm/ollama/utils.mjs.map +1 -0
  95. package/dist/esm/llm/openai/index.mjs +388 -4
  96. package/dist/esm/llm/openai/index.mjs.map +1 -1
  97. package/dist/esm/llm/openai/utils/index.mjs +666 -0
  98. package/dist/esm/llm/openai/utils/index.mjs.map +1 -0
  99. package/dist/esm/llm/providers.mjs +5 -5
  100. package/dist/esm/llm/providers.mjs.map +1 -1
  101. package/dist/esm/llm/text.mjs +14 -3
  102. package/dist/esm/llm/text.mjs.map +1 -1
  103. package/dist/esm/llm/vertexai/index.mjs +328 -0
  104. package/dist/esm/llm/vertexai/index.mjs.map +1 -0
  105. package/dist/esm/main.mjs +6 -5
  106. package/dist/esm/main.mjs.map +1 -1
  107. package/dist/esm/run.mjs +121 -83
  108. package/dist/esm/run.mjs.map +1 -1
  109. package/dist/esm/stream.mjs +87 -54
  110. package/dist/esm/stream.mjs.map +1 -1
  111. package/dist/esm/tools/ToolNode.mjs +10 -4
  112. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  113. package/dist/esm/tools/handlers.mjs +119 -15
  114. package/dist/esm/tools/handlers.mjs.map +1 -1
  115. package/dist/esm/tools/search/anthropic.mjs +37 -0
  116. package/dist/esm/tools/search/anthropic.mjs.map +1 -0
  117. package/dist/esm/tools/search/firecrawl.mjs +55 -9
  118. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  119. package/dist/esm/tools/search/format.mjs +7 -7
  120. package/dist/esm/tools/search/format.mjs.map +1 -1
  121. package/dist/esm/tools/search/rerankers.mjs +7 -29
  122. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  123. package/dist/esm/tools/search/search.mjs +86 -16
  124. package/dist/esm/tools/search/search.mjs.map +1 -1
  125. package/dist/esm/tools/search/tool.mjs +4 -2
  126. package/dist/esm/tools/search/tool.mjs.map +1 -1
  127. package/dist/esm/tools/search/utils.mjs +1 -1
  128. package/dist/esm/tools/search/utils.mjs.map +1 -1
  129. package/dist/esm/utils/events.mjs +29 -0
  130. package/dist/esm/utils/events.mjs.map +1 -0
  131. package/dist/esm/utils/title.mjs +57 -22
  132. package/dist/esm/utils/title.mjs.map +1 -1
  133. package/dist/esm/utils/tokens.mjs +54 -8
  134. package/dist/esm/utils/tokens.mjs.map +1 -1
  135. package/dist/types/agents/AgentContext.d.ts +91 -0
  136. package/dist/types/common/enum.d.ts +15 -6
  137. package/dist/types/events.d.ts +5 -4
  138. package/dist/types/graphs/Graph.d.ts +64 -67
  139. package/dist/types/graphs/MultiAgentGraph.d.ts +37 -0
  140. package/dist/types/graphs/index.d.ts +1 -0
  141. package/dist/types/llm/anthropic/index.d.ts +11 -0
  142. package/dist/types/llm/anthropic/types.d.ts +9 -3
  143. package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
  144. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +4 -4
  145. package/dist/types/llm/anthropic/utils/tools.d.ts +3 -0
  146. package/dist/types/llm/google/index.d.ts +13 -0
  147. package/dist/types/llm/google/types.d.ts +32 -0
  148. package/dist/types/llm/google/utils/common.d.ts +19 -0
  149. package/dist/types/llm/google/utils/tools.d.ts +10 -0
  150. package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +14 -0
  151. package/dist/types/llm/ollama/index.d.ts +7 -0
  152. package/dist/types/llm/ollama/utils.d.ts +7 -0
  153. package/dist/types/llm/openai/index.d.ts +72 -3
  154. package/dist/types/llm/openai/types.d.ts +10 -0
  155. package/dist/types/llm/openai/utils/index.d.ts +20 -0
  156. package/dist/types/llm/text.d.ts +1 -1
  157. package/dist/types/llm/vertexai/index.d.ts +293 -0
  158. package/dist/types/messages/reducer.d.ts +9 -0
  159. package/dist/types/run.d.ts +19 -12
  160. package/dist/types/scripts/ant_web_search.d.ts +1 -0
  161. package/dist/types/scripts/args.d.ts +2 -1
  162. package/dist/types/scripts/handoff-test.d.ts +1 -0
  163. package/dist/types/scripts/multi-agent-conditional.d.ts +1 -0
  164. package/dist/types/scripts/multi-agent-parallel.d.ts +1 -0
  165. package/dist/types/scripts/multi-agent-sequence.d.ts +1 -0
  166. package/dist/types/scripts/multi-agent-supervisor.d.ts +1 -0
  167. package/dist/types/scripts/multi-agent-test.d.ts +1 -0
  168. package/dist/types/scripts/test-custom-prompt-key.d.ts +2 -0
  169. package/dist/types/scripts/test-handoff-input.d.ts +2 -0
  170. package/dist/types/scripts/test-multi-agent-list-handoff.d.ts +2 -0
  171. package/dist/types/stream.d.ts +10 -3
  172. package/dist/types/tools/CodeExecutor.d.ts +2 -2
  173. package/dist/types/tools/ToolNode.d.ts +1 -1
  174. package/dist/types/tools/handlers.d.ts +17 -4
  175. package/dist/types/tools/search/anthropic.d.ts +16 -0
  176. package/dist/types/tools/search/firecrawl.d.ts +15 -0
  177. package/dist/types/tools/search/rerankers.d.ts +0 -1
  178. package/dist/types/tools/search/types.d.ts +30 -9
  179. package/dist/types/types/graph.d.ts +129 -15
  180. package/dist/types/types/llm.d.ts +24 -10
  181. package/dist/types/types/run.d.ts +46 -8
  182. package/dist/types/types/stream.d.ts +16 -2
  183. package/dist/types/types/tools.d.ts +1 -1
  184. package/dist/types/utils/events.d.ts +6 -0
  185. package/dist/types/utils/title.d.ts +2 -1
  186. package/dist/types/utils/tokens.d.ts +24 -0
  187. package/package.json +37 -17
  188. package/src/agents/AgentContext.ts +315 -0
  189. package/src/common/enum.ts +14 -5
  190. package/src/events.ts +24 -13
  191. package/src/graphs/Graph.ts +495 -312
  192. package/src/graphs/MultiAgentGraph.ts +498 -0
  193. package/src/graphs/index.ts +2 -1
  194. package/src/llm/anthropic/Jacob_Lee_Resume_2023.pdf +0 -0
  195. package/src/llm/anthropic/index.ts +78 -13
  196. package/src/llm/anthropic/llm.spec.ts +491 -115
  197. package/src/llm/anthropic/types.ts +39 -3
  198. package/src/llm/anthropic/utils/message_inputs.ts +67 -11
  199. package/src/llm/anthropic/utils/message_outputs.ts +21 -2
  200. package/src/llm/anthropic/utils/output_parsers.ts +25 -6
  201. package/src/llm/anthropic/utils/tools.ts +29 -0
  202. package/src/llm/google/index.ts +218 -0
  203. package/src/llm/google/types.ts +43 -0
  204. package/src/llm/google/utils/common.ts +646 -0
  205. package/src/llm/google/utils/tools.ts +160 -0
  206. package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -0
  207. package/src/llm/ollama/index.ts +89 -0
  208. package/src/llm/ollama/utils.ts +193 -0
  209. package/src/llm/openai/index.ts +600 -14
  210. package/src/llm/openai/types.ts +24 -0
  211. package/src/llm/openai/utils/index.ts +912 -0
  212. package/src/llm/openai/utils/isReasoningModel.test.ts +90 -0
  213. package/src/llm/providers.ts +10 -9
  214. package/src/llm/text.ts +26 -7
  215. package/src/llm/vertexai/index.ts +360 -0
  216. package/src/messages/reducer.ts +80 -0
  217. package/src/run.ts +181 -112
  218. package/src/scripts/ant_web_search.ts +158 -0
  219. package/src/scripts/args.ts +12 -8
  220. package/src/scripts/cli4.ts +29 -21
  221. package/src/scripts/cli5.ts +29 -21
  222. package/src/scripts/code_exec.ts +54 -23
  223. package/src/scripts/code_exec_files.ts +48 -17
  224. package/src/scripts/code_exec_simple.ts +46 -27
  225. package/src/scripts/handoff-test.ts +135 -0
  226. package/src/scripts/image.ts +52 -20
  227. package/src/scripts/multi-agent-conditional.ts +220 -0
  228. package/src/scripts/multi-agent-example-output.md +110 -0
  229. package/src/scripts/multi-agent-parallel.ts +341 -0
  230. package/src/scripts/multi-agent-sequence.ts +212 -0
  231. package/src/scripts/multi-agent-supervisor.ts +361 -0
  232. package/src/scripts/multi-agent-test.ts +186 -0
  233. package/src/scripts/search.ts +1 -9
  234. package/src/scripts/simple.ts +25 -10
  235. package/src/scripts/test-custom-prompt-key.ts +145 -0
  236. package/src/scripts/test-handoff-input.ts +110 -0
  237. package/src/scripts/test-multi-agent-list-handoff.ts +258 -0
  238. package/src/scripts/tools.ts +48 -18
  239. package/src/specs/anthropic.simple.test.ts +150 -34
  240. package/src/specs/azure.simple.test.ts +325 -0
  241. package/src/specs/openai.simple.test.ts +140 -33
  242. package/src/specs/openrouter.simple.test.ts +107 -0
  243. package/src/specs/prune.test.ts +4 -9
  244. package/src/specs/reasoning.test.ts +80 -44
  245. package/src/specs/token-memoization.test.ts +39 -0
  246. package/src/stream.test.ts +94 -0
  247. package/src/stream.ts +139 -60
  248. package/src/tools/ToolNode.ts +21 -7
  249. package/src/tools/handlers.ts +192 -18
  250. package/src/tools/search/anthropic.ts +51 -0
  251. package/src/tools/search/firecrawl.ts +69 -20
  252. package/src/tools/search/format.ts +6 -8
  253. package/src/tools/search/rerankers.ts +7 -40
  254. package/src/tools/search/search.ts +97 -16
  255. package/src/tools/search/tool.ts +5 -2
  256. package/src/tools/search/types.ts +30 -10
  257. package/src/tools/search/utils.ts +1 -1
  258. package/src/types/graph.ts +315 -103
  259. package/src/types/llm.ts +25 -12
  260. package/src/types/run.ts +51 -13
  261. package/src/types/stream.ts +22 -1
  262. package/src/types/tools.ts +16 -10
  263. package/src/utils/events.ts +32 -0
  264. package/src/utils/llmConfig.ts +19 -7
  265. package/src/utils/title.ts +104 -30
  266. package/src/utils/tokens.ts +69 -10
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { config } from 'dotenv';
4
+ config();
5
+
6
+ import { HumanMessage } from '@langchain/core/messages';
7
+ import { Run } from '@/run';
8
+ import { Providers } from '@/common';
9
+ import type * as t from '@/types';
10
+
11
+ /**
12
+ * Test the custom promptKey feature for handoff edges
13
+ * This demonstrates how to use custom parameter names instead of "instructions"
14
+ */
15
+ async function testCustomPromptKey() {
16
+ console.log('Testing Custom Prompt Key Feature...\n');
17
+
18
+ const runConfig: t.RunConfig = {
19
+ runId: `test-custom-prompt-key-${Date.now()}`,
20
+ graphConfig: {
21
+ type: 'multi-agent',
22
+ agents: [
23
+ {
24
+ agentId: 'supervisor',
25
+ provider: Providers.ANTHROPIC,
26
+ clientOptions: {
27
+ modelName: 'claude-3-5-sonnet-latest',
28
+ apiKey: process.env.ANTHROPIC_API_KEY,
29
+ },
30
+ instructions: `You are a Task Supervisor managing different agents:
31
+
32
+ 1. transfer_to_researcher - For research tasks (uses "query" parameter)
33
+ 2. transfer_to_designer - For design tasks (uses "requirements" parameter)
34
+ 3. transfer_to_coder - For coding tasks (uses "specification" parameter)
35
+
36
+ Each agent expects different parameter names in their handoff tools.
37
+ Pay attention to the parameter names when calling each tool.`,
38
+ maxContextTokens: 8000,
39
+ },
40
+ {
41
+ agentId: 'researcher',
42
+ provider: Providers.ANTHROPIC,
43
+ clientOptions: {
44
+ modelName: 'claude-3-5-sonnet-latest',
45
+ apiKey: process.env.ANTHROPIC_API_KEY,
46
+ },
47
+ instructions: `You are a Research Agent. You receive research queries to investigate.
48
+ Look for the "Query:" field in the transfer message.`,
49
+ maxContextTokens: 8000,
50
+ },
51
+ {
52
+ agentId: 'designer',
53
+ provider: Providers.ANTHROPIC,
54
+ clientOptions: {
55
+ modelName: 'claude-3-5-sonnet-latest',
56
+ apiKey: process.env.ANTHROPIC_API_KEY,
57
+ },
58
+ instructions: `You are a Design Agent. You receive design requirements to implement.
59
+ Look for the "Requirements:" field in the transfer message.`,
60
+ maxContextTokens: 8000,
61
+ },
62
+ {
63
+ agentId: 'coder',
64
+ provider: Providers.ANTHROPIC,
65
+ clientOptions: {
66
+ modelName: 'claude-3-5-sonnet-latest',
67
+ apiKey: process.env.ANTHROPIC_API_KEY,
68
+ },
69
+ instructions: `You are a Coding Agent. You receive technical specifications to implement.
70
+ Look for the "Specification:" field in the transfer message.`,
71
+ maxContextTokens: 8000,
72
+ },
73
+ ],
74
+ edges: [
75
+ {
76
+ from: 'supervisor',
77
+ to: 'researcher',
78
+ edgeType: 'handoff',
79
+ // Custom parameter name: "query"
80
+ prompt: 'The research question or topic to investigate',
81
+ promptKey: 'query',
82
+ },
83
+ {
84
+ from: 'supervisor',
85
+ to: 'designer',
86
+ edgeType: 'handoff',
87
+ // Custom parameter name: "requirements"
88
+ prompt: 'The design requirements and constraints',
89
+ promptKey: 'requirements',
90
+ },
91
+ {
92
+ from: 'supervisor',
93
+ to: 'coder',
94
+ edgeType: 'handoff',
95
+ // Custom parameter name: "specification"
96
+ prompt: 'The technical specification for the code to implement',
97
+ promptKey: 'specification',
98
+ },
99
+ ],
100
+ },
101
+ };
102
+
103
+ const run = await Run.create(runConfig);
104
+
105
+ // Test queries for different agents
106
+ const testQueries = [
107
+ // 'Research the latest trends in sustainable energy storage technologies',
108
+ 'Design a mobile app interface for a fitness tracking application',
109
+ // 'Write a Python function that calculates the Fibonacci sequence recursively',
110
+ ];
111
+
112
+ const config = {
113
+ configurable: {
114
+ thread_id: 'custom-prompt-key-test-1',
115
+ },
116
+ streamMode: 'values',
117
+ version: 'v2' as const,
118
+ };
119
+
120
+ for (const query of testQueries) {
121
+ console.log(`\n${'='.repeat(60)}`);
122
+ console.log(`USER QUERY: "${query}"`);
123
+ console.log('='.repeat(60));
124
+
125
+ const inputs = {
126
+ messages: [new HumanMessage(query)],
127
+ };
128
+
129
+ await run.processStream(inputs, config);
130
+
131
+ console.log(`\n${'─'.repeat(60)}`);
132
+ console.log('Each agent receives instructions via their custom parameter:');
133
+ console.log('- Researcher expects "query"');
134
+ console.log('- Designer expects "requirements"');
135
+ console.log('- Coder expects "specification"');
136
+ console.log('─'.repeat(60));
137
+ }
138
+
139
+ console.log('\n\nDemonstration complete!');
140
+ console.log('The promptKey feature allows for more semantic parameter names');
141
+ console.log('that better match the domain and purpose of each agent.');
142
+ }
143
+
144
+ // Run the test
145
+ testCustomPromptKey().catch(console.error);
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { config } from 'dotenv';
4
+ config();
5
+
6
+ import { HumanMessage } from '@langchain/core/messages';
7
+ import { Run } from '@/run';
8
+ import { Providers } from '@/common';
9
+ import type * as t from '@/types';
10
+
11
+ /**
12
+ * Test the new handoff input feature using the prompt field
13
+ * This demonstrates how supervisors can pass specific instructions to specialists
14
+ */
15
+ async function testHandoffInput() {
16
+ console.log('Testing Handoff Input Feature...\n');
17
+
18
+ const runConfig: t.RunConfig = {
19
+ runId: `test-handoff-input-${Date.now()}`,
20
+ graphConfig: {
21
+ type: 'multi-agent',
22
+ agents: [
23
+ {
24
+ agentId: 'supervisor',
25
+ provider: Providers.ANTHROPIC,
26
+ clientOptions: {
27
+ modelName: 'claude-3-5-sonnet-latest',
28
+ apiKey: process.env.ANTHROPIC_API_KEY,
29
+ },
30
+ instructions: `You are a Task Supervisor. You have access to two specialist agents:
31
+
32
+ 1. transfer_to_analyst - For data analysis tasks
33
+ 2. transfer_to_writer - For content creation tasks
34
+
35
+ When transferring to a specialist, you MUST provide specific instructions
36
+ in the tool call to guide their work. Be detailed about what you need.`,
37
+ maxContextTokens: 8000,
38
+ },
39
+ {
40
+ agentId: 'analyst',
41
+ provider: Providers.ANTHROPIC,
42
+ clientOptions: {
43
+ modelName: 'claude-3-5-sonnet-latest',
44
+ apiKey: process.env.ANTHROPIC_API_KEY,
45
+ },
46
+ instructions: `You are a Data Analyst. Follow the supervisor's instructions carefully.
47
+ When you receive instructions, acknowledge them and perform the requested analysis.`,
48
+ maxContextTokens: 8000,
49
+ },
50
+ {
51
+ agentId: 'writer',
52
+ provider: Providers.ANTHROPIC,
53
+ clientOptions: {
54
+ modelName: 'claude-3-5-sonnet-latest',
55
+ apiKey: process.env.ANTHROPIC_API_KEY,
56
+ },
57
+ instructions: `You are a Content Writer. Follow the supervisor's instructions carefully.
58
+ When you receive instructions, acknowledge them and create the requested content.`,
59
+ maxContextTokens: 8000,
60
+ },
61
+ ],
62
+ edges: [
63
+ {
64
+ from: 'supervisor',
65
+ to: ['analyst', 'writer'],
66
+ edgeType: 'handoff',
67
+ // This prompt field now serves as the description for the input parameter
68
+ prompt:
69
+ 'Specific instructions for the specialist to follow. Be detailed about what analysis to perform, what data to focus on, or what content to create.',
70
+ },
71
+ ],
72
+ },
73
+ };
74
+
75
+ const run = await Run.create(runConfig);
76
+
77
+ // Test queries that should result in different handoffs with specific instructions
78
+ const testQueries = [
79
+ 'Analyze our Q4 sales data and identify the top 3 performing products',
80
+ 'Write a blog post about the benefits of remote work for software developers',
81
+ ];
82
+
83
+ const config = {
84
+ configurable: {
85
+ thread_id: 'handoff-input-test-1',
86
+ },
87
+ streamMode: 'values',
88
+ version: 'v2' as const,
89
+ };
90
+
91
+ for (const query of testQueries) {
92
+ console.log(`\n${'='.repeat(60)}`);
93
+ console.log(`USER QUERY: "${query}"`);
94
+ console.log('='.repeat(60));
95
+
96
+ const inputs = {
97
+ messages: [new HumanMessage(query)],
98
+ };
99
+
100
+ await run.processStream(inputs, config);
101
+
102
+ console.log(`\n${'─'.repeat(60)}`);
103
+ console.log('Notice how the supervisor passes specific instructions');
104
+ console.log('to the specialist through the handoff tool input parameter.');
105
+ console.log('─'.repeat(60));
106
+ }
107
+ }
108
+
109
+ // Run the test
110
+ testHandoffInput().catch(console.error);
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { config } from 'dotenv';
4
+ config();
5
+
6
+ import { HumanMessage, BaseMessage } from '@langchain/core/messages';
7
+ import { Run } from '@/run';
8
+ import { Providers, GraphEvents } from '@/common';
9
+ import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
10
+ import { ToolEndHandler, ModelEndHandler } from '@/events';
11
+ import type * as t from '@/types';
12
+
13
+ const conversationHistory: BaseMessage[] = [];
14
+
15
+ /**
16
+ * Test supervisor-based multi-agent system using a single edge with multiple destinations
17
+ *
18
+ * Instead of creating 5 separate edges, we use one edge with an array of destinations
19
+ * This should create handoff tools for all 5 specialists from a single edge definition
20
+ */
21
+ async function testSupervisorListHandoff() {
22
+ console.log('Testing Supervisor with List-Based Handoff Edge...\n');
23
+
24
+ // Set up content aggregator
25
+ const { contentParts, aggregateContent } = createContentAggregator();
26
+
27
+ // Track which specialist role was selected
28
+ let selectedRole = '';
29
+
30
+ // Create custom handlers
31
+ const customHandlers = {
32
+ [GraphEvents.TOOL_END]: new ToolEndHandler(),
33
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
34
+ [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
35
+ [GraphEvents.ON_RUN_STEP]: {
36
+ handle: (
37
+ event: GraphEvents.ON_RUN_STEP,
38
+ data: t.StreamEventData
39
+ ): void => {
40
+ const runStepData = data as any;
41
+ if (runStepData?.name) {
42
+ console.log(`\n[${runStepData.name}] Processing...`);
43
+ }
44
+ aggregateContent({ event, data: data as t.RunStep });
45
+ },
46
+ },
47
+ [GraphEvents.ON_RUN_STEP_COMPLETED]: {
48
+ handle: (
49
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
50
+ data: t.StreamEventData
51
+ ): void => {
52
+ aggregateContent({
53
+ event,
54
+ data: data as unknown as { result: t.ToolEndEvent },
55
+ });
56
+ },
57
+ },
58
+ [GraphEvents.ON_MESSAGE_DELTA]: {
59
+ handle: (
60
+ event: GraphEvents.ON_MESSAGE_DELTA,
61
+ data: t.StreamEventData
62
+ ): void => {
63
+ aggregateContent({ event, data: data as t.MessageDeltaEvent });
64
+ },
65
+ },
66
+ [GraphEvents.TOOL_START]: {
67
+ handle: (
68
+ _event: string,
69
+ data: t.StreamEventData,
70
+ metadata?: Record<string, unknown>
71
+ ): void => {
72
+ const toolData = data as any;
73
+ if (toolData?.name?.includes('transfer_to_')) {
74
+ const specialist = toolData.name.replace('transfer_to_', '');
75
+ console.log(`\n🔀 Transferring to ${specialist}...`);
76
+ selectedRole = specialist;
77
+ }
78
+ },
79
+ },
80
+ };
81
+
82
+ // Function to create the graph with a single edge to multiple specialists
83
+ function createSupervisorGraphWithListEdge(): t.RunConfig {
84
+ console.log(`\nCreating graph with supervisor and 5 specialist agents.`);
85
+ console.log(
86
+ 'Using a SINGLE edge with multiple destinations (list-based handoff).\n'
87
+ );
88
+
89
+ // Define the adaptive specialist configuration that will be reused
90
+ const specialistConfig = {
91
+ provider: Providers.ANTHROPIC,
92
+ clientOptions: {
93
+ modelName: 'claude-3-5-sonnet-latest',
94
+ apiKey: process.env.ANTHROPIC_API_KEY,
95
+ },
96
+ instructions: `You are an Adaptive Specialist. Your agent ID indicates your role:
97
+
98
+ - data_analyst: Focus on statistical analysis, metrics, ML evaluation, A/B testing
99
+ - security_expert: Focus on cybersecurity, vulnerability assessment, compliance
100
+ - product_designer: Focus on UX/UI design, user research, accessibility
101
+ - devops_engineer: Focus on CI/CD, infrastructure, cloud platforms, monitoring
102
+ - legal_advisor: Focus on licensing, privacy laws, contracts, regulatory compliance
103
+
104
+ The supervisor will provide specific instructions. Follow them while maintaining your expert perspective.`,
105
+ maxContextTokens: 8000,
106
+ };
107
+
108
+ // Create the graph with supervisor and all 5 specialists
109
+ const agents: t.AgentInputs[] = [
110
+ {
111
+ agentId: 'supervisor',
112
+ provider: Providers.ANTHROPIC,
113
+ clientOptions: {
114
+ modelName: 'claude-3-5-sonnet-latest',
115
+ apiKey: process.env.ANTHROPIC_API_KEY,
116
+ },
117
+ instructions: `You are a Task Supervisor with access to 5 specialist agents:
118
+ 1. transfer_to_data_analyst - For statistical analysis and metrics
119
+ 2. transfer_to_security_expert - For cybersecurity and vulnerability assessment
120
+ 3. transfer_to_product_designer - For UX/UI design
121
+ 4. transfer_to_devops_engineer - For infrastructure and deployment
122
+ 5. transfer_to_legal_advisor - For compliance and licensing
123
+
124
+ Your role is to:
125
+ 1. Analyze the incoming request
126
+ 2. Decide which specialist is best suited
127
+ 3. Use the appropriate transfer tool (e.g., transfer_to_data_analyst)
128
+ 4. Provide specific instructions to guide their work
129
+
130
+ Be specific about what you need from the specialist.`,
131
+ maxContextTokens: 8000,
132
+ },
133
+ // Include all 5 specialists with the same adaptive configuration
134
+ {
135
+ agentId: 'data_analyst',
136
+ ...specialistConfig,
137
+ },
138
+ {
139
+ agentId: 'security_expert',
140
+ ...specialistConfig,
141
+ },
142
+ {
143
+ agentId: 'product_designer',
144
+ ...specialistConfig,
145
+ },
146
+ {
147
+ agentId: 'devops_engineer',
148
+ ...specialistConfig,
149
+ },
150
+ {
151
+ agentId: 'legal_advisor',
152
+ ...specialistConfig,
153
+ },
154
+ ];
155
+
156
+ // Create a SINGLE edge from supervisor to ALL 5 specialists using a list
157
+ const edges: t.GraphEdge[] = [
158
+ {
159
+ from: 'supervisor',
160
+ to: [
161
+ 'data_analyst',
162
+ 'security_expert',
163
+ 'product_designer',
164
+ 'devops_engineer',
165
+ 'legal_advisor',
166
+ ],
167
+ description:
168
+ 'Transfer to appropriate specialist based on task requirements',
169
+ edgeType: 'handoff',
170
+ },
171
+ ];
172
+
173
+ return {
174
+ runId: `supervisor-list-handoff-${Date.now()}`,
175
+ graphConfig: {
176
+ type: 'multi-agent',
177
+ agents,
178
+ edges,
179
+ },
180
+ customHandlers,
181
+ returnContent: true,
182
+ };
183
+ }
184
+
185
+ try {
186
+ // Test with different queries
187
+ const testQueries = [
188
+ // 'How can we analyze user engagement metrics to improve our product?',
189
+ // 'What security measures should we implement for our new API?',
190
+ // 'Can you help design a better onboarding flow for our mobile app?',
191
+ // 'We need to set up a CI/CD pipeline for our microservices.',
192
+ 'What are the legal implications of using GPL-licensed code in our product?',
193
+ ];
194
+
195
+ const config = {
196
+ configurable: {
197
+ thread_id: 'supervisor-list-handoff-1',
198
+ },
199
+ streamMode: 'values',
200
+ version: 'v2' as const,
201
+ };
202
+
203
+ for (const query of testQueries) {
204
+ console.log(`\n${'='.repeat(60)}`);
205
+ console.log(`USER QUERY: "${query}"`);
206
+ console.log('='.repeat(60));
207
+
208
+ // Reset conversation
209
+ conversationHistory.length = 0;
210
+ conversationHistory.push(new HumanMessage(query));
211
+
212
+ // Create graph with supervisor having a single edge to multiple specialists
213
+ const runConfig = createSupervisorGraphWithListEdge();
214
+ const run = await Run.create(runConfig);
215
+
216
+ console.log('Processing request...');
217
+
218
+ // Process with streaming
219
+ const inputs = {
220
+ messages: conversationHistory,
221
+ };
222
+
223
+ const finalContentParts = await run.processStream(inputs, config);
224
+ const finalMessages = run.getRunMessages();
225
+
226
+ if (finalMessages) {
227
+ conversationHistory.push(...finalMessages);
228
+ }
229
+
230
+ // Show summary
231
+ console.log(`\n${'─'.repeat(60)}`);
232
+ console.log(`Graph structure:`);
233
+ console.log(`- Agents: 6 total (supervisor + 5 specialists)`);
234
+ console.log(`- Edges: 1 edge with multiple destinations`);
235
+ console.log(
236
+ `- Edge type: handoff (creates individual tools for each destination)`
237
+ );
238
+ console.log(
239
+ `- Result: Supervisor has 5 handoff tools from a single edge`
240
+ );
241
+ console.log('─'.repeat(60));
242
+ }
243
+
244
+ // Final summary
245
+ console.log(`\n${'='.repeat(60)}`);
246
+ console.log('TEST COMPLETE');
247
+ console.log('='.repeat(60));
248
+ console.log('\nThis test demonstrates that a single edge with multiple');
249
+ console.log('destinations in the "to" field creates individual handoff');
250
+ console.log('tools for each destination agent, achieving the same result');
251
+ console.log('as creating separate edges for each specialist.');
252
+ } catch (error) {
253
+ console.error('Error in supervisor list handoff test:', error);
254
+ }
255
+ }
256
+
257
+ // Run the test
258
+ testSupervisorListHandoff();
@@ -8,7 +8,6 @@ import type * as t from '@/types';
8
8
  import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
9
9
  import { ToolEndHandler, ModelEndHandler } from '@/events';
10
10
 
11
-
12
11
  import { getArgs } from '@/scripts/args';
13
12
  import { Run } from '@/run';
14
13
  import { GraphEvents, Callback } from '@/common';
@@ -19,42 +18,73 @@ async function testStandardStreaming(): Promise<void> {
19
18
  const { userName, location, provider, currentDate } = await getArgs();
20
19
  const { contentParts, aggregateContent } = createContentAggregator();
21
20
  const customHandlers = {
22
- [GraphEvents.TOOL_END]: new ToolEndHandler(),
21
+ [GraphEvents.TOOL_END]: new ToolEndHandler(undefined, (name?: string) => {
22
+ return true;
23
+ }),
23
24
  [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
24
25
  [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
25
26
  [GraphEvents.ON_RUN_STEP_COMPLETED]: {
26
- handle: (event: GraphEvents.ON_RUN_STEP_COMPLETED, data: t.StreamEventData): void => {
27
+ handle: (
28
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
29
+ data: t.StreamEventData
30
+ ): void => {
27
31
  console.log('====== ON_RUN_STEP_COMPLETED ======');
28
- // console.dir(data, { depth: null });
29
- aggregateContent({ event, data: data as unknown as { result: t.ToolEndEvent } });
30
- }
32
+ console.dir(data, { depth: null });
33
+ aggregateContent({
34
+ event,
35
+ data: data as unknown as { result: t.ToolEndEvent },
36
+ });
37
+ },
31
38
  },
32
39
  [GraphEvents.ON_RUN_STEP]: {
33
- handle: (event: GraphEvents.ON_RUN_STEP, data: t.StreamEventData): void => {
40
+ handle: (
41
+ event: GraphEvents.ON_RUN_STEP,
42
+ data: t.StreamEventData
43
+ ): void => {
34
44
  console.log('====== ON_RUN_STEP ======');
35
45
  console.dir(data, { depth: null });
36
46
  aggregateContent({ event, data: data as t.RunStep });
37
- }
47
+ },
38
48
  },
39
49
  [GraphEvents.ON_RUN_STEP_DELTA]: {
40
- handle: (event: GraphEvents.ON_RUN_STEP_DELTA, data: t.StreamEventData): void => {
50
+ handle: (
51
+ event: GraphEvents.ON_RUN_STEP_DELTA,
52
+ data: t.StreamEventData
53
+ ): void => {
41
54
  console.log('====== ON_RUN_STEP_DELTA ======');
42
55
  console.dir(data, { depth: null });
43
56
  aggregateContent({ event, data: data as t.RunStepDeltaEvent });
44
- }
57
+ },
45
58
  },
46
59
  [GraphEvents.ON_MESSAGE_DELTA]: {
47
- handle: (event: GraphEvents.ON_MESSAGE_DELTA, data: t.StreamEventData): void => {
60
+ handle: (
61
+ event: GraphEvents.ON_MESSAGE_DELTA,
62
+ data: t.StreamEventData
63
+ ): void => {
48
64
  console.log('====== ON_MESSAGE_DELTA ======');
49
65
  console.dir(data, { depth: null });
50
66
  aggregateContent({ event, data: data as t.MessageDeltaEvent });
51
- }
67
+ },
68
+ },
69
+ [GraphEvents.ON_REASONING_DELTA]: {
70
+ handle: (
71
+ event: GraphEvents.ON_REASONING_DELTA,
72
+ data: t.StreamEventData
73
+ ) => {
74
+ console.log('====== ON_REASONING_DELTA ======');
75
+ console.dir(data, { depth: null });
76
+ aggregateContent({ event, data: data as t.ReasoningDeltaEvent });
77
+ },
52
78
  },
53
79
  [GraphEvents.TOOL_START]: {
54
- handle: (_event: string, data: t.StreamEventData, metadata?: Record<string, unknown>): void => {
80
+ handle: (
81
+ _event: string,
82
+ data: t.StreamEventData,
83
+ metadata?: Record<string, unknown>
84
+ ): void => {
55
85
  console.log('====== TOOL_START ======');
56
- // console.dir(data, { depth: null });
57
- }
86
+ console.dir(data, { depth: null });
87
+ },
58
88
  },
59
89
  };
60
90
 
@@ -66,7 +96,8 @@ async function testStandardStreaming(): Promise<void> {
66
96
  type: 'standard',
67
97
  llmConfig,
68
98
  tools: [new TavilySearchResults()],
69
- instructions: 'You are a friendly AI assistant. Always address the user by their name.',
99
+ instructions:
100
+ 'You are a friendly AI assistant. Always address the user by their name.',
70
101
  additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
71
102
  },
72
103
  returnContent: true,
@@ -86,7 +117,6 @@ async function testStandardStreaming(): Promise<void> {
86
117
 
87
118
  const userMessage = `
88
119
  Make a search for the weather in ${location} today, which is ${currentDate}.
89
- Before making the search, please let me know what you're about to do, then immediately start searching without hesitation.
90
120
  Make sure to always refer to me by name, which is ${userName}.
91
121
  After giving me a thorough summary, tell me a joke about the weather forecast we went over.
92
122
  `;
@@ -102,7 +132,7 @@ async function testStandardStreaming(): Promise<void> {
102
132
  conversationHistory.push(...finalMessages);
103
133
  console.dir(conversationHistory, { depth: null });
104
134
  }
105
- // console.dir(finalContentParts, { depth: null });
135
+ console.dir(finalContentParts, { depth: null });
106
136
  console.log('\n\n====================\n\n');
107
137
  // console.dir(contentParts, { depth: null });
108
138
  }