@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
@@ -1,29 +1,27 @@
1
1
  import { nanoid } from 'nanoid';
2
2
  import { concat } from '@langchain/core/utils/stream';
3
3
  import { ChatVertexAI } from '@langchain/google-vertexai';
4
- import { StateGraph, START, END } from '@langchain/langgraph';
5
- import { dispatchCustomEvent } from '@langchain/core/callbacks/dispatch';
4
+ import { Annotation, messagesStateReducer, StateGraph, START, END } from '@langchain/langgraph';
5
+ import { RunnableLambda } from '@langchain/core/runnables';
6
6
  import { SystemMessage, AIMessageChunk, ToolMessage } from '@langchain/core/messages';
7
7
  import { GraphNodeKeys, ContentTypes, Providers, GraphEvents, StepTypes } from '../common/enum.mjs';
8
- import { getChatModelClass, manualToolStreamProviders } from '../llm/providers.mjs';
9
- import { ToolNode, toolsCondition } from '../tools/ToolNode.mjs';
10
- import { convertMessagesToContent, formatAnthropicArtifactContent, formatArtifactPayload, modifyDeltaProperties } from '../messages/core.mjs';
8
+ import { convertMessagesToContent, modifyDeltaProperties, formatAnthropicArtifactContent, formatArtifactPayload } from '../messages/core.mjs';
11
9
  import { createPruneMessages } from '../messages/prune.mjs';
12
10
  import { resetIfNotEmpty, joinKeys } from '../utils/graph.mjs';
13
11
  import { isOpenAILike, isGoogleLike } from '../utils/llm.mjs';
14
12
  import { sleep } from '../utils/run.mjs';
15
13
  import 'js-tiktoken/lite';
14
+ import { getChatModelClass, manualToolStreamProviders } from '../llm/providers.mjs';
15
+ import { ToolNode, toolsCondition } from '../tools/ToolNode.mjs';
16
16
  import { ChatOpenAI, AzureChatOpenAI } from '../llm/openai/index.mjs';
17
+ import { safeDispatchCustomEvent } from '../utils/events.mjs';
18
+ import { AgentContext } from '../agents/AgentContext.mjs';
17
19
  import { createFakeStreamingLLM } from '../llm/fake.mjs';
18
20
 
19
21
  /* eslint-disable no-console */
20
22
  // src/graphs/Graph.ts
21
23
  const { AGENT, TOOLS } = GraphNodeKeys;
