@librechat/agents 2.4.322 → 3.0.0-rc10

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 (279) 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 +15 -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 -213
  8. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  9. package/dist/cjs/graphs/MultiAgentGraph.cjs +507 -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 +422 -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 +137 -85
  41. package/dist/cjs/run.cjs.map +1 -1
  42. package/dist/cjs/stream.cjs +86 -52
  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 +16 -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 -215
  75. package/dist/esm/graphs/Graph.mjs.map +1 -1
  76. package/dist/esm/graphs/MultiAgentGraph.mjs +505 -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 +421 -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 +138 -87
  108. package/dist/esm/run.mjs.map +1 -1
  109. package/dist/esm/stream.mjs +88 -55
  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 +17 -7
  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 +47 -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 +82 -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/stream.d.ts +10 -3
  161. package/dist/types/tools/CodeExecutor.d.ts +2 -2
  162. package/dist/types/tools/ToolNode.d.ts +1 -1
  163. package/dist/types/tools/handlers.d.ts +17 -4
  164. package/dist/types/tools/search/anthropic.d.ts +16 -0
  165. package/dist/types/tools/search/firecrawl.d.ts +15 -0
  166. package/dist/types/tools/search/rerankers.d.ts +0 -1
  167. package/dist/types/tools/search/types.d.ts +30 -9
  168. package/dist/types/types/graph.d.ts +129 -15
  169. package/dist/types/types/llm.d.ts +25 -10
  170. package/dist/types/types/run.d.ts +50 -8
  171. package/dist/types/types/stream.d.ts +16 -2
  172. package/dist/types/types/tools.d.ts +1 -1
  173. package/dist/types/utils/events.d.ts +6 -0
  174. package/dist/types/utils/title.d.ts +2 -1
  175. package/dist/types/utils/tokens.d.ts +24 -0
  176. package/package.json +41 -17
  177. package/src/agents/AgentContext.ts +315 -0
  178. package/src/common/enum.ts +15 -5
  179. package/src/events.ts +24 -13
  180. package/src/graphs/Graph.ts +495 -313
  181. package/src/graphs/MultiAgentGraph.ts +598 -0
  182. package/src/graphs/index.ts +2 -1
  183. package/src/llm/anthropic/Jacob_Lee_Resume_2023.pdf +0 -0
  184. package/src/llm/anthropic/index.ts +78 -13
  185. package/src/llm/anthropic/llm.spec.ts +491 -115
  186. package/src/llm/anthropic/types.ts +39 -3
  187. package/src/llm/anthropic/utils/message_inputs.ts +67 -11
  188. package/src/llm/anthropic/utils/message_outputs.ts +21 -2
  189. package/src/llm/anthropic/utils/output_parsers.ts +25 -6
  190. package/src/llm/anthropic/utils/tools.ts +29 -0
  191. package/src/llm/google/index.ts +218 -0
  192. package/src/llm/google/types.ts +43 -0
  193. package/src/llm/google/utils/common.ts +646 -0
  194. package/src/llm/google/utils/tools.ts +160 -0
  195. package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -0
  196. package/src/llm/ollama/index.ts +89 -0
  197. package/src/llm/ollama/utils.ts +193 -0
  198. package/src/llm/openai/index.ts +641 -14
  199. package/src/llm/openai/types.ts +24 -0
  200. package/src/llm/openai/utils/index.ts +912 -0
  201. package/src/llm/openai/utils/isReasoningModel.test.ts +90 -0
  202. package/src/llm/providers.ts +10 -9
  203. package/src/llm/text.ts +26 -7
  204. package/src/llm/vertexai/index.ts +360 -0
  205. package/src/messages/reducer.ts +80 -0
  206. package/src/run.ts +196 -116
  207. package/src/scripts/ant_web_search.ts +158 -0
  208. package/src/scripts/args.ts +12 -8
  209. package/src/scripts/cli4.ts +29 -21
  210. package/src/scripts/cli5.ts +29 -21
  211. package/src/scripts/code_exec.ts +54 -23
  212. package/src/scripts/code_exec_files.ts +48 -17
  213. package/src/scripts/code_exec_simple.ts +46 -27
  214. package/src/scripts/handoff-test.ts +135 -0
  215. package/src/scripts/image.ts +52 -20
  216. package/src/scripts/multi-agent-chain.ts +278 -0
  217. package/src/scripts/multi-agent-conditional.ts +220 -0
  218. package/src/scripts/multi-agent-document-review-chain.ts +197 -0
  219. package/src/scripts/multi-agent-hybrid-flow.ts +310 -0
  220. package/src/scripts/multi-agent-parallel.ts +341 -0
  221. package/src/scripts/multi-agent-sequence.ts +212 -0
  222. package/src/scripts/multi-agent-supervisor.ts +362 -0
  223. package/src/scripts/multi-agent-test.ts +186 -0
  224. package/src/scripts/search.ts +1 -9
  225. package/src/scripts/simple.ts +25 -10
  226. package/src/scripts/test-custom-prompt-key.ts +145 -0
  227. package/src/scripts/test-handoff-input.ts +170 -0
  228. package/src/scripts/test-multi-agent-list-handoff.ts +261 -0
  229. package/src/scripts/test-tools-before-handoff.ts +233 -0
  230. package/src/scripts/tools.ts +48 -18
  231. package/src/specs/anthropic.simple.test.ts +150 -34
  232. package/src/specs/azure.simple.test.ts +325 -0
  233. package/src/specs/openai.simple.test.ts +140 -33
  234. package/src/specs/openrouter.simple.test.ts +107 -0
  235. package/src/specs/prune.test.ts +4 -9
  236. package/src/specs/reasoning.test.ts +80 -44
  237. package/src/specs/token-memoization.test.ts +39 -0
  238. package/src/stream.test.ts +94 -0
  239. package/src/stream.ts +143 -61
  240. package/src/tools/ToolNode.ts +21 -7
  241. package/src/tools/handlers.ts +192 -18
  242. package/src/tools/search/anthropic.ts +51 -0
  243. package/src/tools/search/firecrawl.ts +69 -20
  244. package/src/tools/search/format.ts +6 -8
  245. package/src/tools/search/rerankers.ts +7 -40
  246. package/src/tools/search/search.ts +97 -16
  247. package/src/tools/search/tool.ts +5 -2
  248. package/src/tools/search/types.ts +30 -10
  249. package/src/tools/search/utils.ts +1 -1
  250. package/src/types/graph.ts +318 -103
  251. package/src/types/llm.ts +26 -12
  252. package/src/types/run.ts +56 -13
  253. package/src/types/stream.ts +22 -1
  254. package/src/types/tools.ts +16 -10
  255. package/src/utils/events.ts +32 -0
  256. package/src/utils/llmConfig.ts +19 -7
  257. package/src/utils/title.ts +104 -30
  258. package/src/utils/tokens.ts +69 -10
  259. package/dist/types/scripts/abort.d.ts +0 -1
  260. package/dist/types/scripts/args.d.ts +0 -6
  261. package/dist/types/scripts/caching.d.ts +0 -1
  262. package/dist/types/scripts/cli.d.ts +0 -1
  263. package/dist/types/scripts/cli2.d.ts +0 -1
  264. package/dist/types/scripts/cli3.d.ts +0 -1
  265. package/dist/types/scripts/cli4.d.ts +0 -1
  266. package/dist/types/scripts/cli5.d.ts +0 -1
  267. package/dist/types/scripts/code_exec.d.ts +0 -1
  268. package/dist/types/scripts/code_exec_files.d.ts +0 -1
  269. package/dist/types/scripts/code_exec_simple.d.ts +0 -1
  270. package/dist/types/scripts/content.d.ts +0 -1
  271. package/dist/types/scripts/empty_input.d.ts +0 -1
  272. package/dist/types/scripts/image.d.ts +0 -1
  273. package/dist/types/scripts/memory.d.ts +0 -1
  274. package/dist/types/scripts/search.d.ts +0 -1
  275. package/dist/types/scripts/simple.d.ts +0 -1
  276. package/dist/types/scripts/stream.d.ts +0 -1
  277. package/dist/types/scripts/thinking.d.ts +0 -1
  278. package/dist/types/scripts/tools.d.ts +0 -1
  279. package/dist/types/specs/spec.utils.d.ts +0 -1
