@librechat/agents 2.4.322 → 3.0.0-rc1

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 (258) 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 +322 -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 +320 -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-test.d.ts +1 -0
  167. package/dist/types/stream.d.ts +10 -3
  168. package/dist/types/tools/CodeExecutor.d.ts +2 -2
  169. package/dist/types/tools/ToolNode.d.ts +1 -1
  170. package/dist/types/tools/handlers.d.ts +17 -4
  171. package/dist/types/tools/search/anthropic.d.ts +16 -0
  172. package/dist/types/tools/search/firecrawl.d.ts +15 -0
  173. package/dist/types/tools/search/rerankers.d.ts +0 -1
  174. package/dist/types/tools/search/types.d.ts +30 -9
  175. package/dist/types/types/graph.d.ts +95 -15
  176. package/dist/types/types/llm.d.ts +24 -10
  177. package/dist/types/types/run.d.ts +46 -8
  178. package/dist/types/types/stream.d.ts +16 -2
  179. package/dist/types/types/tools.d.ts +1 -1
  180. package/dist/types/utils/events.d.ts +6 -0
  181. package/dist/types/utils/title.d.ts +2 -1
  182. package/dist/types/utils/tokens.d.ts +24 -0
  183. package/package.json +33 -17
  184. package/src/agents/AgentContext.ts +315 -0
  185. package/src/common/enum.ts +14 -5
  186. package/src/events.ts +24 -13
  187. package/src/graphs/Graph.ts +495 -312
  188. package/src/graphs/MultiAgentGraph.ts +381 -0
  189. package/src/graphs/index.ts +2 -1
  190. package/src/llm/anthropic/Jacob_Lee_Resume_2023.pdf +0 -0
  191. package/src/llm/anthropic/index.ts +78 -13
  192. package/src/llm/anthropic/llm.spec.ts +491 -115
  193. package/src/llm/anthropic/types.ts +39 -3
  194. package/src/llm/anthropic/utils/message_inputs.ts +67 -11
  195. package/src/llm/anthropic/utils/message_outputs.ts +21 -2
  196. package/src/llm/anthropic/utils/output_parsers.ts +25 -6
  197. package/src/llm/anthropic/utils/tools.ts +29 -0
  198. package/src/llm/google/index.ts +218 -0
  199. package/src/llm/google/types.ts +43 -0
  200. package/src/llm/google/utils/common.ts +646 -0
  201. package/src/llm/google/utils/tools.ts +160 -0
  202. package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -0
  203. package/src/llm/ollama/index.ts +89 -0
  204. package/src/llm/ollama/utils.ts +193 -0
  205. package/src/llm/openai/index.ts +600 -14
  206. package/src/llm/openai/types.ts +24 -0
  207. package/src/llm/openai/utils/index.ts +912 -0
  208. package/src/llm/openai/utils/isReasoningModel.test.ts +90 -0
  209. package/src/llm/providers.ts +10 -9
  210. package/src/llm/text.ts +26 -7
  211. package/src/llm/vertexai/index.ts +360 -0
  212. package/src/messages/reducer.ts +80 -0
  213. package/src/run.ts +181 -112
  214. package/src/scripts/ant_web_search.ts +158 -0
  215. package/src/scripts/args.ts +12 -8
  216. package/src/scripts/cli4.ts +29 -21
  217. package/src/scripts/cli5.ts +29 -21
  218. package/src/scripts/code_exec.ts +54 -23
  219. package/src/scripts/code_exec_files.ts +48 -17
  220. package/src/scripts/code_exec_simple.ts +46 -27
  221. package/src/scripts/handoff-test.ts +135 -0
  222. package/src/scripts/image.ts +52 -20
  223. package/src/scripts/multi-agent-conditional.ts +220 -0
  224. package/src/scripts/multi-agent-example-output.md +110 -0
  225. package/src/scripts/multi-agent-parallel.ts +337 -0
  226. package/src/scripts/multi-agent-sequence.ts +212 -0
  227. package/src/scripts/multi-agent-test.ts +186 -0
  228. package/src/scripts/search.ts +1 -9
  229. package/src/scripts/simple.ts +25 -10
  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 +139 -60
  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 +272 -103
  251. package/src/types/llm.ts +25 -12
  252. package/src/types/run.ts +51 -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
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,70 @@ 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;
88
+ private createLegacyGraph(
89
+ config: t.LegacyGraphConfig
90
+ ): t.CompiledStateWorkflow {
91
+ const {
92
+ type: _type,
93
+ llmConfig,
94
+ signal,
95
+ tools = [],
96
+ ...agentInputs
97
+ } = config;
73
98
  const { provider, ...clientOptions } = llmConfig;
74
99
 
75
- const standardGraph = new StandardGraph({
100
+ /** TEMP: Create agent configuration for the single agent */
101
+ const agentConfig: t.AgentInputs = {
102
+ ...agentInputs,
76
103
  tools,
77
104
  provider,
78
105
  clientOptions,
79
- ...graphInput,
106
+ agentId: 'default',
107
+ };
108
+
109
+ const standardGraph = new StandardGraph({
110
+ signal,
80
111
  runId: this.id,
112
+ agents: [agentConfig],
113
+ tokenCounter: this.tokenCounter,
114
+ indexTokenCountMap: this.indexTokenCountMap,
81
115
  });
116
+ // propagate compile options from graph config
117
+ standardGraph.compileOptions = (
118
+ config as t.LegacyGraphConfig
119
+ ).compileOptions;
82
120
  this.Graph = standardGraph;
83
121
  return standardGraph.createWorkflow();
84
122
  }
85
123
 
124
+ private createMultiAgentGraph(
125
+ config: t.MultiAgentGraphConfig
126
+ ): t.CompiledStateWorkflow {
127
+ const { agents, edges, compileOptions } = config;
128
+
129
+ const multiAgentGraph = new MultiAgentGraph({
130
+ runId: this.id,
131
+ agents,
132
+ edges,
133
+ tokenCounter: this.tokenCounter,
134
+ indexTokenCountMap: this.indexTokenCountMap,
135
+ });
136
+
137
+ if (compileOptions != null) {
138
+ multiAgentGraph.compileOptions = compileOptions;
139
+ }
140
+
141
+ this.Graph = multiAgentGraph;
142
+ return multiAgentGraph.createWorkflow();
143
+ }
144
+
86
145
  static async create<T extends t.BaseGraphState>(
87
146
  config: t.RunConfig
88
147
  ): Promise<Run<T>> {
148
+ // Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not
149
+ if (config.indexTokenCountMap && !config.tokenCounter) {
150
+ config.tokenCounter = await createTokenCounter();
151
+ }
89
152
  return new Run<T>(config);
90
153
  }
91
154
 
@@ -98,12 +161,49 @@ export class Run<T extends t.BaseGraphState> {
98
161
  return this.Graph.getRunMessages();
99
162
  }
100
163
 
164
+ /**
165
+ * Creates a custom event callback handler that intercepts custom events
166
+ * and processes them through our handler registry instead of EventStreamCallbackHandler
167
+ */
168
+ private createCustomEventCallback() {
169
+ return async (
170
+ eventName: string,
171
+ data: unknown,
172
+ runId: string,
173
+ tags?: string[],
174
+ metadata?: Record<string, unknown>
175
+ ): Promise<void> => {
176
+ if (
177
+ (data as t.StreamEventData)['emitted'] === true &&
178
+ eventName === GraphEvents.CHAT_MODEL_STREAM
179
+ ) {
180
+ return;
181
+ }
182
+ const handler = this.handlerRegistry.getHandler(eventName);
183
+ if (handler && this.Graph) {
184
+ await handler.handle(
185
+ eventName,
186
+ data as
187
+ | t.StreamEventData
188
+ | t.ModelEndData
189
+ | t.RunStep
190
+ | t.RunStepDeltaEvent
191
+ | t.MessageDeltaEvent
192
+ | t.ReasoningDeltaEvent
193
+ | { result: t.ToolEndEvent },
194
+ metadata,
195
+ this.Graph
196
+ );
197
+ }
198
+ };
199
+ }
200
+
101
201
  async processStream(
102
202
  inputs: t.IState,
103
203
  config: Partial<RunnableConfig> & { version: 'v1' | 'v2'; run_id?: string },
104
204
  streamOptions?: t.EventStreamOptions
105
205
  ): Promise<MessageContentComplex[] | undefined> {
106
- if (!this.graphRunnable) {
206
+ if (this.graphRunnable == null) {
107
207
  throw new Error(
108
208
  'Run not initialized. Make sure to use Run.create() to instantiate the Run.'
109
209
  );
@@ -115,88 +215,45 @@ export class Run<T extends t.BaseGraphState> {
115
215
  }
116
216
 
117
217
  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
- }
218
+
219
+ /** Custom event callback to intercept and handle custom events */
220
+ const customEventCallback = this.createCustomEventCallback();
221
+
222
+ const baseCallbacks = (config.callbacks as t.ProvidedCallbacks) ?? [];
223
+ const streamCallbacks = streamOptions?.callbacks
224
+ ? this.getCallbacks(streamOptions.callbacks)
225
+ : [];
226
+
227
+ config.callbacks = baseCallbacks.concat(streamCallbacks).concat({
228
+ [Callback.CUSTOM_EVENT]: customEventCallback,
229
+ });
127
230
 
128
231
  if (!this.id) {
129
232
  throw new Error('Run ID not provided');
130
233
  }
131
234
 
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
235
  config.run_id = this.id;
173
236
  config.configurable = Object.assign(config.configurable ?? {}, {
174
237
  run_id: this.id,
175
- provider: this.provider,
176
238
  });
177
239
 
178
- const stream = this.graphRunnable.streamEvents(inputs, config);
240
+ const stream = this.graphRunnable.streamEvents(inputs, config, {
241
+ raiseError: true,
242
+ });
179
243
 
180
244
  for await (const event of stream) {
181
- const { data, name, metadata, ...info } = event;
245
+ const { data, metadata, ...info } = event;
182
246
 
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
- }
247
+ const eventName: t.EventName = info.event;
192
248
 
193
- if (eventName && eventName === GraphEvents.ON_CUSTOM_EVENT) {
194
- eventName = name;
249
+ /** Skip custom events as they're handled by our callback */
250
+ if (eventName === GraphEvents.ON_CUSTOM_EVENT) {
251
+ continue;
195
252
  }
196
253
 
197
254
  const handler = this.handlerRegistry.getHandler(eventName);
198
255
  if (handler) {
199
- handler.handle(eventName, data, metadata, this.Graph);
256
+ await handler.handle(eventName, data, metadata, this.Graph);
200
257
  }
201
258
  }
202
259
 
@@ -205,19 +262,19 @@ export class Run<T extends t.BaseGraphState> {
205
262
  }
206
263
  }
207
264
 
208
- private createSystemCallback<K extends keyof ClientCallbacks>(
209
- clientCallbacks: ClientCallbacks,
265
+ private createSystemCallback<K extends keyof t.ClientCallbacks>(
266
+ clientCallbacks: t.ClientCallbacks,
210
267
  key: K
211
- ): SystemCallbacks[K] {
268
+ ): t.SystemCallbacks[K] {
212
269
  return ((...args: unknown[]) => {
213
270
  const clientCallback = clientCallbacks[key];
214
271
  if (clientCallback && this.Graph) {
215
272
  (clientCallback as (...args: unknown[]) => void)(this.Graph, ...args);
216
273
  }
217
- }) as SystemCallbacks[K];
274
+ }) as t.SystemCallbacks[K];
218
275
  }
219
276
 
220
- getCallbacks(clientCallbacks: ClientCallbacks): SystemCallbacks {
277
+ getCallbacks(clientCallbacks: t.ClientCallbacks): t.SystemCallbacks {
221
278
  return {
222
279
  [Callback.TOOL_ERROR]: this.createSystemCallback(
223
280
  clientCallbacks,
@@ -235,15 +292,18 @@ export class Run<T extends t.BaseGraphState> {
235
292
  }
236
293
 
237
294
  async generateTitle({
295
+ provider,
238
296
  inputText,
239
297
  contentParts,
240
298
  titlePrompt,
241
299
  clientOptions,
242
300
  chainOptions,
243
301
  skipLanguage,
244
- }: t.RunTitleOptions): Promise<{ language: string; title: string }> {
302
+ titleMethod = TitleMethod.COMPLETION,
303
+ titlePromptTemplate,
304
+ }: t.RunTitleOptions): Promise<{ language?: string; title?: string }> {
245
305
  const convoTemplate = PromptTemplate.fromTemplate(
246
- 'User: {input}\nAI: {output}'
306
+ titlePromptTemplate ?? 'User: {input}\nAI: {output}'
247
307
  );
248
308
  const response = contentParts
249
309
  .map((part) => {
@@ -255,22 +315,14 @@ export class Run<T extends t.BaseGraphState> {
255
315
  await convoTemplate.invoke({ input: inputText, output: response })
256
316
  ).value;
257
317
  const model = this.Graph?.getNewModel({
318
+ provider,
258
319
  clientOptions,
259
- omitOriginalOptions: new Set([
260
- 'clientOptions',
261
- 'streaming',
262
- 'stream',
263
- 'thinking',
264
- 'maxTokens',
265
- 'maxOutputTokens',
266
- 'additionalModelRequestFields',
267
- ]),
268
320
  });
269
321
  if (!model) {
270
322
  return { language: '', title: '' };
271
323
  }
272
324
  if (
273
- isOpenAILike(this.provider) &&
325
+ isOpenAILike(provider) &&
274
326
  (model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)
275
327
  ) {
276
328
  model.temperature = (clientOptions as t.OpenAIClientOptions | undefined)
@@ -286,10 +338,27 @@ export class Run<T extends t.BaseGraphState> {
286
338
  model.n = (clientOptions as t.OpenAIClientOptions | undefined)
287
339
  ?.n as number;
288
340
  }
289
- const chain = await createTitleRunnable(model, titlePrompt);
290
- return (await chain.invoke(
291
- { convo, inputText, skipLanguage },
292
- chainOptions
293
- )) as { language: string; title: string };
341
+ const chain =
342
+ titleMethod === TitleMethod.COMPLETION
343
+ ? await createCompletionTitleRunnable(model, titlePrompt)
344
+ : await createTitleRunnable(model, titlePrompt);
345
+ const invokeConfig = Object.assign({}, chainOptions, {
346
+ run_id: this.id,
347
+ runId: this.id,
348
+ });
349
+ try {
350
+ return await chain.invoke(
351
+ { convo, inputText, skipLanguage },
352
+ invokeConfig
353
+ );
354
+ } catch (_e) {
355
+ // Fallback: strip callbacks to avoid EventStream tracer errors in certain environments
356
+ const { callbacks: _cb, ...rest } = invokeConfig;
357
+ const safeConfig = Object.assign({}, rest, { callbacks: [] });
358
+ return await chain.invoke(
359
+ { convo, inputText, skipLanguage },
360
+ safeConfig as Partial<RunnableConfig>
361
+ );
362
+ }
294
363
  }
295
364
  }
@@ -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
  }