22
24
  class Graph {
23
- lastToken;
24
- tokenTypeSwitch;
25
- reasoningKey = 'reasoning_content';
26
- currentTokenType = ContentTypes.TEXT;
27
25
  messageStepHasToolCalls = new Map();
28
26
  messageIdsByStepKey = new Map();
29
27
  prelimMessageIdsByStepKey = new Map();
@@ -32,71 +30,37 @@ class Graph {
32
30
  stepKeyIds = new Map();
33
31
  contentIndexMap = new Map();
34
32
  toolCallStepIds = new Map();
35
- currentUsage;
36
- indexTokenCountMap = {};
37
- maxContextTokens;
38
- pruneMessages;
39
- /** The amount of time that should pass before another consecutive API call */
40
- streamBuffer;
41
- tokenCounter;
42
33
  signal;
34
+ /** Set of invoked tool call IDs from non-message run steps completed mid-run, if any */
35
+ invokedToolIds;
36
+ handlerRegistry;
43
37
  }
44
38
  class StandardGraph extends Graph {
45
- graphState;
46
- clientOptions;
47
- boundModel;
48
- /** The last recorded timestamp that a stream API call was invoked */
49
- lastStreamCall;
50
- handlerRegistry;
51
- systemMessage;
39
+ overrideModel;
40
+ /** Optional compile options passed into workflow.compile() */
41
+ compileOptions;
52
42
  messages = [];
53
43
  runId;
54
- tools;
55
- toolMap;
56
44
  startIndex = 0;
57
- provider;
58
- toolEnd;
59
45
  signal;
60
- constructor({ runId, tools, signal, toolMap, provider, streamBuffer, instructions, reasoningKey, clientOptions, toolEnd = false, additional_instructions = '', }) {
46
+ /** Map of agent contexts by agent ID */
47
+ agentContexts = new Map();
48
+ /** Default agent ID to use */
49
+ defaultAgentId;
50
+ constructor({
51
+ // parent-level graph inputs
52
+ runId, signal, agents, tokenCounter, indexTokenCountMap, }) {
61
53
  super();
62
54
  this.runId = runId;
63
- this.tools = tools;
64
55
  this.signal = signal;
65
- this.toolEnd = toolEnd;
66
- this.toolMap = toolMap;
67
- this.provider = provider;
68
- this.streamBuffer = streamBuffer;
69
- this.clientOptions = clientOptions;
70
- this.graphState = this.createGraphState();
71
- this.boundModel = this.initializeModel();
72
- if (reasoningKey) {
73
- this.reasoningKey = reasoningKey;
56
+ if (agents.length === 0) {
57
+ throw new Error('At least one agent configuration is required');
74
58
  }
75
- let finalInstructions = instructions;
76
- if (additional_instructions) {
77
- finalInstructions =
78
- finalInstructions != null && finalInstructions
79
- ? `${finalInstructions}\n\n${additional_instructions}`
80
- : additional_instructions;
81
- }
82
- if (finalInstructions != null &&
83
- finalInstructions &&
84
- provider === Providers.ANTHROPIC &&
85
- (clientOptions.clientOptions?.defaultHeaders?.['anthropic-beta']?.includes('prompt-caching') ??
86
- false)) {
87
- finalInstructions = {
88
- content: [
89
- {
90
- type: 'text',
91
- text: instructions,
92
- cache_control: { type: 'ephemeral' },
93
- },
94
- ],
95
- };
96
- }
97
- if (finalInstructions != null && finalInstructions !== '') {
98
- this.systemMessage = new SystemMessage(finalInstructions);
59
+ for (const agentConfig of agents) {
60
+ const agentContext = AgentContext.fromConfig(agentConfig, tokenCounter, indexTokenCountMap);
61
+ this.agentContexts.set(agentConfig.agentId, agentContext);
99
62
  }
63
+ this.defaultAgentId = agents[0].agentId;
100
64
  }
101
65
  /* Init */
102
66
  resetValues(keepContent) {
@@ -109,15 +73,12 @@ class StandardGraph extends Graph {
109
73
  this.stepKeyIds = resetIfNotEmpty(this.stepKeyIds, new Map());
110
74
  this.toolCallStepIds = resetIfNotEmpty(this.toolCallStepIds, new Map());
111
75
  this.messageIdsByStepKey = resetIfNotEmpty(this.messageIdsByStepKey, new Map());
112
- this.messageStepHasToolCalls = resetIfNotEmpty(this.prelimMessageIdsByStepKey, new Map());
76
+ this.messageStepHasToolCalls = resetIfNotEmpty(this.messageStepHasToolCalls, new Map());
113
77
  this.prelimMessageIdsByStepKey = resetIfNotEmpty(this.prelimMessageIdsByStepKey, new Map());
114
- this.currentTokenType = resetIfNotEmpty(this.currentTokenType, ContentTypes.TEXT);
115
- this.lastToken = resetIfNotEmpty(this.lastToken, undefined);
116
- this.tokenTypeSwitch = resetIfNotEmpty(this.tokenTypeSwitch, undefined);
117
- this.indexTokenCountMap = resetIfNotEmpty(this.indexTokenCountMap, {});
118
- this.currentUsage = resetIfNotEmpty(this.currentUsage, undefined);
119
- this.tokenCounter = resetIfNotEmpty(this.tokenCounter, undefined);
120
- this.maxContextTokens = resetIfNotEmpty(this.maxContextTokens, undefined);
78
+ this.invokedToolIds = resetIfNotEmpty(this.invokedToolIds, undefined);
79
+ for (const context of this.agentContexts.values()) {
80
+ context.reset();
81
+ }
121
82
  }
122
83
  /* Run Step Processing */
123
84
  getRunStep(stepId) {
@@ -127,6 +88,27 @@ class StandardGraph extends Graph {
127
88
  }
128
89
  return undefined;
129
90
  }
91
+ getAgentContext(metadata) {
92
+ if (!metadata) {
93
+ throw new Error('No metadata provided to retrieve agent context');
94
+ }
95
+ const currentNode = metadata.langgraph_node;
96
+ if (!currentNode) {
97
+ throw new Error('No langgraph_node in metadata to retrieve agent context');
98
+ }
99
+ let agentId;
100
+ if (currentNode.startsWith(AGENT)) {
101
+ agentId = currentNode.substring(AGENT.length);
102
+ }
103
+ else if (currentNode.startsWith(TOOLS)) {
104
+ agentId = currentNode.substring(TOOLS.length);
105
+ }
106
+ const agentContext = this.agentContexts.get(agentId ?? '');
107
+ if (!agentContext) {
108
+ throw new Error(`No agent context found for agent ID ${agentId}`);
109
+ }
110
+ return agentContext;
111
+ }
130
112
  getStepKey(metadata) {
131
113
  if (!metadata)
132
114
  return '';
@@ -172,10 +154,14 @@ class StandardGraph extends Graph {
172
154
  metadata.langgraph_step,
173
155
  metadata.checkpoint_ns,
174
156
  ];
175
- if (this.currentTokenType === ContentTypes.THINK ||
176
- this.currentTokenType === 'think_and_text') {
157
+ const agentContext = this.getAgentContext(metadata);
158
+ if (agentContext.currentTokenType === ContentTypes.THINK ||
159
+ agentContext.currentTokenType === 'think_and_text') {
177
160
  keyList.push('reasoning');
178
161
  }
162
+ if (this.invokedToolIds != null && this.invokedToolIds.size > 0) {
163
+ keyList.push(this.invokedToolIds.size + '');
164
+ }
179
165
  return keyList;
180
166
  }
181
167
  checkKeyList(keyList) {
@@ -189,113 +175,158 @@ class StandardGraph extends Graph {
189
175
  return convertMessagesToContent(this.messages.slice(this.startIndex));
190
176
  }
191
177
  /* Graph */
192
- createGraphState() {
193
- return {
194
- messages: {
195
- value: (x, y) => {
196
- if (!x.length) {
197
- if (this.systemMessage) {
198
- x.push(this.systemMessage);
199
- }
200
- this.startIndex = x.length + y.length;
201
- }
202
- const current = x.concat(y);
203
- this.messages = current;
204
- return current;
205
- },
206
- default: () => [],
207
- },
208
- };
178
+ createSystemRunnable({ provider, clientOptions, instructions, additional_instructions, }) {
179
+ let finalInstructions = instructions;
180
+ if (additional_instructions != null && additional_instructions !== '') {
181
+ finalInstructions =
182
+ finalInstructions != null && finalInstructions
183
+ ? `${finalInstructions}\n\n${additional_instructions}`
184
+ : additional_instructions;
185
+ }
186
+ if (finalInstructions != null &&
187
+ finalInstructions &&
188
+ provider === Providers.ANTHROPIC &&
189
+ (clientOptions.clientOptions
190
+ ?.defaultHeaders?.['anthropic-beta']?.includes('prompt-caching') ??
191
+ false)) {
192
+ finalInstructions = {
193
+ content: [
194
+ {
195
+ type: 'text',
196
+ text: instructions,
197
+ cache_control: { type: 'ephemeral' },
198
+ },
199
+ ],
200
+ };
201
+ }
202
+ if (finalInstructions != null && finalInstructions !== '') {
203
+ const systemMessage = new SystemMessage(finalInstructions);
204
+ return RunnableLambda.from((messages) => {
205
+ return [systemMessage, ...messages];
206
+ }).withConfig({ runName: 'prompt' });
207
+ }
209
208
  }
210
- initializeTools() {
211
- // return new ToolNode<t.BaseGraphState>(this.tools);
209
+ initializeTools({ currentTools, currentToolMap, }) {
212
210
  return new ToolNode({
213
- tools: this.tools || [],
214
- toolMap: this.toolMap,
211
+ tools: currentTools ?? [],
212
+ toolMap: currentToolMap,
215
213
  toolCallStepIds: this.toolCallStepIds,
216
214
  errorHandler: (data, metadata) => StandardGraph.handleToolCallErrorStatic(this, data, metadata),
217
215
  });
218
216
  }
219
- initializeModel() {
220
- const ChatModelClass = getChatModelClass(this.provider);
221
- const model = new ChatModelClass(this.clientOptions);
222
- if (isOpenAILike(this.provider) &&
217
+ initializeModel({ provider, tools, clientOptions, }) {
218
+ const ChatModelClass = getChatModelClass(provider);
219
+ const model = new ChatModelClass(clientOptions ?? {});
220
+ if (isOpenAILike(provider) &&
223
221
  (model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)) {
224
- model.temperature = this.clientOptions
222
+ model.temperature = clientOptions
225
223
  .temperature;
226
- model.topP = this.clientOptions.topP;
227
- model.frequencyPenalty = this.clientOptions
224
+ model.topP = clientOptions.topP;
225
+ model.frequencyPenalty = clientOptions
228
226
  .frequencyPenalty;
229
- model.presencePenalty = this.clientOptions
227
+ model.presencePenalty = clientOptions
230
228
  .presencePenalty;
231
- model.n = this.clientOptions.n;
229
+ model.n = clientOptions.n;
232
230
  }
233
- else if (this.provider === Providers.VERTEXAI &&
231
+ else if (provider === Providers.VERTEXAI &&
234
232
  model instanceof ChatVertexAI) {
235
- model.temperature = this.clientOptions
233
+ model.temperature = clientOptions
236
234
  .temperature;
237
- model.topP = this.clientOptions
238
- .topP;
239
- model.topK = this.clientOptions
240
- .topK;
241
- model.topLogprobs = this.clientOptions
235
+ model.topP = clientOptions.topP;
236
+ model.topK = clientOptions.topK;
237
+ model.topLogprobs = clientOptions
242
238
  .topLogprobs;
243
- model.frequencyPenalty = this.clientOptions
239
+ model.frequencyPenalty = clientOptions
244
240
  .frequencyPenalty;
245
- model.presencePenalty = this.clientOptions
241
+ model.presencePenalty = clientOptions
246
242
  .presencePenalty;
247
- model.maxOutputTokens = this.clientOptions
243
+ model.maxOutputTokens = clientOptions
248
244
  .maxOutputTokens;
249
245
  }
250
- if (!this.tools || this.tools.length === 0) {
246
+ if (!tools || tools.length === 0) {
251
247
  return model;
252
248
  }
253
- return model.bindTools(this.tools);
249
+ return model.bindTools(tools);
254
250
  }
255
251
  overrideTestModel(responses, sleep, toolCalls) {
256
- this.boundModel = createFakeStreamingLLM({
252
+ this.overrideModel = createFakeStreamingLLM({
257
253
  responses,
258
254
  sleep,
259
255
  toolCalls,
260
256
  });
261
257
  }
262
- getNewModel({ clientOptions = {}, omitOriginalOptions, }) {
263
- const ChatModelClass = getChatModelClass(this.provider);
264
- const _options = omitOriginalOptions
265
- ? Object.fromEntries(Object.entries(this.clientOptions).filter(([key]) => !omitOriginalOptions.has(key)))
266
- : this.clientOptions;
267
- const options = Object.assign(_options, clientOptions);
268
- return new ChatModelClass(options);
258
+ getNewModel({ provider, clientOptions, }) {
259
+ const ChatModelClass = getChatModelClass(provider);
260
+ return new ChatModelClass(clientOptions ?? {});
269
261
  }
270
- storeUsageMetadata(finalMessage) {
262
+ getUsageMetadata(finalMessage) {
271
263
  if (finalMessage &&
272
264
  'usage_metadata' in finalMessage &&
273
265
  finalMessage.usage_metadata != null) {
274
- this.currentUsage = finalMessage.usage_metadata;
266
+ return finalMessage.usage_metadata;
267
+ }
268
+ }
269
+ /** Execute model invocation with streaming support */
270
+ async attemptInvoke({ currentModel, finalMessages, provider, tools, }, config) {
271
+ const model = this.overrideModel ?? currentModel;
272
+ if (!model) {
273
+ throw new Error('No model found');
274
+ }
275
+ if ((tools?.length ?? 0) > 0 && manualToolStreamProviders.has(provider)) {
276
+ if (!model.stream) {
277
+ throw new Error('Model does not support stream');
278
+ }
279
+ const stream = await model.stream(finalMessages, config);
280
+ let finalChunk;
281
+ for await (const chunk of stream) {
282
+ await safeDispatchCustomEvent(GraphEvents.CHAT_MODEL_STREAM, { chunk, emitted: true }, config);
283
+ finalChunk = finalChunk ? concat(finalChunk, chunk) : chunk;
284
+ }
285
+ finalChunk = modifyDeltaProperties(provider, finalChunk);
286
+ return { messages: [finalChunk] };
287
+ }
288
+ else {
289
+ const finalMessage = await model.invoke(finalMessages, config);
290
+ if ((finalMessage.tool_calls?.length ?? 0) > 0) {
291
+ finalMessage.tool_calls = finalMessage.tool_calls?.filter((tool_call) => !!tool_call.name);
292
+ }
293
+ return { messages: [finalMessage] };
275
294
  }
276
295
  }
277
- cleanupSignalListener() {
296
+ cleanupSignalListener(currentModel) {
278
297
  if (!this.signal) {
279
298
  return;
280
299
  }
281
- if (!this.boundModel) {
300
+ const model = this.overrideModel ?? currentModel;
301
+ if (!model) {
282
302
  return;
283
303
  }
284
- const client = this.boundModel?.exposedClient;
304
+ const client = model?.exposedClient;
285
305
  if (!client?.abortHandler) {
286
306
  return;
287
307
  }
288
308
  this.signal.removeEventListener('abort', client.abortHandler);
289
309
  client.abortHandler = undefined;
290
310
  }
291
- createCallModel() {
311
+ createCallModel(agentId = 'default', currentModel) {
292
312
  return async (state, config) => {
293
- const { provider = '' } = config?.configurable ?? {};
294
- if (this.boundModel == null) {
313
+ /**
314
+ * Get agent context - it must exist by this point
315
+ */
316
+ const agentContext = this.agentContexts.get(agentId);
317
+ if (!agentContext) {
318
+ throw new Error(`Agent context not found for agentId: ${agentId}`);
319
+ }
320
+ const model = this.overrideModel ?? currentModel;
321
+ if (!model) {
295
322
  throw new Error('No Graph model found');
296
323
  }
297
- if (!config || !provider) {
298
- throw new Error(`No ${config ? 'provider' : 'config'} provided`);
324
+ if (!config) {
325
+ throw new Error('No config provided');
326
+ }
327
+ // Ensure token calculations are complete before proceeding
328
+ if (agentContext.tokenCalculationPromise) {
329
+ await agentContext.tokenCalculationPromise;
299
330
  }
300
331
  if (!config.signal) {
301
332
  config.signal = this.signal;
@@ -303,32 +334,32 @@ class StandardGraph extends Graph {
303
334
  this.config = config;
304
335
  const { messages } = state;
305
336
  let messagesToUse = messages;
306
- if (!this.pruneMessages &&
307
- this.tokenCounter &&
308
- this.maxContextTokens != null &&
309
- this.indexTokenCountMap[0] != null) {
310
- const isAnthropicWithThinking = (this.provider === Providers.ANTHROPIC &&
311
- this.clientOptions.thinking !=
337
+ if (!agentContext.pruneMessages &&
338
+ agentContext.tokenCounter &&
339
+ agentContext.maxContextTokens != null &&
340
+ agentContext.indexTokenCountMap[0] != null) {
341
+ const isAnthropicWithThinking = (agentContext.provider === Providers.ANTHROPIC &&
342
+ agentContext.clientOptions.thinking !=
312
343
  null) ||
313
- (this.provider === Providers.BEDROCK &&
314
- this.clientOptions
344
+ (agentContext.provider === Providers.BEDROCK &&
345
+ agentContext.clientOptions
315
346
  .additionalModelRequestFields?.['thinking'] != null);
316
- this.pruneMessages = createPruneMessages({
317
- provider: this.provider,
318
- indexTokenCountMap: this.indexTokenCountMap,
319
- maxTokens: this.maxContextTokens,
320
- tokenCounter: this.tokenCounter,
347
+ agentContext.pruneMessages = createPruneMessages({
321
348
  startIndex: this.startIndex,
349
+ provider: agentContext.provider,
350
+ tokenCounter: agentContext.tokenCounter,
351
+ maxTokens: agentContext.maxContextTokens,
322
352
  thinkingEnabled: isAnthropicWithThinking,
353
+ indexTokenCountMap: agentContext.indexTokenCountMap,
323
354
  });
324
355
  }
325
- if (this.pruneMessages) {
326
- const { context, indexTokenCountMap } = this.pruneMessages({
356
+ if (agentContext.pruneMessages) {
357
+ const { context, indexTokenCountMap } = agentContext.pruneMessages({
327
358
  messages,
328
- usageMetadata: this.currentUsage,
359
+ usageMetadata: agentContext.currentUsage,
329
360
  // startOnMessageType: 'human',
330
361
  });
331
- this.indexTokenCountMap = indexTokenCountMap;
362
+ agentContext.indexTokenCountMap = indexTokenCountMap;
332
363
  messagesToUse = context;
333
364
  }
334
365
  const finalMessages = messagesToUse;
@@ -338,87 +369,145 @@ class StandardGraph extends Graph {
338
369
  const lastMessageY = finalMessages.length >= 1
339
370
  ? finalMessages[finalMessages.length - 1]
340
371
  : null;
341
- if (provider === Providers.BEDROCK &&
372
+ if (agentContext.provider === Providers.BEDROCK &&
342
373
  lastMessageX instanceof AIMessageChunk &&
343
374
  lastMessageY instanceof ToolMessage &&
344
375
  typeof lastMessageX.content === 'string') {
345
376
  finalMessages[finalMessages.length - 2].content = '';
346
377
  }
347
378
  const isLatestToolMessage = lastMessageY instanceof ToolMessage;
348
- if (isLatestToolMessage && provider === Providers.ANTHROPIC) {
379
+ if (isLatestToolMessage &&
380
+ agentContext.provider === Providers.ANTHROPIC) {
349
381
  formatAnthropicArtifactContent(finalMessages);
350
382
  }
351
383
  else if (isLatestToolMessage &&
352
- (isOpenAILike(provider) || isGoogleLike(provider))) {
384
+ (isOpenAILike(agentContext.provider) ||
385
+ isGoogleLike(agentContext.provider))) {
353
386
  formatArtifactPayload(finalMessages);
354
387
  }
355
- if (this.lastStreamCall != null && this.streamBuffer != null) {
356
- const timeSinceLastCall = Date.now() - this.lastStreamCall;
357
- if (timeSinceLastCall < this.streamBuffer) {
358
- const timeToWait = Math.ceil((this.streamBuffer - timeSinceLastCall) / 1000) * 1000;
388
+ if (agentContext.lastStreamCall != null &&
389
+ agentContext.streamBuffer != null) {
390
+ const timeSinceLastCall = Date.now() - agentContext.lastStreamCall;
391
+ if (timeSinceLastCall < agentContext.streamBuffer) {
392
+ const timeToWait = Math.ceil((agentContext.streamBuffer - timeSinceLastCall) / 1000) *
393
+ 1000;
359
394
  await sleep(timeToWait);
360
395
  }
361
396
  }
362
- this.lastStreamCall = Date.now();
397
+ agentContext.lastStreamCall = Date.now();
363
398
  let result;
364
- if ((this.tools?.length ?? 0) > 0 &&
365
- manualToolStreamProviders.has(provider)) {
366
- const stream = await this.boundModel.stream(finalMessages, config);
367
- let finalChunk;
368
- for await (const chunk of stream) {
369
- dispatchCustomEvent(GraphEvents.CHAT_MODEL_STREAM, { chunk }, config);
370
- if (!finalChunk) {
371
- finalChunk = chunk;
399
+ const fallbacks = agentContext.clientOptions?.fallbacks ??
400
+ [];
401
+ try {
402
+ result = await this.attemptInvoke({
403
+ currentModel: model,
404
+ finalMessages,
405
+ provider: agentContext.provider,
406
+ tools: agentContext.tools,
407
+ }, config);
408
+ }
409
+ catch (primaryError) {
410
+ let lastError = primaryError;
411
+ for (const fb of fallbacks) {
412
+ try {
413
+ let model = this.getNewModel({
414
+ provider: fb.provider,
415
+ clientOptions: fb.clientOptions,
416
+ });
417
+ const bindableTools = agentContext.tools;
418
+ model = (!bindableTools || bindableTools.length === 0
419
+ ? model
420
+ : model.bindTools(bindableTools));
421
+ result = await this.attemptInvoke({
422
+ currentModel: model,
423
+ finalMessages,
424
+ provider: fb.provider,
425
+ tools: agentContext.tools,
426
+ }, config);
427
+ lastError = undefined;
428
+ break;
372
429
  }
373
- else {
374
- finalChunk = concat(finalChunk, chunk);
430
+ catch (e) {
431
+ lastError = e;
432
+ continue;
375
433
  }
376
434
  }
377
- finalChunk = modifyDeltaProperties(this.provider, finalChunk);
378
- result = { messages: [finalChunk] };
379
- }
380
- else {
381
- const finalMessage = (await this.boundModel.invoke(finalMessages, config));
382
- if ((finalMessage.tool_calls?.length ?? 0) > 0) {
383
- finalMessage.tool_calls = finalMessage.tool_calls?.filter((tool_call) => {
384
- if (!tool_call.name) {
385
- return false;
386
- }
387
- return true;
388
- });
435
+ if (lastError !== undefined) {
436
+ throw lastError;
389
437
  }
390
- result = { messages: [finalMessage] };
391
438
  }
392
- this.storeUsageMetadata(result.messages?.[0]);
439
+ if (!result) {
440
+ throw new Error('No result after model invocation');
441
+ }
442
+ agentContext.currentUsage = this.getUsageMetadata(result.messages?.[0]);
393
443
  this.cleanupSignalListener();
394
444
  return result;
395
445
  };
396
446
  }
397
- createWorkflow() {
447
+ createAgentNode(agentId) {
448
+ const agentContext = this.agentContexts.get(agentId);
449
+ if (!agentContext) {
450
+ throw new Error(`Agent context not found for agentId: ${agentId}`);
451
+ }
452
+ let currentModel = this.initializeModel({
453
+ tools: agentContext.tools,
454
+ provider: agentContext.provider,
455
+ clientOptions: agentContext.clientOptions,
456
+ });
457
+ if (agentContext.systemRunnable) {
458
+ currentModel = agentContext.systemRunnable.pipe(currentModel);
459
+ }
460
+ const agentNode = `${AGENT}${agentId}`;
461
+ const toolNode = `${TOOLS}${agentId}`;
398
462
  const routeMessage = (state, config) => {
399
463
  this.config = config;
400
- // const lastMessage = state.messages[state.messages.length - 1] as AIMessage;
401
- // if (!lastMessage?.tool_calls?.length) {
402
- // return END;
403
- // }
404
- // return TOOLS;
405
- return toolsCondition(state);
464
+ return toolsCondition(state, toolNode, this.invokedToolIds);
406
465
  };
407
- const workflow = new StateGraph({
408
- channels: this.graphState,
409
- })
410
- .addNode(AGENT, this.createCallModel())
411
- .addNode(TOOLS, this.initializeTools())
412
- .addEdge(START, AGENT)
413
- .addConditionalEdges(AGENT, routeMessage)
414
- .addEdge(TOOLS, this.toolEnd ? END : AGENT);
415
- return workflow.compile();
466
+ const StateAnnotation = Annotation.Root({
467
+ messages: Annotation({
468
+ reducer: messagesStateReducer,
469
+ default: () => [],
470
+ }),
471
+ });
472
+ const workflow = new StateGraph(StateAnnotation)
473
+ .addNode(agentNode, this.createCallModel(agentId, currentModel))
474
+ .addNode(toolNode, this.initializeTools({
475
+ currentTools: agentContext.tools,
476
+ currentToolMap: agentContext.toolMap,
477
+ }))
478
+ .addEdge(START, agentNode)
479
+ .addConditionalEdges(agentNode, routeMessage)
480
+ .addEdge(toolNode, agentContext.toolEnd ? END : agentNode);
481
+ // Cast to unknown to avoid tight coupling to external types; options are opt-in
482
+ return workflow.compile(this.compileOptions);
483
+ }
484
+ createWorkflow() {
485
+ /** Use the default (first) agent for now */
486
+ const agentNode = this.createAgentNode(this.defaultAgentId);
487
+ const StateAnnotation = Annotation.Root({
488
+ messages: Annotation({
489
+ reducer: (a, b) => {
490
+ if (!a.length) {
491
+ this.startIndex = a.length + b.length;
492
+ }
493
+ const result = messagesStateReducer(a, b);
494
+ this.messages = result;
495
+ return result;
496
+ },
497
+ default: () => [],
498
+ }),
499
+ });
500
+ const workflow = new StateGraph(StateAnnotation)
501
+ .addNode(this.defaultAgentId, agentNode, { ends: [END] })
502
+ .addEdge(START, this.defaultAgentId)
503
+ .compile();
504
+ return workflow;
416
505
  }
417
506
  /* Dispatchers */
418
507
  /**
419
508
  * Dispatches a run step to the client, returns the step ID
420
509
  */
421
- dispatchRunStep(stepKey, stepDetails) {
510
+ async dispatchRunStep(stepKey, stepDetails) {
422
511
  if (!this.config) {
423
512
  throw new Error('No config provided');
424
513
  }
@@ -446,17 +535,21 @@ class StandardGraph extends Graph {
446
535
  }
447
536
  this.contentData.push(runStep);
448
537
  this.contentIndexMap.set(stepId, runStep.index);
449
- dispatchCustomEvent(GraphEvents.ON_RUN_STEP, runStep, this.config);
538
+ await safeDispatchCustomEvent(GraphEvents.ON_RUN_STEP, runStep, this.config);
450
539
  return stepId;
451
540
  }
452
- handleToolCallCompleted(data, metadata) {
541
+ async handleToolCallCompleted(data, metadata, omitOutput) {
453
542
  if (!this.config) {
454
543
  throw new Error('No config provided');
455
544
  }
456
545
  if (!data.output) {
457
546
  return;
458
547
  }
459
- const { input, output } = data;
548
+ const { input, output: _output } = data;
549
+ if (_output?.lg_name === 'Command') {
550
+ return;
551
+ }
552
+ const output = _output;
460
553
  const { tool_call_id } = output;
461
554
  const stepId = this.toolCallStepIds.get(tool_call_id) ?? '';
462
555
  if (!stepId) {
@@ -466,17 +559,20 @@ class StandardGraph extends Graph {
466
559
  if (!runStep) {
467
560
  throw new Error(`No run step found for stepId ${stepId}`);
468
561
  }
562
+ const dispatchedOutput = typeof output.content === 'string'
563
+ ? output.content
564
+ : JSON.stringify(output.content);
469
565
  const args = typeof input === 'string' ? input : input.input;
470
566
  const tool_call = {
471
567
  args: typeof args === 'string' ? args : JSON.stringify(args),
472
568
  name: output.name ?? '',
473
569
  id: output.tool_call_id,
474
- output: typeof output.content === 'string'
475
- ? output.content
476
- : JSON.stringify(output.content),
570
+ output: omitOutput === true ? '' : dispatchedOutput,
477
571
  progress: 1,
478
572
  };
479
- this.handlerRegistry?.getHandler(GraphEvents.ON_RUN_STEP_COMPLETED)?.handle(GraphEvents.ON_RUN_STEP_COMPLETED, {
573
+ await this.handlerRegistry
574
+ ?.getHandler(GraphEvents.ON_RUN_STEP_COMPLETED)
575
+ ?.handle(GraphEvents.ON_RUN_STEP_COMPLETED, {
480
576
  result: {
481
577
  id: stepId,
482
578
  index: runStep.index,
@@ -489,7 +585,7 @@ class StandardGraph extends Graph {
489
585
  * Static version of handleToolCallError to avoid creating strong references
490
586
  * that prevent garbage collection
491
587
  */
492
- static handleToolCallErrorStatic(graph, data, metadata) {
588
+ static async handleToolCallErrorStatic(graph, data, metadata) {
493
589
  if (!graph.config) {
494
590
  throw new Error('No config provided');
495
591
  }
@@ -513,7 +609,7 @@ class StandardGraph extends Graph {
513
609
  output: `Error processing tool${error?.message != null ? `: ${error.message}` : ''}`,
514
610
  progress: 1,
515
611
  };
516
- graph.handlerRegistry
612
+ await graph.handlerRegistry
517
613
  ?.getHandler(GraphEvents.ON_RUN_STEP_COMPLETED)
518
614
  ?.handle(GraphEvents.ON_RUN_STEP_COMPLETED, {
519
615
  result: {
@@ -528,10 +624,10 @@ class StandardGraph extends Graph {
528
624
  * Instance method that delegates to the static method
529
625
  * Kept for backward compatibility
530
626
  */
531
- handleToolCallError(data, metadata) {
532
- StandardGraph.handleToolCallErrorStatic(this, data, metadata);
627
+ async handleToolCallError(data, metadata) {
628
+ await StandardGraph.handleToolCallErrorStatic(this, data, metadata);
533
629
  }
534
- dispatchRunStepDelta(id, delta) {
630
+ async dispatchRunStepDelta(id, delta) {
535
631
  if (!this.config) {
536
632
  throw new Error('No config provided');
537
633
  }
@@ -542,9 +638,9 @@ class StandardGraph extends Graph {
542
638
  id,
543
639
  delta,
544
640
  };
545
- dispatchCustomEvent(GraphEvents.ON_RUN_STEP_DELTA, runStepDelta, this.config);
641
+ await safeDispatchCustomEvent(GraphEvents.ON_RUN_STEP_DELTA, runStepDelta, this.config);
546
642
  }
547
- dispatchMessageDelta(id, delta) {
643
+ async dispatchMessageDelta(id, delta) {
548
644
  if (!this.config) {
549
645
  throw new Error('No config provided');
550
646
  }
@@ -552,9 +648,9 @@ class StandardGraph extends Graph {
552
648
  id,
553
649
  delta,
554
650
  };
555
- dispatchCustomEvent(GraphEvents.ON_MESSAGE_DELTA, messageDelta, this.config);
651
+ await safeDispatchCustomEvent(GraphEvents.ON_MESSAGE_DELTA, messageDelta, this.config);
556
652
  }
557
- dispatchReasoningDelta = (stepId, delta) => {
653
+ dispatchReasoningDelta = async (stepId, delta) => {
558
654
  if (!this.config) {
559
655
  throw new Error('No config provided');
560
656
  }
@@ -562,7 +658,7 @@ class StandardGraph extends Graph {
562
658
  id: stepId,
563
659
  delta,
564
660
  };
565
- dispatchCustomEvent(GraphEvents.ON_REASONING_DELTA, reasoningDelta, this.config);
661
+ await safeDispatchCustomEvent(GraphEvents.ON_REASONING_DELTA, reasoningDelta, this.config);
566
662
  };
567
663
  }
568
664