@librechat/agents 2.4.321 → 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 (266) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +218 -0
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -0
  3. package/dist/cjs/common/enum.cjs +14 -5
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/events.cjs +10 -6
  6. package/dist/cjs/events.cjs.map +1 -1
  7. package/dist/cjs/graphs/Graph.cjs +309 -212
  8. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  9. package/dist/cjs/graphs/MultiAgentGraph.cjs +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 +61 -13
  51. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  52. package/dist/cjs/tools/search/format.cjs +9 -3
  53. package/dist/cjs/tools/search/format.cjs.map +1 -1
  54. package/dist/cjs/tools/search/rerankers.cjs +35 -50
  55. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  56. package/dist/cjs/tools/search/schema.cjs +70 -0
  57. package/dist/cjs/tools/search/schema.cjs.map +1 -0
  58. package/dist/cjs/tools/search/search.cjs +145 -38
  59. package/dist/cjs/tools/search/search.cjs.map +1 -1
  60. package/dist/cjs/tools/search/tool.cjs +165 -48
  61. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  62. package/dist/cjs/tools/search/utils.cjs +34 -5
  63. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  64. package/dist/cjs/utils/events.cjs +31 -0
  65. package/dist/cjs/utils/events.cjs.map +1 -0
  66. package/dist/cjs/utils/title.cjs +57 -21
  67. package/dist/cjs/utils/title.cjs.map +1 -1
  68. package/dist/cjs/utils/tokens.cjs +54 -7
  69. package/dist/cjs/utils/tokens.cjs.map +1 -1
  70. package/dist/esm/agents/AgentContext.mjs +216 -0
  71. package/dist/esm/agents/AgentContext.mjs.map +1 -0
  72. package/dist/esm/common/enum.mjs +15 -6
  73. package/dist/esm/common/enum.mjs.map +1 -1
  74. package/dist/esm/events.mjs +10 -6
  75. package/dist/esm/events.mjs.map +1 -1
  76. package/dist/esm/graphs/Graph.mjs +311 -214
  77. package/dist/esm/graphs/Graph.mjs.map +1 -1
  78. package/dist/esm/graphs/MultiAgentGraph.mjs +320 -0
  79. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -0
  80. package/dist/esm/llm/anthropic/index.mjs +54 -9
  81. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  82. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  83. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +52 -6
  84. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  85. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +22 -2
  86. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  87. package/dist/esm/llm/anthropic/utils/tools.mjs +27 -0
  88. package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -0
  89. package/dist/esm/llm/google/index.mjs +142 -0
  90. package/dist/esm/llm/google/index.mjs.map +1 -0
  91. package/dist/esm/llm/google/utils/common.mjs +471 -0
  92. package/dist/esm/llm/google/utils/common.mjs.map +1 -0
  93. package/dist/esm/llm/ollama/index.mjs +65 -0
  94. package/dist/esm/llm/ollama/index.mjs.map +1 -0
  95. package/dist/esm/llm/ollama/utils.mjs +155 -0
  96. package/dist/esm/llm/ollama/utils.mjs.map +1 -0
  97. package/dist/esm/llm/openai/index.mjs +388 -4
  98. package/dist/esm/llm/openai/index.mjs.map +1 -1
  99. package/dist/esm/llm/openai/utils/index.mjs +666 -0
  100. package/dist/esm/llm/openai/utils/index.mjs.map +1 -0
  101. package/dist/esm/llm/providers.mjs +5 -5
  102. package/dist/esm/llm/providers.mjs.map +1 -1
  103. package/dist/esm/llm/text.mjs +14 -3
  104. package/dist/esm/llm/text.mjs.map +1 -1
  105. package/dist/esm/llm/vertexai/index.mjs +328 -0
  106. package/dist/esm/llm/vertexai/index.mjs.map +1 -0
  107. package/dist/esm/main.mjs +6 -5
  108. package/dist/esm/main.mjs.map +1 -1
  109. package/dist/esm/run.mjs +121 -83
  110. package/dist/esm/run.mjs.map +1 -1
  111. package/dist/esm/stream.mjs +87 -54
  112. package/dist/esm/stream.mjs.map +1 -1
  113. package/dist/esm/tools/ToolNode.mjs +10 -4
  114. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  115. package/dist/esm/tools/handlers.mjs +119 -15
  116. package/dist/esm/tools/handlers.mjs.map +1 -1
  117. package/dist/esm/tools/search/anthropic.mjs +37 -0
  118. package/dist/esm/tools/search/anthropic.mjs.map +1 -0
  119. package/dist/esm/tools/search/firecrawl.mjs +61 -13
  120. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  121. package/dist/esm/tools/search/format.mjs +10 -4
  122. package/dist/esm/tools/search/format.mjs.map +1 -1
  123. package/dist/esm/tools/search/rerankers.mjs +35 -50
  124. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  125. package/dist/esm/tools/search/schema.mjs +61 -0
  126. package/dist/esm/tools/search/schema.mjs.map +1 -0
  127. package/dist/esm/tools/search/search.mjs +146 -39
  128. package/dist/esm/tools/search/search.mjs.map +1 -1
  129. package/dist/esm/tools/search/tool.mjs +164 -47
  130. package/dist/esm/tools/search/tool.mjs.map +1 -1
  131. package/dist/esm/tools/search/utils.mjs +33 -6
  132. package/dist/esm/tools/search/utils.mjs.map +1 -1
  133. package/dist/esm/utils/events.mjs +29 -0
  134. package/dist/esm/utils/events.mjs.map +1 -0
  135. package/dist/esm/utils/title.mjs +57 -22
  136. package/dist/esm/utils/title.mjs.map +1 -1
  137. package/dist/esm/utils/tokens.mjs +54 -8
  138. package/dist/esm/utils/tokens.mjs.map +1 -1
  139. package/dist/types/agents/AgentContext.d.ts +91 -0
  140. package/dist/types/common/enum.d.ts +15 -6
  141. package/dist/types/events.d.ts +5 -4
  142. package/dist/types/graphs/Graph.d.ts +64 -67
  143. package/dist/types/graphs/MultiAgentGraph.d.ts +37 -0
  144. package/dist/types/graphs/index.d.ts +1 -0
  145. package/dist/types/llm/anthropic/index.d.ts +11 -0
  146. package/dist/types/llm/anthropic/types.d.ts +9 -3
  147. package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
  148. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +4 -4
  149. package/dist/types/llm/anthropic/utils/tools.d.ts +3 -0
  150. package/dist/types/llm/google/index.d.ts +13 -0
  151. package/dist/types/llm/google/types.d.ts +32 -0
  152. package/dist/types/llm/google/utils/common.d.ts +19 -0
  153. package/dist/types/llm/google/utils/tools.d.ts +10 -0
  154. package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +14 -0
  155. package/dist/types/llm/ollama/index.d.ts +7 -0
  156. package/dist/types/llm/ollama/utils.d.ts +7 -0
  157. package/dist/types/llm/openai/index.d.ts +72 -3
  158. package/dist/types/llm/openai/types.d.ts +10 -0
  159. package/dist/types/llm/openai/utils/index.d.ts +20 -0
  160. package/dist/types/llm/text.d.ts +1 -1
  161. package/dist/types/llm/vertexai/index.d.ts +293 -0
  162. package/dist/types/messages/reducer.d.ts +9 -0
  163. package/dist/types/run.d.ts +19 -12
  164. package/dist/types/scripts/ant_web_search.d.ts +1 -0
  165. package/dist/types/scripts/args.d.ts +2 -1
  166. package/dist/types/scripts/handoff-test.d.ts +1 -0
  167. package/dist/types/scripts/multi-agent-conditional.d.ts +1 -0
  168. package/dist/types/scripts/multi-agent-parallel.d.ts +1 -0
  169. package/dist/types/scripts/multi-agent-sequence.d.ts +1 -0
  170. package/dist/types/scripts/multi-agent-test.d.ts +1 -0
  171. package/dist/types/stream.d.ts +10 -3
  172. package/dist/types/tools/CodeExecutor.d.ts +2 -2
  173. package/dist/types/tools/ToolNode.d.ts +1 -1
  174. package/dist/types/tools/handlers.d.ts +17 -4
  175. package/dist/types/tools/search/anthropic.d.ts +16 -0
  176. package/dist/types/tools/search/firecrawl.d.ts +16 -0
  177. package/dist/types/tools/search/rerankers.d.ts +8 -5
  178. package/dist/types/tools/search/schema.d.ts +16 -0
  179. package/dist/types/tools/search/tool.d.ts +13 -0
  180. package/dist/types/tools/search/types.d.ts +64 -9
  181. package/dist/types/tools/search/utils.d.ts +9 -2
  182. package/dist/types/types/graph.d.ts +95 -15
  183. package/dist/types/types/llm.d.ts +24 -10
  184. package/dist/types/types/run.d.ts +46 -8
  185. package/dist/types/types/stream.d.ts +16 -2
  186. package/dist/types/types/tools.d.ts +1 -1
  187. package/dist/types/utils/events.d.ts +6 -0
  188. package/dist/types/utils/title.d.ts +2 -1
  189. package/dist/types/utils/tokens.d.ts +24 -0
  190. package/package.json +35 -18
  191. package/src/agents/AgentContext.ts +315 -0
  192. package/src/common/enum.ts +14 -5
  193. package/src/events.ts +24 -13
  194. package/src/graphs/Graph.ts +495 -312
  195. package/src/graphs/MultiAgentGraph.ts +381 -0
  196. package/src/graphs/index.ts +2 -1
  197. package/src/llm/anthropic/Jacob_Lee_Resume_2023.pdf +0 -0
  198. package/src/llm/anthropic/index.ts +78 -13
  199. package/src/llm/anthropic/llm.spec.ts +491 -115
  200. package/src/llm/anthropic/types.ts +39 -3
  201. package/src/llm/anthropic/utils/message_inputs.ts +67 -11
  202. package/src/llm/anthropic/utils/message_outputs.ts +21 -2
  203. package/src/llm/anthropic/utils/output_parsers.ts +25 -6
  204. package/src/llm/anthropic/utils/tools.ts +29 -0
  205. package/src/llm/google/index.ts +218 -0
  206. package/src/llm/google/types.ts +43 -0
  207. package/src/llm/google/utils/common.ts +646 -0
  208. package/src/llm/google/utils/tools.ts +160 -0
  209. package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -0
  210. package/src/llm/ollama/index.ts +89 -0
  211. package/src/llm/ollama/utils.ts +193 -0
  212. package/src/llm/openai/index.ts +600 -14
  213. package/src/llm/openai/types.ts +24 -0
  214. package/src/llm/openai/utils/index.ts +912 -0
  215. package/src/llm/openai/utils/isReasoningModel.test.ts +90 -0
  216. package/src/llm/providers.ts +10 -9
  217. package/src/llm/text.ts +26 -7
  218. package/src/llm/vertexai/index.ts +360 -0
  219. package/src/messages/reducer.ts +80 -0
  220. package/src/run.ts +181 -112
  221. package/src/scripts/ant_web_search.ts +158 -0
  222. package/src/scripts/args.ts +12 -8
  223. package/src/scripts/cli4.ts +29 -21
  224. package/src/scripts/cli5.ts +29 -21
  225. package/src/scripts/code_exec.ts +54 -23
  226. package/src/scripts/code_exec_files.ts +48 -17
  227. package/src/scripts/code_exec_simple.ts +46 -27
  228. package/src/scripts/handoff-test.ts +135 -0
  229. package/src/scripts/image.ts +52 -20
  230. package/src/scripts/multi-agent-conditional.ts +220 -0
  231. package/src/scripts/multi-agent-example-output.md +110 -0
  232. package/src/scripts/multi-agent-parallel.ts +337 -0
  233. package/src/scripts/multi-agent-sequence.ts +212 -0
  234. package/src/scripts/multi-agent-test.ts +186 -0
  235. package/src/scripts/search.ts +4 -12
  236. package/src/scripts/simple.ts +25 -10
  237. package/src/scripts/tools.ts +48 -18
  238. package/src/specs/anthropic.simple.test.ts +150 -34
  239. package/src/specs/azure.simple.test.ts +325 -0
  240. package/src/specs/openai.simple.test.ts +140 -33
  241. package/src/specs/openrouter.simple.test.ts +107 -0
  242. package/src/specs/prune.test.ts +4 -9
  243. package/src/specs/reasoning.test.ts +80 -44
  244. package/src/specs/token-memoization.test.ts +39 -0
  245. package/src/stream.test.ts +94 -0
  246. package/src/stream.ts +139 -60
  247. package/src/tools/ToolNode.ts +21 -7
  248. package/src/tools/handlers.ts +192 -18
  249. package/src/tools/search/anthropic.ts +51 -0
  250. package/src/tools/search/firecrawl.ts +78 -24
  251. package/src/tools/search/format.ts +10 -5
  252. package/src/tools/search/rerankers.ts +50 -62
  253. package/src/tools/search/schema.ts +63 -0
  254. package/src/tools/search/search.ts +167 -34
  255. package/src/tools/search/tool.ts +222 -46
  256. package/src/tools/search/types.ts +65 -10
  257. package/src/tools/search/utils.ts +37 -5
  258. package/src/types/graph.ts +272 -103
  259. package/src/types/llm.ts +25 -12
  260. package/src/types/run.ts +51 -13
  261. package/src/types/stream.ts +22 -1
  262. package/src/types/tools.ts +16 -10
  263. package/src/utils/events.ts +32 -0
  264. package/src/utils/llmConfig.ts +20 -8
  265. package/src/utils/title.ts +104 -30
  266. package/src/utils/tokens.ts +69 -10
