@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,361 @@
1
+ import { config } from 'dotenv';
2
+ config();
3
+
4
+ import { HumanMessage, BaseMessage } from '@langchain/core/messages';
5
+ import { Run } from '@/run';
6
+ import { Providers, GraphEvents } from '@/common';
7
+ import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
8
+ import { ToolEndHandler, ModelEndHandler } from '@/events';
9
+ import type * as t from '@/types';
10
+
11
+ const conversationHistory: BaseMessage[] = [];
12
+
13
+ /**
14
+ * Example of supervisor-based multi-agent system
15
+ *
16
+ * The supervisor has handoff tools for 5 different specialists.
17
+ * To demonstrate the concept while respecting LangGraph constraints,
18
+ * we show two approaches:
19
+ *
20
+ * 1. All 5 specialists exist but share the same adaptive configuration
21
+ * 2. Only 2 agents total by using a single adaptive specialist (requires workaround)
22
+ */
23
+ async function testSupervisorMultiAgent() {
24
+ console.log('Testing Supervisor-Based Multi-Agent System...\n');
25
+
26
+ // NOTE: To truly have only 2 agents with 5 handoff tools, you would need:
27
+ // 1. Custom tool implementation (see multi-agent-supervisor-mock.ts)
28
+ // 2. Or modify MultiAgentGraph to support "virtual" agents
29
+ // 3. Or use a single conditional edge with role parameter
30
+ //
31
+ // This example shows the concept using 6 agents that share configuration
32
+
33
+ // Set up content aggregator
34
+ const { contentParts, aggregateContent } = createContentAggregator();
35
+
36
+ // Define configurations for all possible specialists
37
+ const specialistConfigs = {
38
+ data_analyst: {
39
+ provider: Providers.ANTHROPIC,
40
+ clientOptions: {
41
+ modelName: 'claude-3-5-sonnet-latest',
42
+ apiKey: process.env.ANTHROPIC_API_KEY,
43
+ },
44
+ instructions: `You are a Data Analyst specialist. Your expertise includes:
45
+ - Statistical analysis and data visualization
46
+ - SQL queries and database optimization
47
+ - Python/R for data science
48
+ - Machine learning model evaluation
49
+ - A/B testing and experiment design
50
+
51
+ Follow the supervisor's specific instructions carefully.`,
52
+ maxContextTokens: 8000,
53
+ },
54
+ security_expert: {
55
+ provider: Providers.ANTHROPIC,
56
+ clientOptions: {
57
+ modelName: 'claude-3-5-sonnet-latest',
58
+ apiKey: process.env.ANTHROPIC_API_KEY,
59
+ },
60
+ instructions: `You are a Security Expert. Your expertise includes:
61
+ - Cybersecurity best practices
62
+ - Vulnerability assessment and penetration testing
63
+ - Security architecture and threat modeling
64
+ - Compliance (GDPR, HIPAA, SOC2, etc.)
65
+ - Incident response and forensics
66
+
67
+ Follow the supervisor's specific instructions carefully.`,
68
+ maxContextTokens: 8000,
69
+ },
70
+ product_designer: {
71
+ provider: Providers.ANTHROPIC,
72
+ clientOptions: {
73
+ modelName: 'claude-3-5-sonnet-latest',
74
+ apiKey: process.env.ANTHROPIC_API_KEY,
75
+ },
76
+ instructions: `You are a Product Designer. Your expertise includes:
77
+ - User experience (UX) design principles
78
+ - User interface (UI) design and prototyping
79
+ - Design systems and component libraries
80
+ - User research and usability testing
81
+ - Accessibility and inclusive design
82
+
83
+ Follow the supervisor's specific instructions carefully.`,
84
+ maxContextTokens: 8000,
85
+ },
86
+ devops_engineer: {
87
+ provider: Providers.ANTHROPIC,
88
+ clientOptions: {
89
+ modelName: 'claude-3-5-sonnet-latest',
90
+ apiKey: process.env.ANTHROPIC_API_KEY,
91
+ },
92
+ instructions: `You are a DevOps Engineer. Your expertise includes:
93
+ - CI/CD pipeline design and optimization
94
+ - Infrastructure as Code (Terraform, CloudFormation)
95
+ - Container orchestration (Kubernetes, Docker)
96
+ - Cloud platforms (AWS, GCP, Azure)
97
+ - Monitoring, logging, and observability
98
+
99
+ Follow the supervisor's specific instructions carefully.`,
100
+ maxContextTokens: 8000,
101
+ },
102
+ legal_advisor: {
103
+ provider: Providers.ANTHROPIC,
104
+ clientOptions: {
105
+ modelName: 'claude-3-5-sonnet-latest',
106
+ apiKey: process.env.ANTHROPIC_API_KEY,
107
+ },
108
+ instructions: `You are a Legal Advisor specializing in technology. Your expertise includes:
109
+ - Software licensing and open source compliance
110
+ - Data privacy and protection laws
111
+ - Intellectual property and patents
112
+ - Contract review and negotiation
113
+ - Regulatory compliance for tech companies
114
+
115
+ Follow the supervisor's specific instructions carefully.`,
116
+ maxContextTokens: 8000,
117
+ },
118
+ };
119
+
120
+ // Track which specialist role was selected
121
+ let selectedRole = '';
122
+ let roleInstructions = '';
123
+
124
+ // Create custom handlers
125
+ const customHandlers = {
126
+ [GraphEvents.TOOL_END]: new ToolEndHandler(),
127
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
128
+ [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
129
+ [GraphEvents.ON_RUN_STEP]: {
130
+ handle: (
131
+ event: GraphEvents.ON_RUN_STEP,
132
+ data: t.StreamEventData
133
+ ): void => {
134
+ const runStepData = data as any;
135
+ if (runStepData?.name) {
136
+ console.log(`\n[${runStepData.name}] Processing...`);
137
+ }
138
+ aggregateContent({ event, data: data as t.RunStep });
139
+ },
140
+ },
141
+ [GraphEvents.ON_RUN_STEP_COMPLETED]: {
142
+ handle: (
143
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
144
+ data: t.StreamEventData
145
+ ): void => {
146
+ aggregateContent({
147
+ event,
148
+ data: data as unknown as { result: t.ToolEndEvent },
149
+ });
150
+ },
151
+ },
152
+ [GraphEvents.ON_MESSAGE_DELTA]: {
153
+ handle: (
154
+ event: GraphEvents.ON_MESSAGE_DELTA,
155
+ data: t.StreamEventData
156
+ ): void => {
157
+ aggregateContent({ event, data: data as t.MessageDeltaEvent });
158
+ },
159
+ },
160
+ [GraphEvents.TOOL_START]: {
161
+ handle: (
162
+ _event: string,
163
+ data: t.StreamEventData,
164
+ metadata?: Record<string, unknown>
165
+ ): void => {
166
+ const toolData = data as any;
167
+ if (toolData?.name?.includes('transfer_to_')) {
168
+ const specialist = toolData.name.replace('transfer_to_', '');
169
+ console.log(`\n🔀 Transferring to ${specialist}...`);
170
+ selectedRole = specialist;
171
+ }
172
+ },
173
+ },
174
+ };
175
+
176
+ // Function to create the graph with supervisor having multiple handoff options
177
+ function createSupervisorGraph(): t.RunConfig {
178
+ console.log(`\nCreating graph with supervisor and 5 specialist agents.`);
179
+ console.log('All specialists share the same adaptive configuration.\n');
180
+
181
+ // Define the adaptive specialist configuration that will be reused
182
+ const specialistConfig = {
183
+ provider: Providers.ANTHROPIC,
184
+ clientOptions: {
185
+ modelName: 'claude-3-5-sonnet-latest',
186
+ apiKey: process.env.ANTHROPIC_API_KEY,
187
+ },
188
+ instructions: `You are an Adaptive Specialist. Your agent ID indicates your role:
189
+
190
+ - data_analyst: Focus on statistical analysis, metrics, ML evaluation, A/B testing
191
+ - security_expert: Focus on cybersecurity, vulnerability assessment, compliance
192
+ - product_designer: Focus on UX/UI design, user research, accessibility
193
+ - devops_engineer: Focus on CI/CD, infrastructure, cloud platforms, monitoring
194
+ - legal_advisor: Focus on licensing, privacy laws, contracts, regulatory compliance
195
+
196
+ The supervisor will provide specific instructions. Follow them while maintaining your expert perspective.`,
197
+ maxContextTokens: 8000,
198
+ };
199
+
200
+ // Create the graph with supervisor and all 5 specialists
201
+ // All specialists share the same adaptive configuration
202
+ const agents: t.AgentInputs[] = [
203
+ {
204
+ agentId: 'supervisor',
205
+ provider: Providers.ANTHROPIC,
206
+ clientOptions: {
207
+ modelName: 'claude-3-5-sonnet-latest',
208
+ apiKey: process.env.ANTHROPIC_API_KEY,
209
+ },
210
+ instructions: `You are a Task Supervisor with access to 5 specialist agents:
211
+ 1. transfer_to_data_analyst - For statistical analysis and metrics
212
+ 2. transfer_to_security_expert - For cybersecurity and vulnerability assessment
213
+ 3. transfer_to_product_designer - For UX/UI design
214
+ 4. transfer_to_devops_engineer - For infrastructure and deployment
215
+ 5. transfer_to_legal_advisor - For compliance and licensing
216
+
217
+ Your role is to:
218
+ 1. Analyze the incoming request
219
+ 2. Decide which specialist is best suited
220
+ 3. Use the appropriate transfer tool (e.g., transfer_to_data_analyst)
221
+ 4. Provide specific instructions to guide their work
222
+
223
+ Be specific about what you need from the specialist.`,
224
+ maxContextTokens: 8000,
225
+ },
226
+ // Include all 5 specialists with the same adaptive configuration
227
+ {
228
+ agentId: 'data_analyst',
229
+ ...specialistConfig,
230
+ },
231
+ {
232
+ agentId: 'security_expert',
233
+ ...specialistConfig,
234
+ },
235
+ {
236
+ agentId: 'product_designer',
237
+ ...specialistConfig,
238
+ },
239
+ {
240
+ agentId: 'devops_engineer',
241
+ ...specialistConfig,
242
+ },
243
+ {
244
+ agentId: 'legal_advisor',
245
+ ...specialistConfig,
246
+ },
247
+ ];
248
+
249
+ // Create edges from supervisor to all 5 specialists
250
+ const edges: t.GraphEdge[] = [
251
+ {
252
+ from: 'supervisor',
253
+ to: 'data_analyst',
254
+ description:
255
+ 'Transfer to data analyst for statistical analysis and metrics',
256
+ edgeType: 'handoff',
257
+ },
258
+ {
259
+ from: 'supervisor',
260
+ to: 'security_expert',
261
+ description: 'Transfer to security expert for cybersecurity assessment',
262
+ edgeType: 'handoff',
263
+ },
264
+ {
265
+ from: 'supervisor',
266
+ to: 'product_designer',
267
+ description: 'Transfer to product designer for UX/UI design',
268
+ edgeType: 'handoff',
269
+ },
270
+ {
271
+ from: 'supervisor',
272
+ to: 'devops_engineer',
273
+ description:
274
+ 'Transfer to DevOps engineer for infrastructure and deployment',
275
+ edgeType: 'handoff',
276
+ },
277
+ {
278
+ from: 'supervisor',
279
+ to: 'legal_advisor',
280
+ description: 'Transfer to legal advisor for compliance and licensing',
281
+ edgeType: 'handoff',
282
+ },
283
+ ];
284
+
285
+ return {
286
+ runId: `supervisor-multi-agent-${Date.now()}`,
287
+ graphConfig: {
288
+ type: 'multi-agent',
289
+ agents,
290
+ edges,
291
+ },
292
+ customHandlers,
293
+ returnContent: true,
294
+ };
295
+ }
296
+
297
+ try {
298
+ // Test with different queries
299
+ const testQueries = [
300
+ 'How can we analyze user engagement metrics to improve our product?',
301
+ 'What security measures should we implement for our new API?',
302
+ 'Can you help design a better onboarding flow for our mobile app?',
303
+ 'We need to set up a CI/CD pipeline for our microservices.',
304
+ 'What are the legal implications of using GPL-licensed code in our product?',
305
+ ];
306
+
307
+ const config = {
308
+ configurable: {
309
+ thread_id: 'supervisor-conversation-1',
310
+ },
311
+ streamMode: 'values',
312
+ version: 'v2' as const,
313
+ };
314
+
315
+ for (const query of testQueries) {
316
+ console.log(`\n${'='.repeat(60)}`);
317
+ console.log(`USER QUERY: "${query}"`);
318
+ console.log('='.repeat(60));
319
+
320
+ // Reset conversation
321
+ conversationHistory.length = 0;
322
+ conversationHistory.push(new HumanMessage(query));
323
+
324
+ // Create graph with supervisor having 5 handoff tools to 1 adaptive specialist
325
+ const runConfig = createSupervisorGraph();
326
+ const run = await Run.create(runConfig);
327
+
328
+ console.log('Processing request...');
329
+
330
+ // Process with streaming
331
+ const inputs = {
332
+ messages: conversationHistory,
333
+ };
334
+
335
+ const finalContentParts = await run.processStream(inputs, config);
336
+ const finalMessages = run.getRunMessages();
337
+
338
+ if (finalMessages) {
339
+ conversationHistory.push(...finalMessages);
340
+ }
341
+
342
+ // Show summary
343
+ console.log(`\n${'─'.repeat(60)}`);
344
+ console.log(`Agents in graph: 6 total (supervisor + 5 specialists)`);
345
+ console.log(`All specialists share the same adaptive configuration`);
346
+ console.log(
347
+ `Supervisor tools: transfer_to_data_analyst, transfer_to_security_expert,`
348
+ );
349
+ console.log(
350
+ ` transfer_to_product_designer, transfer_to_devops_engineer,`
351
+ );
352
+ console.log(` transfer_to_legal_advisor`);
353
+ console.log('─'.repeat(60));
354
+ }
355
+ } catch (error) {
356
+ console.error('Error in supervisor multi-agent test:', error);
357
+ }
358
+ }
359
+
360
+ // Run the test
361
+ testSupervisorMultiAgent();
@@ -0,0 +1,186 @@
1
+ import { config } from 'dotenv';
2
+ config();
3
+
4
+ import { HumanMessage, BaseMessage } from '@langchain/core/messages';
5
+ import { Run } from '@/run';
6
+ import { Providers, GraphEvents } from '@/common';
7
+ import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
8
+ import { ToolEndHandler, ModelEndHandler } from '@/events';
9
+ import type * as t from '@/types';
10
+
11
+ const conversationHistory: BaseMessage[] = [];
12
+
13
+ async function testMultiAgentHandoff() {
14
+ console.log('Testing Multi-Agent Handoff System...\n');
15
+
16
+ // Set up content aggregator
17
+ const { contentParts, aggregateContent } = createContentAggregator();
18
+
19
+ // Define agent configurations
20
+ const agents: t.AgentInputs[] = [
21
+ {
22
+ agentId: 'flight_assistant',
23
+ provider: Providers.ANTHROPIC,
24
+ clientOptions: {
25
+ modelName: 'claude-3-5-sonnet-latest',
26
+ apiKey: process.env.ANTHROPIC_API_KEY,
27
+ },
28
+ instructions:
29
+ 'You are a flight booking assistant. Help users book flights between airports.',
30
+ maxContextTokens: 28000,
31
+ },
32
+ {
33
+ agentId: 'hotel_assistant',
34
+ provider: Providers.ANTHROPIC,
35
+ clientOptions: {
36
+ modelName: 'claude-3-5-sonnet-latest',
37
+ apiKey: process.env.ANTHROPIC_API_KEY,
38
+ },
39
+ instructions:
40
+ 'You are a hotel booking assistant. Help users book hotel stays.',
41
+ maxContextTokens: 28000,
42
+ },
43
+ ];
44
+
45
+ // Define edges (handoff relationships)
46
+ // These edges create handoff tools that agents can use to transfer control dynamically
47
+ const edges: t.GraphEdge[] = [
48
+ {
49
+ from: 'flight_assistant',
50
+ to: 'hotel_assistant',
51
+ description:
52
+ 'Transfer to hotel booking assistant when user needs hotel assistance',
53
+ // edgeType defaults to 'handoff' for single-to-single edges
54
+ },
55
+ {
56
+ from: 'hotel_assistant',
57
+ to: 'flight_assistant',
58
+ description:
59
+ 'Transfer to flight booking assistant when user needs flight assistance',
60
+ // edgeType defaults to 'handoff' for single-to-single edges
61
+ },
62
+ ];
63
+
64
+ // Create custom handlers similar to examples
65
+ const customHandlers = {
66
+ [GraphEvents.TOOL_END]: new ToolEndHandler(),
67
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
68
+ [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
69
+ [GraphEvents.ON_RUN_STEP_COMPLETED]: {
70
+ handle: (
71
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
72
+ data: t.StreamEventData
73
+ ): void => {
74
+ console.log('====== ON_RUN_STEP_COMPLETED ======');
75
+ console.dir(data, { depth: null });
76
+ aggregateContent({
77
+ event,
78
+ data: data as unknown as { result: t.ToolEndEvent },
79
+ });
80
+ },
81
+ },
82
+ [GraphEvents.ON_RUN_STEP]: {
83
+ handle: (
84
+ event: GraphEvents.ON_RUN_STEP,
85
+ data: t.StreamEventData
86
+ ): void => {
87
+ console.log('====== ON_RUN_STEP ======');
88
+ console.dir(data, { depth: null });
89
+ aggregateContent({ event, data: data as t.RunStep });
90
+ },
91
+ },
92
+ [GraphEvents.ON_RUN_STEP_DELTA]: {
93
+ handle: (
94
+ event: GraphEvents.ON_RUN_STEP_DELTA,
95
+ data: t.StreamEventData
96
+ ): void => {
97
+ console.log('====== ON_RUN_STEP_DELTA ======');
98
+ console.dir(data, { depth: null });
99
+ aggregateContent({ event, data: data as t.RunStepDeltaEvent });
100
+ },
101
+ },
102
+ [GraphEvents.ON_MESSAGE_DELTA]: {
103
+ handle: (
104
+ event: GraphEvents.ON_MESSAGE_DELTA,
105
+ data: t.StreamEventData
106
+ ): void => {
107
+ console.log('====== ON_MESSAGE_DELTA ======');
108
+ console.dir(data, { depth: null });
109
+ aggregateContent({ event, data: data as t.MessageDeltaEvent });
110
+ },
111
+ },
112
+ [GraphEvents.ON_REASONING_DELTA]: {
113
+ handle: (
114
+ event: GraphEvents.ON_REASONING_DELTA,
115
+ data: t.StreamEventData
116
+ ): void => {
117
+ console.log('====== ON_REASONING_DELTA ======');
118
+ console.dir(data, { depth: null });
119
+ aggregateContent({ event, data: data as t.ReasoningDeltaEvent });
120
+ },
121
+ },
122
+ [GraphEvents.TOOL_START]: {
123
+ handle: (
124
+ _event: string,
125
+ data: t.StreamEventData,
126
+ metadata?: Record<string, unknown>
127
+ ): void => {
128
+ console.log('====== TOOL_START ======');
129
+ console.dir(data, { depth: null });
130
+ },
131
+ },
132
+ };
133
+
134
+ // Create multi-agent run configuration
135
+ const runConfig: t.RunConfig = {
136
+ runId: `multi-agent-test-${Date.now()}`,
137
+ graphConfig: {
138
+ type: 'multi-agent',
139
+ agents,
140
+ edges,
141
+ },
142
+ customHandlers,
143
+ returnContent: true,
144
+ };
145
+
146
+ try {
147
+ // Create and execute the run
148
+ const run = await Run.create(runConfig);
149
+
150
+ const userMessage =
151
+ 'I need to book a flight from Boston to New York, and also need a hotel near Times Square.';
152
+ conversationHistory.push(new HumanMessage(userMessage));
153
+
154
+ console.log('Invoking multi-agent graph...\n');
155
+
156
+ const config = {
157
+ configurable: {
158
+ thread_id: 'multi-agent-conversation-1',
159
+ },
160
+ streamMode: 'values',
161
+ version: 'v2' as const,
162
+ };
163
+
164
+ // Process with streaming
165
+ const inputs = {
166
+ messages: conversationHistory,
167
+ };
168
+
169
+ const finalContentParts = await run.processStream(inputs, config);
170
+ const finalMessages = run.getRunMessages();
171
+
172
+ if (finalMessages) {
173
+ conversationHistory.push(...finalMessages);
174
+ console.log('\n\nConversation history:');
175
+ console.dir(conversationHistory, { depth: null });
176
+ }
177
+
178
+ console.log('\n\nFinal content parts:');
179
+ console.dir(contentParts, { depth: null });
180
+ } catch (error) {
181
+ console.error('Error in multi-agent test:', error);
182
+ }
183
+ }
184
+
185
+ // Run the test
186
+ testMultiAgentHandoff();
@@ -39,8 +39,6 @@ async function testStandardStreaming(): Promise<void> {
39
39
  event: GraphEvents.ON_RUN_STEP,
40
40
  data: t.StreamEventData
41
41
  ): void => {
42
- console.log('====== ON_RUN_STEP ======');
43
- console.dir(data, { depth: null });
44
42
  aggregateContent({ event, data: data as t.RunStep });
45
43
  },
46
44
  },
@@ -49,8 +47,6 @@ async function testStandardStreaming(): Promise<void> {
49
47
  event: GraphEvents.ON_RUN_STEP_DELTA,
50
48
  data: t.StreamEventData
51
49
  ): void => {
52
- console.log('====== ON_RUN_STEP_DELTA ======');
53
- console.dir(data, { depth: null });
54
50
  aggregateContent({ event, data: data as t.RunStepDeltaEvent });
55
51
  },
56
52
  },