package/src/run.ts CHANGED
@@ -1,32 +1,43 @@
1
1
  // src/run.ts
2
- import { zodToJsonSchema } from 'zod-to-json-schema';
3
2
  import { PromptTemplate } from '@langchain/core/prompts';
4
3
  import { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';
5
- import { SystemMessage } from '@langchain/core/messages';
6
4
  import type {
7
5
  BaseMessage,
8
6
  MessageContentComplex,
9
7
  } from '@langchain/core/messages';
10
- import type { ClientCallbacks, SystemCallbacks } from '@/graphs/Graph';
11
8
  import type { RunnableConfig } from '@langchain/core/runnables';
12
9
  import type * as t from '@/types';
13
- import { GraphEvents, Providers, Callback } from '@/common';
14
- import { manualToolStreamProviders } from '@/llm/providers';
15
- import { shiftIndexTokenCountMap } from '@/messages/format';
16
- import { createTitleRunnable } from '@/utils/title';
10
+ import {
11
+ createCompletionTitleRunnable,
12
+ createTitleRunnable,
13
+ } from '@/utils/title';
14
+ import { GraphEvents, Callback, TitleMethod } from '@/common';
15
+ import { MultiAgentGraph } from '@/graphs/MultiAgentGraph';
17
16
  import { createTokenCounter } from '@/utils/tokens';
18
17
  import { StandardGraph } from '@/graphs/Graph';
19
18
  import { HandlerRegistry } from '@/events';
20
19
  import { isOpenAILike } from '@/utils/llm';
21
20
 
22
- export class Run<T extends t.BaseGraphState> {
23
- graphRunnable?: t.CompiledWorkflow<T, Partial<T>, string>;
24
- // private collab!: CollabGraph;
25
- // private taskManager!: TaskManager;
26
- private handlerRegistry: HandlerRegistry;
21
+ export const defaultOmitOptions = new Set([
22
+ 'stream',
23
+ 'thinking',
24
+ 'streaming',
25
+ 'maxTokens',
26
+ 'clientOptions',
27
+ 'thinkingConfig',
28
+ 'thinkingBudget',
29
+ 'includeThoughts',
30
+ 'maxOutputTokens',
31
+ 'additionalModelRequestFields',
32
+ ]);
33
+
34
+ export class Run<_T extends t.BaseGraphState> {
27
35
  id: string;
28
- Graph: StandardGraph | undefined;
29
- provider: Providers | undefined;
36
+ private tokenCounter?: t.TokenCounter;
37
+ private handlerRegistry?: HandlerRegistry;
38
+ private indexTokenCountMap?: Record<string, number>;
39
+ graphRunnable?: t.CompiledStateWorkflow;
40
+ Graph: StandardGraph | MultiAgentGraph | undefined;
30
41
  returnContent: boolean = false;
31
42
 
32
43
  private constructor(config: Partial<t.RunConfig>) {
@@ -36,6 +47,8 @@ export class Run<T extends t.BaseGraphState> {
36
47
  }
37
48
 
38
49
  this.id = runId;
50
+ this.tokenCounter = config.tokenCounter;
51
+ this.indexTokenCountMap = config.indexTokenCountMap;
39
52
 
40
53
  const handlerRegistry = new HandlerRegistry();
41
54
 
@@ -53,12 +66,18 @@ export class Run<T extends t.BaseGraphState> {
53
66
  throw new Error('Graph config not provided');
54
67
  }
55
68
 
56
- if (config.graphConfig.type === 'standard' || !config.graphConfig.type) {
57
- this.provider = config.graphConfig.llmConfig.provider;
58
- this.graphRunnable = this.createStandardGraph(
59
- config.graphConfig
60
- ) as unknown as t.CompiledWorkflow<T, Partial<T>, string>;
69
+ /** Handle different graph types */
70
+ if (config.graphConfig.type === 'multi-agent') {
71
+ this.graphRunnable = this.createMultiAgentGraph(config.graphConfig);
72
+ if (this.Graph) {
73
+ this.Graph.handlerRegistry = handlerRegistry;
74
+ }
75
+ } else {
76
+ /** Default to legacy graph for 'standard' or undefined type */
77
+ this.graphRunnable = this.createLegacyGraph(config.graphConfig);
61
78
  if (this.Graph) {
79
+ this.Graph.compileOptions =
80
+ config.graphConfig.compileOptions ?? this.Graph.compileOptions;
62
81
  this.Graph.handlerRegistry = handlerRegistry;
63
82
  }
64
83
  }
@@ -66,26 +85,81 @@ export class Run<T extends t.BaseGraphState> {
66
85
  this.returnContent = config.returnContent ?? false;
67
86
  }
68
87
 
69
- private createStandardGraph(
70
- config: t.StandardGraphConfig
71
- ): t.CompiledWorkflow<t.IState, Partial<t.IState>, string> {
72
- const { llmConfig, tools = [], ...graphInput } = config;
73
- const { provider, ...clientOptions } = llmConfig;
88
+ private createLegacyGraph(
89
+ config: t.LegacyGraphConfig | t.StandardGraphConfig
90
+ ): t.CompiledStateWorkflow {
91
+ let agentConfig: t.AgentInputs;
92
+ let signal: AbortSignal | undefined;
93
+
94
+ /** Check if this is a multi-agent style config (has agents array) */
95
+ if ('agents' in config && Array.isArray(config.agents)) {
96
+ if (config.agents.length === 0) {
97
+ throw new Error('At least one agent must be provided');
98
+ }
99
+ agentConfig = config.agents[0];
100
+ signal = config.signal;
101
+ } else {
102
+ /** Legacy path: build agent config from llmConfig */
103
+ const {
104
+ type: _type,
105
+ llmConfig,
106
+ signal: legacySignal,
107
+ tools = [],
108
+ ...agentInputs
109
+ } = config as t.LegacyGraphConfig;
110
+ const { provider, ...clientOptions } = llmConfig;
111
+
112
+ agentConfig = {
113
+ ...agentInputs,
114
+ tools,
115
+ provider,
116
+ clientOptions,
117
+ agentId: 'default',
118
+ };
119
+ signal = legacySignal;
120
+ }
74
121
 
75
122
  const standardGraph = new StandardGraph({
76
- tools,
77
- provider,
78
- clientOptions,
79
- ...graphInput,
123
+ signal,
80
124
  runId: this.id,
125
+ agents: [agentConfig],
126
+ tokenCounter: this.tokenCounter,
127
+ indexTokenCountMap: this.indexTokenCountMap,
81
128
  });
129
+ /** Propagate compile options from graph config */
130
+ standardGraph.compileOptions = config.compileOptions;
82
131
  this.Graph = standardGraph;
83
132
  return standardGraph.createWorkflow();
84
133
  }
85
134
 
135
+ private createMultiAgentGraph(
136
+ config: t.MultiAgentGraphConfig
137
+ ): t.CompiledStateWorkflow {
138
+ const { agents, edges, compileOptions } = config;
139
+
140
+ const multiAgentGraph = new MultiAgentGraph({
141
+ runId: this.id,
142
+ agents,
143
+ edges,
144
+ tokenCounter: this.tokenCounter,
145
+ indexTokenCountMap: this.indexTokenCountMap,
146
+ });
147
+
148
+ if (compileOptions != null) {
149
+ multiAgentGraph.compileOptions = compileOptions;
150
+ }
151
+
152
+ this.Graph = multiAgentGraph;
153
+ return multiAgentGraph.createWorkflow();
154
+ }
155
+
86
156
  static async create<T extends t.BaseGraphState>(
87
157
  config: t.RunConfig
88
158
  ): Promise<Run<T>> {
159
+ /** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not */
160
+ if (config.indexTokenCountMap && !config.tokenCounter) {
161
+ config.tokenCounter = await createTokenCounter();
162
+ }
89
163
  return new Run<T>(config);
90
164
  }
91
165
 
@@ -98,12 +172,49 @@ export class Run<T extends t.BaseGraphState> {
98
172
  return this.Graph.getRunMessages();
99
173
  }
100
174
 
175
+ /**
176
+ * Creates a custom event callback handler that intercepts custom events
177
+ * and processes them through our handler registry instead of EventStreamCallbackHandler
178
+ */
179
+ private createCustomEventCallback() {
180
+ return async (
181
+ eventName: string,
182
+ data: unknown,
183
+ runId: string,
184
+ tags?: string[],
185
+ metadata?: Record<string, unknown>
186
+ ): Promise<void> => {
187
+ if (
188
+ (data as t.StreamEventData)['emitted'] === true &&
189
+ eventName === GraphEvents.CHAT_MODEL_STREAM
190
+ ) {
191
+ return;
192
+ }
193
+ const handler = this.handlerRegistry?.getHandler(eventName);
194
+ if (handler && this.Graph) {
195
+ await handler.handle(
196
+ eventName,
197
+ data as
198
+ | t.StreamEventData
199
+ | t.ModelEndData
200
+ | t.RunStep
201
+ | t.RunStepDeltaEvent
202
+ | t.MessageDeltaEvent
203
+ | t.ReasoningDeltaEvent
204
+ | { result: t.ToolEndEvent },
205
+ metadata,
206
+ this.Graph
207
+ );
208
+ }
209
+ };
210
+ }
211
+
101
212
  async processStream(
102
213
  inputs: t.IState,
103
214
  config: Partial<RunnableConfig> & { version: 'v1' | 'v2'; run_id?: string },
104
215
  streamOptions?: t.EventStreamOptions
105
216
  ): Promise<MessageContentComplex[] | undefined> {
106
- if (!this.graphRunnable) {
217
+ if (this.graphRunnable == null) {
107
218
  throw new Error(
108
219
  'Run not initialized. Make sure to use Run.create() to instantiate the Run.'
109
220
  );
@@ -115,88 +226,45 @@ export class Run<T extends t.BaseGraphState> {
115
226
  }
116
227
 
117
228
  this.Graph.resetValues(streamOptions?.keepContent);
118
- const provider = this.Graph.provider;
119
- const hasTools = this.Graph.tools ? this.Graph.tools.length > 0 : false;
120
- if (streamOptions?.callbacks) {
121
- /* TODO: conflicts with callback manager */
122
- const callbacks = (config.callbacks as t.ProvidedCallbacks) ?? [];
123
- config.callbacks = callbacks.concat(
124
- this.getCallbacks(streamOptions.callbacks)
125
- );
126
- }
229
+
230
+ /** Custom event callback to intercept and handle custom events */
231
+ const customEventCallback = this.createCustomEventCallback();
232
+
233
+ const baseCallbacks = (config.callbacks as t.ProvidedCallbacks) ?? [];
234
+ const streamCallbacks = streamOptions?.callbacks
235
+ ? this.getCallbacks(streamOptions.callbacks)
236
+ : [];
237
+
238
+ config.callbacks = baseCallbacks.concat(streamCallbacks).concat({
239
+ [Callback.CUSTOM_EVENT]: customEventCallback,
240
+ });
127
241
 
128
242
  if (!this.id) {
129
243
  throw new Error('Run ID not provided');
130
244
  }
131
245
 
132
- const tokenCounter =
133
- streamOptions?.tokenCounter ??
134
- (streamOptions?.indexTokenCountMap
135
- ? await createTokenCounter()
136
- : undefined);
137
- const toolTokens = tokenCounter
138
- ? (this.Graph.tools?.reduce((acc, tool) => {
139
- if (!(tool as Partial<t.GenericTool>).schema) {
140
- return acc;
141
- }
142
-
143
- const jsonSchema = zodToJsonSchema(
144
- (tool.schema as t.ZodObjectAny).describe(tool.description ?? ''),
145
- tool.name
146
- );
147
- return (
148
- acc + tokenCounter(new SystemMessage(JSON.stringify(jsonSchema)))
149
- );
150
- }, 0) ?? 0)
151
- : 0;
152
- let instructionTokens = toolTokens;
153
- if (this.Graph.systemMessage && tokenCounter) {
154
- instructionTokens += tokenCounter(this.Graph.systemMessage);
155
- }
156
- const tokenMap = streamOptions?.indexTokenCountMap ?? {};
157
- if (this.Graph.systemMessage && instructionTokens > 0) {
158
- this.Graph.indexTokenCountMap = shiftIndexTokenCountMap(
159
- tokenMap,
160
- instructionTokens
161
- );
162
- } else if (instructionTokens > 0) {
163
- tokenMap[0] = tokenMap[0] + instructionTokens;
164
- this.Graph.indexTokenCountMap = tokenMap;
165
- } else {
166
- this.Graph.indexTokenCountMap = tokenMap;
167
- }
168
-
169
- this.Graph.maxContextTokens = streamOptions?.maxContextTokens;
170
- this.Graph.tokenCounter = tokenCounter;
171
-
172
246
  config.run_id = this.id;
173
247
  config.configurable = Object.assign(config.configurable ?? {}, {
174
248
  run_id: this.id,
175
- provider: this.provider,
176
249
  });
177
250
 
178
- const stream = this.graphRunnable.streamEvents(inputs, config);
251
+ const stream = this.graphRunnable.streamEvents(inputs, config, {
252
+ raiseError: true,
253
+ });
179
254
 
180
255
  for await (const event of stream) {
181
- const { data, name, metadata, ...info } = event;
256
+ const { data, metadata, ...info } = event;
182
257
 
183
- let eventName: t.EventName = info.event;
184
- if (
185
- hasTools &&
186
- manualToolStreamProviders.has(provider) &&
187
- eventName === GraphEvents.CHAT_MODEL_STREAM
188
- ) {
189
- /* Skipping CHAT_MODEL_STREAM event due to double-call edge case */
190
- continue;
191
- }
258
+ const eventName: t.EventName = info.event;
192
259
 
193
- if (eventName && eventName === GraphEvents.ON_CUSTOM_EVENT) {
194
- eventName = name;
260
+ /** Skip custom events as they're handled by our callback */
261
+ if (eventName === GraphEvents.ON_CUSTOM_EVENT) {
262
+ continue;
195
263
  }
196
264
 
197
- const handler = this.handlerRegistry.getHandler(eventName);
265
+ const handler = this.handlerRegistry?.getHandler(eventName);
198
266
  if (handler) {
199
- handler.handle(eventName, data, metadata, this.Graph);
267
+ await handler.handle(eventName, data, metadata, this.Graph);
200
268
  }
201
269
  }
202
270
 
@@ -205,19 +273,19 @@ export class Run<T extends t.BaseGraphState> {
205
273
  }
206
274
  }
207
275
 
208
- private createSystemCallback<K extends keyof ClientCallbacks>(
209
- clientCallbacks: ClientCallbacks,
276
+ private createSystemCallback<K extends keyof t.ClientCallbacks>(
277
+ clientCallbacks: t.ClientCallbacks,
210
278
  key: K
211
- ): SystemCallbacks[K] {
279
+ ): t.SystemCallbacks[K] {
212
280
  return ((...args: unknown[]) => {
213
281
  const clientCallback = clientCallbacks[key];
214
282
  if (clientCallback && this.Graph) {
215
283
  (clientCallback as (...args: unknown[]) => void)(this.Graph, ...args);
216
284
  }
217
- }) as SystemCallbacks[K];
285
+ }) as t.SystemCallbacks[K];
218
286
  }
219
287
 
220
- getCallbacks(clientCallbacks: ClientCallbacks): SystemCallbacks {
288
+ getCallbacks(clientCallbacks: t.ClientCallbacks): t.SystemCallbacks {
221
289
  return {
222
290
  [Callback.TOOL_ERROR]: this.createSystemCallback(
223
291
  clientCallbacks,
@@ -235,15 +303,18 @@ export class Run<T extends t.BaseGraphState> {
235
303
  }
236
304
 
237
305
  async generateTitle({
306
+ provider,
238
307
  inputText,
239
308
  contentParts,
240
309
  titlePrompt,
241
310
  clientOptions,
242
311
  chainOptions,
243
312
  skipLanguage,
244
- }: t.RunTitleOptions): Promise<{ language: string; title: string }> {
313
+ titleMethod = TitleMethod.COMPLETION,
314
+ titlePromptTemplate,
315
+ }: t.RunTitleOptions): Promise<{ language?: string; title?: string }> {
245
316
  const convoTemplate = PromptTemplate.fromTemplate(
246
- 'User: {input}\nAI: {output}'
317
+ titlePromptTemplate ?? 'User: {input}\nAI: {output}'
247
318
  );
248
319
  const response = contentParts
249
320
  .map((part) => {
@@ -255,22 +326,14 @@ export class Run<T extends t.BaseGraphState> {
255
326
  await convoTemplate.invoke({ input: inputText, output: response })
256
327
  ).value;
257
328
  const model = this.Graph?.getNewModel({
329
+ provider,
258
330
  clientOptions,
259
- omitOriginalOptions: new Set([
260
- 'clientOptions',
261
- 'streaming',
262
- 'stream',
263
- 'thinking',
264
- 'maxTokens',
265
- 'maxOutputTokens',
266
- 'additionalModelRequestFields',
267
- ]),
268
331
  });
269
332
  if (!model) {
270
333
  return { language: '', title: '' };
271
334
  }
272
335
  if (
273
- isOpenAILike(this.provider) &&
336
+ isOpenAILike(provider) &&
274
337
  (model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)
275
338
  ) {
276
339
  model.temperature = (clientOptions as t.OpenAIClientOptions | undefined)
@@ -286,10 +349,27 @@ export class Run<T extends t.BaseGraphState> {
286
349
  model.n = (clientOptions as t.OpenAIClientOptions | undefined)
287
350
  ?.n as number;
288
351
  }
289
- const chain = await createTitleRunnable(model, titlePrompt);
290
- return (await chain.invoke(
291
- { convo, inputText, skipLanguage },
292
- chainOptions
293
- )) as { language: string; title: string };
352
+ const chain =
353
+ titleMethod === TitleMethod.COMPLETION
354
+ ? await createCompletionTitleRunnable(model, titlePrompt)
355
+ : await createTitleRunnable(model, titlePrompt);
356
+ const invokeConfig = Object.assign({}, chainOptions, {
357
+ run_id: this.id,
358
+ runId: this.id,
359
+ });
360
+ try {
361
+ return await chain.invoke(
362
+ { convo, inputText, skipLanguage },
363
+ invokeConfig
364
+ );
365
+ } catch (_e) {
366
+ // Fallback: strip callbacks to avoid EventStream tracer errors in certain environments
367
+ const { callbacks: _cb, ...rest } = invokeConfig;
368
+ const safeConfig = Object.assign({}, rest, { callbacks: [] });
369
+ return await chain.invoke(
370
+ { convo, inputText, skipLanguage },
371
+ safeConfig as Partial<RunnableConfig>
372
+ );
373
+ }
294
374
  }
295
375
  }
@@ -0,0 +1,158 @@
1
+ /* eslint-disable no-console */
2
+ // src/scripts/cli.ts
3
+ import { config } from 'dotenv';
4
+ config();
5
+ import { HumanMessage, BaseMessage } from '@langchain/core/messages';
6
+ import type * as t from '@/types';
7
+ import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
8
+ import { ToolEndHandler, ModelEndHandler } from '@/events';
9
+
10
+ import { getArgs } from '@/scripts/args';
11
+ import { Run } from '@/run';
12
+ import { GraphEvents, Callback, Providers } from '@/common';
13
+ import { getLLMConfig } from '@/utils/llmConfig';
14
+
15
+ const conversationHistory: BaseMessage[] = [];
16
+ let _contentParts: (t.MessageContentComplex | undefined)[] = [];
17
+ async function testStandardStreaming(): Promise<void> {
18
+ const { userName, location, currentDate } = await getArgs();
19
+ const { contentParts, aggregateContent } = createContentAggregator();
20
+ _contentParts = contentParts;
21
+ const customHandlers = {
22
+ [GraphEvents.TOOL_END]: new ToolEndHandler(),
23
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
24
+ [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
25
+ [GraphEvents.ON_RUN_STEP_COMPLETED]: {
26
+ handle: (
27
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
28
+ data: t.StreamEventData
29
+ ): void => {
30
+ console.log('====== ON_RUN_STEP_COMPLETED ======');
31
+ // console.dir(data, { depth: null });
32
+ aggregateContent({
33
+ event,
34
+ data: data as unknown as { result: t.ToolEndEvent },
35
+ });
36
+ },
37
+ },
38
+ [GraphEvents.ON_RUN_STEP]: {
39
+ handle: (
40
+ event: GraphEvents.ON_RUN_STEP,
41
+ data: t.StreamEventData
42
+ ): void => {
43
+ console.log('====== ON_RUN_STEP ======');
44
+ console.dir(data, { depth: null });
45
+ aggregateContent({ event, data: data as t.RunStep });
46
+ },
47
+ },
48
+ [GraphEvents.ON_RUN_STEP_DELTA]: {
49
+ handle: (
50
+ event: GraphEvents.ON_RUN_STEP_DELTA,
51
+ data: t.StreamEventData
52
+ ): void => {
53
+ console.log('====== ON_RUN_STEP_DELTA ======');
54
+ console.dir(data, { depth: null });
55
+ aggregateContent({ event, data: data as t.RunStepDeltaEvent });
56
+ },
57
+ },
58
+ [GraphEvents.ON_MESSAGE_DELTA]: {
59
+ handle: (
60
+ event: GraphEvents.ON_MESSAGE_DELTA,
61
+ data: t.StreamEventData
62
+ ): void => {
63
+ console.log('====== ON_MESSAGE_DELTA ======');
64
+ console.dir(data, { depth: null });
65
+ aggregateContent({ event, data: data as t.MessageDeltaEvent });
66
+ },
67
+ },
68
+ [GraphEvents.TOOL_START]: {
69
+ handle: (
70
+ _event: string,
71
+ data: t.StreamEventData,
72
+ metadata?: Record<string, unknown>
73
+ ): void => {
74
+ console.log('====== TOOL_START ======');
75
+ // console.dir(data, { depth: null });
76
+ },
77
+ },
78
+ };
79
+
80
+ const llmConfig = getLLMConfig(
81
+ Providers.ANTHROPIC
82
+ ) as t.AnthropicClientOptions & t.SharedLLMConfig;
83
+ llmConfig.model = 'claude-3-5-sonnet-latest';
84
+
85
+ const run = await Run.create<t.IState>({
86
+ runId: 'test-run-id',
87
+ graphConfig: {
88
+ type: 'standard',
89
+ llmConfig,
90
+ tools: [
91
+ {
92
+ type: 'web_search_20250305',
93
+ name: 'web_search',
94
+ max_uses: 5,
95
+ },
96
+ ],
97
+ instructions: 'You are a friendly AI assistant.',
98
+ // additional_instructions: `Always address the user by their name. The user's name is ${userName} and they are located in ${location}.`,
99
+ },
100
+ returnContent: true,
101
+ customHandlers,
102
+ });
103
+
104
+ const config = {
105
+ configurable: {
106
+ provider: Providers.ANTHROPIC,
107
+ thread_id: 'conversation-num-1',
108
+ },
109
+ streamMode: 'values',
110
+ version: 'v2' as const,
111
+ };
112
+
113
+ console.log('Test 1: Search query (search tool test)');
114
+
115
+ // const userMessage = `
116
+ // Make a search for the weather in ${location} today, which is ${currentDate}.
117
+ // Before making the search, please let me know what you're about to do, then immediately start searching without hesitation.
118
+ // Make sure to always refer to me by name, which is ${userName}.
119
+ // After giving me a thorough summary, tell me a joke about the weather forecast we went over.
120
+ // `;
121
+ // const userMessage = 'Are massage guns good?';
122
+ // const userMessage = 'What is functional programming?';
123
+ const userMessage = "Get me today's trending news.";
124
+ // const userMessage = "search recent italy earthquake volcano activity";
125
+ // const userMessage =
126
+ // "use 'Trump' as the exact search query and tell me what you find.";
127
+
128
+ conversationHistory.push(new HumanMessage(userMessage));
129
+
130
+ const inputs = {
131
+ messages: conversationHistory,
132
+ };
133
+ const finalContentParts = await run.processStream(inputs, config);
134
+ const finalMessages = run.getRunMessages();
135
+ if (finalMessages) {
136
+ conversationHistory.push(...finalMessages);
137
+ console.dir(conversationHistory, { depth: null });
138
+ }
139
+ // console.dir(finalContentParts, { depth: null });
140
+ console.log('\n\n====================\n\n');
141
+ // console.dir(contentParts, { depth: null });
142
+ }
143
+
144
+ process.on('unhandledRejection', (reason, promise) => {
145
+ console.error('Unhandled Rejection at:', promise, 'reason:', reason);
146
+ console.log('Content Parts:');
147
+ console.dir(_contentParts, { depth: null });
148
+ process.exit(1);
149
+ });
150
+
151
+ testStandardStreaming().catch((err) => {
152
+ console.error(err);
153
+ console.log('Conversation history:');
154
+ console.dir(conversationHistory, { depth: null });
155
+ console.log('Content Parts:');
156
+ console.dir(_contentParts, { depth: null });
157
+ process.exit(1);
158
+ });
@@ -4,41 +4,45 @@ import { hideBin } from 'yargs/helpers';
4
4
  import { llmConfigs } from '@/utils/llmConfig';
5
5
  import { Providers } from '@/common';
6
6
 
7
- export async function getArgs(): Promise<{ userName: string; location: string; provider: string; currentDate: string; }> {
7
+ export async function getArgs(): Promise<{
8
+ userName: string;
9
+ location: string;
10
+ provider: Providers;
11
+ currentDate: string;
12
+ }> {
8
13
  const argv = yargs(hideBin(process.argv))
9
14
  .option('name', {
10
15
  alias: 'n',
11
16
  type: 'string',
12
17
  description: 'User name',
13
- default: 'Jo'
18
+ default: 'Jo',
14
19
  })
15
20
  .option('location', {
16
21
  alias: 'l',
17
22
  type: 'string',
18
23
  description: 'User location',
19
- default: 'New York'
24
+ default: 'New York',
20
25
  })
21
26
  .option('provider', {
22
27
  alias: 'p',
23
28
  type: 'string',
24
29
  description: 'LLM provider',
25
30
  choices: Object.keys(llmConfigs),
26
- default: Providers.OPENAI
31
+ default: Providers.OPENAI,
27
32
  })
28
33
  .help()
29
- .alias('help', 'h')
30
- .argv;
34
+ .alias('help', 'h').argv;
31
35
 
32
36
  const args = await argv;
33
37
  const userName = args.name as string;
34
38
  const location = args.location as string;
35
- const provider = args.provider as string;
39
+ const provider = args.provider as Providers;
36
40
  const currentDate = new Date().toLocaleString();
37
41
 
38
42
  return {
39
43
  userName,
40
44
  location,
41
45
  provider,
42
- currentDate
46
+ currentDate,
43
47
  };
44
48
  }