@@ -1,21 +1,36 @@
1
1
  /* eslint-disable no-console */
2
2
  // src/tools/handlers.ts
3
3
  import { nanoid } from 'nanoid';
4
+ import { ToolMessage } from '@langchain/core/messages';
5
+ import type { AnthropicWebSearchResultBlockParam } from '@/llm/anthropic/types';
4
6
  import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
5
- import type { Graph } from '@/graphs';
7
+ import type { MultiAgentGraph, StandardGraph } from '@/graphs';
8
+ import type { AgentContext } from '@/agents/AgentContext';
6
9
  import type * as t from '@/types';
7
- import { StepTypes, ContentTypes, ToolCallTypes } from '@/common';
10
+ import {
11
+ ToolCallTypes,
12
+ ContentTypes,
13
+ GraphEvents,
14
+ StepTypes,
15
+ Providers,
16
+ Constants,
17
+ } from '@/common';
18
+ import {
19
+ coerceAnthropicSearchResults,
20
+ isAnthropicWebSearchResult,
21
+ } from '@/tools/search/anthropic';
22
+ import { formatResultsForLLM } from '@/tools/search/format';
8
23
  import { getMessageId } from '@/messages';
9
24
 
10
- export function handleToolCallChunks({
25
+ export async function handleToolCallChunks({
11
26
  graph,
12
27
  stepKey,
13
28
  toolCallChunks,
14
29
  }: {
15
- graph: Graph;
30
+ graph: StandardGraph | MultiAgentGraph;
16
31
  stepKey: string;
17
32
  toolCallChunks: ToolCallChunk[];
18
- }): void {
33
+ }): Promise<void> {
19
34
  let prevStepId: string;
20
35
  let prevRunStep: t.RunStep | undefined;
21
36
  try {
@@ -24,7 +39,7 @@ export function handleToolCallChunks({
24
39
  } catch {
25
40
  /** Edge Case: If no previous step exists, create a new message creation step */
26
41
  const message_id = getMessageId(stepKey, graph, true) ?? '';
27
- prevStepId = graph.dispatchRunStep(stepKey, {
42
+ prevStepId = await graph.dispatchRunStep(stepKey, {
28
43
  type: StepTypes.MESSAGE_CREATION,
29
44
  message_creation: {
30
45
  message_id,
@@ -67,7 +82,7 @@ export function handleToolCallChunks({
67
82
  prevRunStep?.type === StepTypes.MESSAGE_CREATION &&
68
83
  graph.messageStepHasToolCalls.has(prevStepId);
69
84
  if (!alreadyDispatched && tool_calls?.length === toolCallChunks.length) {
70
- graph.dispatchMessageDelta(prevStepId, {
85
+ await graph.dispatchMessageDelta(prevStepId, {
71
86
  content: [
72
87
  {
73
88
  type: ContentTypes.TEXT,
@@ -77,22 +92,22 @@ export function handleToolCallChunks({
77
92
  ],
78
93
  });
79
94
  graph.messageStepHasToolCalls.set(prevStepId, true);
80
- stepId = graph.dispatchRunStep(stepKey, {
95
+ stepId = await graph.dispatchRunStep(stepKey, {
81
96
  type: StepTypes.TOOL_CALLS,
82
97
  tool_calls,
83
98
  });
84
99
  }
85
- graph.dispatchRunStepDelta(stepId, {
100
+ await graph.dispatchRunStepDelta(stepId, {
86
101
  type: StepTypes.TOOL_CALLS,
87
102
  tool_calls: toolCallChunks,
88
103
  });
89
104
  }
90
105
 
91
- export const handleToolCalls = (
106
+ export const handleToolCalls = async (
92
107
  toolCalls?: ToolCall[],
93
108
  metadata?: Record<string, unknown>,
94
- graph?: Graph
95
- ): void => {
109
+ graph?: StandardGraph | MultiAgentGraph
110
+ ): Promise<void> => {
96
111
  if (!graph || !metadata) {
97
112
  console.warn(`Graph or metadata not found in ${event} event`);
98
113
  return;
@@ -124,8 +139,10 @@ export const handleToolCalls = (
124
139
  // no previous step
125
140
  }
126
141
 
127
- const dispatchToolCallIds = (lastMessageStepId: string): void => {
128
- graph.dispatchMessageDelta(lastMessageStepId, {
142
+ const dispatchToolCallIds = async (
143
+ lastMessageStepId: string
144
+ ): Promise<void> => {
145
+ await graph.dispatchMessageDelta(lastMessageStepId, {
129
146
  content: [
130
147
  {
131
148
  type: 'text',
@@ -141,7 +158,7 @@ export const handleToolCalls = (
141
158
  prevRunStep &&
142
159
  prevRunStep.type === StepTypes.MESSAGE_CREATION
143
160
  ) {
144
- dispatchToolCallIds(prevStepId);
161
+ await dispatchToolCallIds(prevStepId);
145
162
  graph.messageStepHasToolCalls.set(prevStepId, true);
146
163
  /* If the previous step doesn't exist or is not a message creation */
147
164
  } else if (
@@ -149,19 +166,176 @@ export const handleToolCalls = (
149
166
  prevRunStep.type !== StepTypes.MESSAGE_CREATION
150
167
  ) {
151
168
  const messageId = getMessageId(stepKey, graph, true) ?? '';
152
- const stepId = graph.dispatchRunStep(stepKey, {
169
+ const stepId = await graph.dispatchRunStep(stepKey, {
153
170
  type: StepTypes.MESSAGE_CREATION,
154
171
  message_creation: {
155
172
  message_id: messageId,
156
173
  },
157
174
  });
158
- dispatchToolCallIds(stepId);
175
+ await dispatchToolCallIds(stepId);
159
176
  graph.messageStepHasToolCalls.set(prevStepId, true);
160
177
  }
161
178
 
162
- graph.dispatchRunStep(stepKey, {
179
+ await graph.dispatchRunStep(stepKey, {
163
180
  type: StepTypes.TOOL_CALLS,
164
181
  tool_calls: [tool_call],
165
182
  });
166
183
  }
167
184
  };
185
+
186
+ export const toolResultTypes = new Set([
187
+ // 'tool_use',
188
+ // 'server_tool_use',
189
+ // 'input_json_delta',
190
+ 'tool_result',
191
+ 'web_search_result',
192
+ 'web_search_tool_result',
193
+ ]);
194
+
195
+ /**
196
+ * Handles the result of a server tool call; in other words, a provider's built-in tool.
197
+ * As of 2025-07-06, only Anthropic handles server tool calls with this pattern.
198
+ */
199
+ export async function handleServerToolResult({
200
+ graph,
201
+ content,
202
+ metadata,
203
+ agentContext,
204
+ }: {
205
+ graph: StandardGraph | MultiAgentGraph;
206
+ content?: string | t.MessageContentComplex[];
207
+ metadata?: Record<string, unknown>;
208
+ agentContext?: AgentContext;
209
+ }): Promise<boolean> {
210
+ let skipHandling = false;
211
+ if (agentContext?.provider !== Providers.ANTHROPIC) {
212
+ return skipHandling;
213
+ }
214
+ if (
215
+ typeof content === 'string' ||
216
+ content == null ||
217
+ content.length === 0 ||
218
+ (content.length === 1 &&
219
+ (content[0] as t.ToolResultContent).tool_use_id == null)
220
+ ) {
221
+ return skipHandling;
222
+ }
223
+
224
+ for (const contentPart of content) {
225
+ const toolUseId = (contentPart as t.ToolResultContent).tool_use_id;
226
+ if (toolUseId == null || toolUseId === '') {
227
+ continue;
228
+ }
229
+ const stepId = graph.toolCallStepIds.get(toolUseId);
230
+ if (stepId == null || stepId === '') {
231
+ console.warn(
232
+ `Tool use ID ${toolUseId} not found in graph, cannot dispatch tool result.`
233
+ );
234
+ continue;
235
+ }
236
+ const runStep = graph.getRunStep(stepId);
237
+ if (!runStep) {
238
+ console.warn(
239
+ `Run step for ${stepId} does not exist, cannot dispatch tool result.`
240
+ );
241
+ continue;
242
+ } else if (runStep.type !== StepTypes.TOOL_CALLS) {
243
+ console.warn(
244
+ `Run step for ${stepId} is not a tool call step, cannot dispatch tool result.`
245
+ );
246
+ continue;
247
+ }
248
+
249
+ const toolCall =
250
+ runStep.stepDetails.type === StepTypes.TOOL_CALLS
251
+ ? (runStep.stepDetails.tool_calls?.find(
252
+ (toolCall) => toolCall.id === toolUseId
253
+ ) as ToolCall)
254
+ : undefined;
255
+
256
+ if (!toolCall) {
257
+ continue;
258
+ }
259
+
260
+ if (
261
+ contentPart.type === 'web_search_result' ||
262
+ contentPart.type === 'web_search_tool_result'
263
+ ) {
264
+ await handleAnthropicSearchResults({
265
+ contentPart: contentPart as t.ToolResultContent,
266
+ toolCall,
267
+ metadata,
268
+ graph,
269
+ });
270
+ }
271
+
272
+ if (!skipHandling) {
273
+ skipHandling = true;
274
+ }
275
+ }
276
+
277
+ return skipHandling;
278
+ }
279
+
280
+ async function handleAnthropicSearchResults({
281
+ contentPart,
282
+ toolCall,
283
+ metadata,
284
+ graph,
285
+ }: {
286
+ contentPart: t.ToolResultContent;
287
+ toolCall: Partial<ToolCall>;
288
+ metadata?: Record<string, unknown>;
289
+ graph: StandardGraph | MultiAgentGraph;
290
+ }): Promise<void> {
291
+ if (!Array.isArray(contentPart.content)) {
292
+ console.warn(
293
+ `Expected content to be an array, got ${typeof contentPart.content}`
294
+ );
295
+ return;
296
+ }
297
+
298
+ if (!isAnthropicWebSearchResult(contentPart.content[0])) {
299
+ console.warn(
300
+ `Expected content to be an Anthropic web search result, got ${JSON.stringify(
301
+ contentPart.content
302
+ )}`
303
+ );
304
+ return;
305
+ }
306
+
307
+ const turn = graph.invokedToolIds?.size ?? 0;
308
+ const searchResultData = coerceAnthropicSearchResults({
309
+ turn,
310
+ results: contentPart.content as AnthropicWebSearchResultBlockParam[],
311
+ });
312
+
313
+ const name = toolCall.name;
314
+ const input = toolCall.args ?? {};
315
+ const artifact = {
316
+ [Constants.WEB_SEARCH]: searchResultData,
317
+ };
318
+ const { output: formattedOutput } = formatResultsForLLM(
319
+ turn,
320
+ searchResultData
321
+ );
322
+ const output = new ToolMessage({
323
+ name,
324
+ artifact,
325
+ content: formattedOutput,
326
+ tool_call_id: toolCall.id!,
327
+ });
328
+ const toolEndData: t.ToolEndData = {
329
+ input,
330
+ output,
331
+ };
332
+ await graph.handlerRegistry
333
+ ?.getHandler(GraphEvents.TOOL_END)
334
+ ?.handle(GraphEvents.TOOL_END, toolEndData, metadata, graph);
335
+
336
+ if (graph.invokedToolIds == null) {
337
+ graph.invokedToolIds = new Set<string>();
338
+ }
339
+
340
+ graph.invokedToolIds.add(toolCall.id!);
341
+ }
@@ -0,0 +1,51 @@
1
+ import type {
2
+ AnthropicTextBlockParam,
3
+ AnthropicWebSearchResultBlockParam,
4
+ } from '@/llm/anthropic/types';
5
+ import type { SearchResultData, ProcessedOrganic } from './types';
6
+ import { getAttribution } from './utils';
7
+
8
+ /**
9
+ * Coerces Anthropic web search results to the SearchResultData format
10
+ * @param results - Array of Anthropic web search results
11
+ * @param turn - The turn number to associate with these results
12
+ * @returns SearchResultData with minimal ProcessedOrganic items
13
+ */
14
+ export function coerceAnthropicSearchResults({
15
+ results,
16
+ turn = 0,
17
+ }: {
18
+ results: (AnthropicTextBlockParam | AnthropicWebSearchResultBlockParam)[];
19
+ turn?: number;
20
+ }): SearchResultData {
21
+ const organic: ProcessedOrganic[] = results
22
+ .filter((result) => result.type === 'web_search_result')
23
+ .map((result, index) => ({
24
+ link: result.url,
25
+ position: index + 1,
26
+ title: result.title,
27
+ date: result.page_age ?? undefined,
28
+ attribution: getAttribution(result.url),
29
+ }));
30
+
31
+ return {
32
+ turn,
33
+ organic,
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Helper function to check if an object is an Anthropic web search result
39
+ */
40
+ export function isAnthropicWebSearchResult(
41
+ obj: unknown
42
+ ): obj is AnthropicWebSearchResultBlockParam {
43
+ return (
44
+ typeof obj === 'object' &&
45
+ obj !== null &&
46
+ 'type' in obj &&
47
+ obj.type === 'web_search_result' &&
48
+ 'url' in obj &&
49
+ typeof (obj as Record<string, unknown>).url === 'string'
50
+ );
51
+ }
@@ -1,7 +1,7 @@
1
- /* eslint-disable no-console */
2
1
  import axios from 'axios';
3
2
  import { processContent } from './content';
4
3
  import type * as t from './types';
4
+ import { createDefaultLogger } from './utils';
5
5
 
6
6
  /**
7
7
  * Firecrawl scraper implementation
@@ -12,6 +12,22 @@ export class FirecrawlScraper {
12
12
  private apiUrl: string;
13
13
  private defaultFormats: string[];
14
14
  private timeout: number;
15
+ private logger: t.Logger;
16
+ private includeTags?: string[];
17
+ private excludeTags?: string[];
18
+ private waitFor?: number;
19
+ private maxAge?: number;
20
+ private mobile?: boolean;
21
+ private skipTlsVerification?: boolean;
22
+ private blockAds?: boolean;
23
+ private removeBase64Images?: boolean;
24
+ private parsePDF?: boolean;
25
+ private storeInCache?: boolean;
26
+ private zeroDataRetention?: boolean;
27
+ private headers?: Record<string, string>;
28
+ private location?: { country?: string; languages?: string[] };
29
+ private onlyMainContent?: boolean;
30
+ private changeTrackingOptions?: object;
15
31
 
16
32
  constructor(config: t.FirecrawlScraperConfig = {}) {
17
33
  this.apiKey = config.apiKey ?? process.env.FIRECRAWL_API_KEY ?? '';
@@ -22,14 +38,34 @@ export class FirecrawlScraper {
22
38
  'https://api.firecrawl.dev';
23
39
  this.apiUrl = `${baseUrl.replace(/\/+$/, '')}/v1/scrape`;
24
40
 
25
- this.defaultFormats = config.formats ?? ['markdown', 'html'];
26
- this.timeout = config.timeout ?? 15000;
41
+ this.defaultFormats = config.formats ?? ['markdown', 'rawHtml'];
42
+ this.timeout = config.timeout ?? 7500;
43
+
44
+ this.logger = config.logger || createDefaultLogger();
45
+
46
+ this.includeTags = config.includeTags;
47
+ this.excludeTags = config.excludeTags;
48
+ this.waitFor = config.waitFor;
49
+ this.maxAge = config.maxAge;
50
+ this.mobile = config.mobile;
51
+ this.skipTlsVerification = config.skipTlsVerification;
52
+ this.blockAds = config.blockAds;
53
+ this.removeBase64Images = config.removeBase64Images;
54
+ this.parsePDF = config.parsePDF;
55
+ this.storeInCache = config.storeInCache;
56
+ this.zeroDataRetention = config.zeroDataRetention;
57
+ this.headers = config.headers;
58
+ this.location = config.location;
59
+ this.onlyMainContent = config.onlyMainContent;
60
+ this.changeTrackingOptions = config.changeTrackingOptions;
27
61
 
28
62
  if (!this.apiKey) {
29
- console.warn('FIRECRAWL_API_KEY is not set. Scraping will not work.');
63
+ this.logger.warn('FIRECRAWL_API_KEY is not set. Scraping will not work.');
30
64
  }
31
65
 
32
- console.log(`Firecrawl scraper initialized with API URL: ${this.apiUrl}`);
66
+ this.logger.debug(
67
+ `Firecrawl scraper initialized with API URL: ${this.apiUrl}`
68
+ );
33
69
  }
34
70
 
35
71
  /**
@@ -53,25 +89,36 @@ export class FirecrawlScraper {
53
89
  }
54
90
 
55
91
  try {
56
- const response = await axios.post(
57
- this.apiUrl,
58
- {
59
- url,
60
- formats: options.formats || this.defaultFormats,
61
- includeTags: options.includeTags,
62
- excludeTags: options.excludeTags,
63
- headers: options.headers,
64
- waitFor: options.waitFor,
65
- timeout: options.timeout ?? this.timeout,
92
+ const payload = omitUndefined({
93
+ url,
94
+ formats: options.formats ?? this.defaultFormats,
95
+ includeTags: options.includeTags ?? this.includeTags,
96
+ excludeTags: options.excludeTags ?? this.excludeTags,
97
+ headers: options.headers ?? this.headers,
98
+ waitFor: options.waitFor ?? this.waitFor,
99
+ timeout: options.timeout ?? this.timeout,
100
+ onlyMainContent: options.onlyMainContent ?? this.onlyMainContent,
101
+ maxAge: options.maxAge ?? this.maxAge,
102
+ mobile: options.mobile ?? this.mobile,
103
+ skipTlsVerification:
104
+ options.skipTlsVerification ?? this.skipTlsVerification,
105
+ parsePDF: options.parsePDF ?? this.parsePDF,
106
+ location: options.location ?? this.location,
107
+ removeBase64Images:
108
+ options.removeBase64Images ?? this.removeBase64Images,
109
+ blockAds: options.blockAds ?? this.blockAds,
110
+ storeInCache: options.storeInCache ?? this.storeInCache,
111
+ zeroDataRetention: options.zeroDataRetention ?? this.zeroDataRetention,
112
+ changeTrackingOptions:
113
+ options.changeTrackingOptions ?? this.changeTrackingOptions,
114
+ });
115
+ const response = await axios.post(this.apiUrl, payload, {
116
+ headers: {
117
+ 'Content-Type': 'application/json',
118
+ Authorization: `Bearer ${this.apiKey}`,
66
119
  },
67
- {
68
- headers: {
69
- 'Content-Type': 'application/json',
70
- Authorization: `Bearer ${this.apiKey}`,
71
- },
72
- timeout: this.timeout,
73
- }
74
- );
120
+ timeout: this.timeout,
121
+ });
75
122
 
76
123
  return [url, response.data];
77
124
  } catch (error) {
@@ -107,7 +154,7 @@ export class FirecrawlScraper {
107
154
  );
108
155
  return [markdown, rest];
109
156
  } catch (error) {
110
- console.error('Error processing content:', error);
157
+ this.logger.error('Error processing content:', error);
111
158
  return [response.data.markdown, undefined];
112
159
  }
113
160
  } else if (response.data.markdown != null) {
@@ -151,3 +198,10 @@ export const createFirecrawlScraper = (
151
198
  ): FirecrawlScraper => {
152
199
  return new FirecrawlScraper(config);
153
200
  };
201
+
202
+ // Helper function to clean up payload for firecrawl
203
+ function omitUndefined<T extends object>(obj: T): Partial<T> {
204
+ return Object.fromEntries(
205
+ Object.entries(obj).filter(([, v]) => v !== undefined)
206
+ ) as Partial<T>;
207
+ }
@@ -1,5 +1,5 @@
1
1
  import type * as t from './types';
2
- import { getDomainName } from './utils';
2
+ import { getDomainName, fileExtRegex } from './utils';
3
3
 
4
4
  function addHighlightSection(): string[] {
5
5
  return ['\n## Highlights', ''];
@@ -62,6 +62,15 @@ function formatSource(
62
62
 
63
63
  for (let j = 0; j < h.references.length; j++) {
64
64
  const ref = h.references[j];
65
+ if (ref.reference.originalUrl.includes('mailto:')) {
66
+ continue;
67
+ }
68
+ if (ref.type !== 'link') {
69
+ continue;
70
+ }
71
+ if (fileExtRegex.test(ref.reference.originalUrl)) {
72
+ continue;
73
+ }
65
74
  references.push({
66
75
  type: ref.type,
67
76
  link: ref.reference.originalUrl,
@@ -72,10 +81,6 @@ function formatSource(
72
81
  ).split('\n')[0],
73
82
  });
74
83
 
75
- if (ref.type !== 'link') {
76
- continue;
77
- }
78
-
79
84
  if (!hasHeader) {
80
85
  refLines.push('Core References:');
81
86
  hasHeader = true;