@@ -59,8 +55,6 @@ async function testStandardStreaming(): Promise<void> {
59
55
  event: GraphEvents.ON_MESSAGE_DELTA,
60
56
  data: t.StreamEventData
61
57
  ): void => {
62
- console.log('====== ON_MESSAGE_DELTA ======');
63
- console.dir(data, { depth: null });
64
58
  aggregateContent({ event, data: data as t.MessageDeltaEvent });
65
59
  },
66
60
  },
@@ -133,9 +127,7 @@ async function testStandardStreaming(): Promise<void> {
133
127
  }
134
128
 
135
129
  process.on('unhandledRejection', (reason, promise) => {
136
- console.error('Unhandled Rejection at:', promise, 'reason:', reason);
137
- console.log('Conversation history:');
138
- process.exit(1);
130
+ console.warn('Unhandled Rejection (non-fatal):', reason);
139
131
  });
140
132
 
141
133
  testStandardStreaming().catch((err) => {
@@ -1,7 +1,12 @@
1
1
  // src/scripts/cli.ts
2
2
  import { config } from 'dotenv';
3
+ import { v4 as uuidv4 } from 'uuid';
3
4
  config();
4
- import { HumanMessage, BaseMessage } from '@langchain/core/messages';
5
+ import {
6
+ HumanMessage,
7
+ BaseMessage,
8
+ UsageMetadata,
9
+ } from '@langchain/core/messages';
5
10
  import { TavilySearchResults } from '@langchain/community/tools/tavily_search';
6
11
  import type * as t from '@/types';
7
12
  import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
@@ -10,21 +15,27 @@ import {
10
15
  ModelEndHandler,
11
16
  createMetadataAggregator,
12
17
  } from '@/events';
18
+ import { GraphEvents, Providers, TitleMethod } from '@/common';
13
19
  import { getLLMConfig } from '@/utils/llmConfig';
14
20
  import { getArgs } from '@/scripts/args';
15
- import { GraphEvents, Providers } from '@/common';
16
21
  import { Run } from '@/run';
17
22
 
18
23
  const conversationHistory: BaseMessage[] = [];
19
24
  let _contentParts: t.MessageContentComplex[] = [];
25
+ let collectedUsage: UsageMetadata[] = [];
20
26
 
21
27
  async function testStandardStreaming(): Promise<void> {
22
- const { userName, location, provider, currentDate } = await getArgs();
28
+ const {
29
+ userName,
30
+ location,
31
+ provider: _provider,
32
+ currentDate,
33
+ } = await getArgs();
23
34
  const { contentParts, aggregateContent } = createContentAggregator();
24
35
  _contentParts = contentParts as t.MessageContentComplex[];
25
36
  const customHandlers = {
26
37
  [GraphEvents.TOOL_END]: new ToolEndHandler(),
27
- [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
38
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
28
39
  [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
29
40
  [GraphEvents.ON_RUN_STEP_COMPLETED]: {
30
41
  handle: (
@@ -32,7 +43,7 @@ async function testStandardStreaming(): Promise<void> {
32
43
  data: t.StreamEventData
33
44
  ): void => {
34
45
  console.log('====== ON_RUN_STEP_COMPLETED ======');
35
- // console.dir(data, { depth: null });
46
+ console.dir(data, { depth: null });
36
47
  aggregateContent({
37
48
  event,
38
49
  data: data as unknown as { result: t.ToolEndEvent },
@@ -91,7 +102,7 @@ async function testStandardStreaming(): Promise<void> {
91
102
  },
92
103
  };
93
104
 
94
- const llmConfig = getLLMConfig(provider);
105
+ const llmConfig = getLLMConfig(_provider);
95
106
  if (
96
107
  'configuration' in llmConfig &&
97
108
  (llmConfig as t.OpenAIClientOptions).configuration != null
@@ -99,7 +110,7 @@ async function testStandardStreaming(): Promise<void> {
99
110
  const openAIConfig = llmConfig as t.OpenAIClientOptions;
100
111
  if (openAIConfig.configuration) {
101
112
  openAIConfig.configuration.fetch = (
102
- url: RequestInfo,
113
+ url: string | URL | Request,
103
114
  init?: RequestInit
104
115
  ) => {
105
116
  console.log('Fetching:', url);
@@ -107,6 +118,7 @@ async function testStandardStreaming(): Promise<void> {
107
118
  };
108
119
  }
109
120
  }
121
+ const provider = llmConfig.provider;
110
122
 
111
123
  if (provider === Providers.ANTHROPIC) {
112
124
  (llmConfig as t.AnthropicClientOptions).clientOptions = {
@@ -118,12 +130,12 @@ async function testStandardStreaming(): Promise<void> {
118
130
  }
119
131
 
120
132
  const run = await Run.create<t.IState>({
121
- runId: 'test-run-id',
133
+ runId: uuidv4(),
122
134
  graphConfig: {
123
135
  type: 'standard',
124
136
  llmConfig,
125
137
  // tools: [new TavilySearchResults()],
126
- reasoningKey: 'reasoning',
138
+ // reasoningKey: 'reasoning',
127
139
  instructions:
128
140
  'You are a friendly AI assistant. Always address the user by their name.',
129
141
  additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
@@ -160,8 +172,10 @@ async function testStandardStreaming(): Promise<void> {
160
172
  console.dir(contentParts, { depth: null });
161
173
  const { handleLLMEnd, collected } = createMetadataAggregator();
162
174
  const titleOptions: t.RunTitleOptions = {
175
+ provider,
163
176
  inputText: userMessage,
164
177
  contentParts,
178
+ // titleMethod: TitleMethod.STRUCTURED,
165
179
  chainOptions: {
166
180
  callbacks: [
167
181
  {
@@ -176,8 +190,9 @@ async function testStandardStreaming(): Promise<void> {
176
190
  };
177
191
  }
178
192
  const titleResult = await run.generateTitle(titleOptions);
193
+ console.log('Collected usage metadata:', collectedUsage);
179
194
  console.log('Generated Title:', titleResult);
180
- console.log('Collected metadata:', collected);
195
+ console.log('Collected title usage metadata:', collected);
181
196
  }
182
197
 
183
198
  process.on('unhandledRejection', (reason, promise) => {