@librechat/agents 2.4.30 → 2.4.33

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 (124) hide show
  1. package/dist/cjs/common/enum.cjs +1 -0
  2. package/dist/cjs/common/enum.cjs.map +1 -1
  3. package/dist/cjs/events.cjs +3 -3
  4. package/dist/cjs/events.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +2 -1
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/main.cjs +7 -2
  8. package/dist/cjs/main.cjs.map +1 -1
  9. package/dist/cjs/messages/ids.cjs +23 -0
  10. package/dist/cjs/messages/ids.cjs.map +1 -0
  11. package/dist/cjs/splitStream.cjs +2 -1
  12. package/dist/cjs/splitStream.cjs.map +1 -1
  13. package/dist/cjs/stream.cjs +87 -154
  14. package/dist/cjs/stream.cjs.map +1 -1
  15. package/dist/cjs/tools/ToolNode.cjs +14 -3
  16. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  17. package/dist/cjs/tools/handlers.cjs +144 -0
  18. package/dist/cjs/tools/handlers.cjs.map +1 -0
  19. package/dist/cjs/tools/search/content.cjs +140 -0
  20. package/dist/cjs/tools/search/content.cjs.map +1 -0
  21. package/dist/cjs/tools/search/firecrawl.cjs +131 -0
  22. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -0
  23. package/dist/cjs/tools/search/format.cjs +203 -0
  24. package/dist/cjs/tools/search/format.cjs.map +1 -0
  25. package/dist/cjs/tools/search/highlights.cjs +245 -0
  26. package/dist/cjs/tools/search/highlights.cjs.map +1 -0
  27. package/dist/cjs/tools/search/rerankers.cjs +194 -0
  28. package/dist/cjs/tools/search/rerankers.cjs.map +1 -0
  29. package/dist/cjs/tools/search/schema.cjs +70 -0
  30. package/dist/cjs/tools/search/schema.cjs.map +1 -0
  31. package/dist/cjs/tools/search/search.cjs +491 -0
  32. package/dist/cjs/tools/search/search.cjs.map +1 -0
  33. package/dist/cjs/tools/search/tool.cjs +292 -0
  34. package/dist/cjs/tools/search/tool.cjs.map +1 -0
  35. package/dist/cjs/tools/search/utils.cjs +66 -0
  36. package/dist/cjs/tools/search/utils.cjs.map +1 -0
  37. package/dist/esm/common/enum.mjs +1 -0
  38. package/dist/esm/common/enum.mjs.map +1 -1
  39. package/dist/esm/events.mjs +1 -1
  40. package/dist/esm/events.mjs.map +1 -1
  41. package/dist/esm/graphs/Graph.mjs +2 -1
  42. package/dist/esm/graphs/Graph.mjs.map +1 -1
  43. package/dist/esm/main.mjs +4 -1
  44. package/dist/esm/main.mjs.map +1 -1
  45. package/dist/esm/messages/ids.mjs +21 -0
  46. package/dist/esm/messages/ids.mjs.map +1 -0
  47. package/dist/esm/splitStream.mjs +2 -1
  48. package/dist/esm/splitStream.mjs.map +1 -1
  49. package/dist/esm/stream.mjs +87 -152
  50. package/dist/esm/stream.mjs.map +1 -1
  51. package/dist/esm/tools/ToolNode.mjs +14 -3
  52. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  53. package/dist/esm/tools/handlers.mjs +141 -0
  54. package/dist/esm/tools/handlers.mjs.map +1 -0
  55. package/dist/esm/tools/search/content.mjs +119 -0
  56. package/dist/esm/tools/search/content.mjs.map +1 -0
  57. package/dist/esm/tools/search/firecrawl.mjs +128 -0
  58. package/dist/esm/tools/search/firecrawl.mjs.map +1 -0
  59. package/dist/esm/tools/search/format.mjs +201 -0
  60. package/dist/esm/tools/search/format.mjs.map +1 -0
  61. package/dist/esm/tools/search/highlights.mjs +243 -0
  62. package/dist/esm/tools/search/highlights.mjs.map +1 -0
  63. package/dist/esm/tools/search/rerankers.mjs +188 -0
  64. package/dist/esm/tools/search/rerankers.mjs.map +1 -0
  65. package/dist/esm/tools/search/schema.mjs +61 -0
  66. package/dist/esm/tools/search/schema.mjs.map +1 -0
  67. package/dist/esm/tools/search/search.mjs +488 -0
  68. package/dist/esm/tools/search/search.mjs.map +1 -0
  69. package/dist/esm/tools/search/tool.mjs +290 -0
  70. package/dist/esm/tools/search/tool.mjs.map +1 -0
  71. package/dist/esm/tools/search/utils.mjs +61 -0
  72. package/dist/esm/tools/search/utils.mjs.map +1 -0
  73. package/dist/types/common/enum.d.ts +1 -0
  74. package/dist/types/graphs/Graph.d.ts +1 -1
  75. package/dist/types/index.d.ts +2 -0
  76. package/dist/types/messages/ids.d.ts +3 -0
  77. package/dist/types/messages/index.d.ts +1 -0
  78. package/dist/types/scripts/search.d.ts +1 -0
  79. package/dist/types/stream.d.ts +0 -8
  80. package/dist/types/tools/ToolNode.d.ts +6 -0
  81. package/dist/types/tools/example.d.ts +23 -3
  82. package/dist/types/tools/handlers.d.ts +8 -0
  83. package/dist/types/tools/search/content.d.ts +4 -0
  84. package/dist/types/tools/search/firecrawl.d.ts +38 -0
  85. package/dist/types/tools/search/format.d.ts +5 -0
  86. package/dist/types/tools/search/highlights.d.ts +13 -0
  87. package/dist/types/tools/search/index.d.ts +2 -0
  88. package/dist/types/tools/search/rerankers.d.ts +36 -0
  89. package/dist/types/tools/search/schema.d.ts +16 -0
  90. package/dist/types/tools/search/search.d.ts +9 -0
  91. package/dist/types/tools/search/test.d.ts +1 -0
  92. package/dist/types/tools/search/tool.d.ts +33 -0
  93. package/dist/types/tools/search/types.d.ts +540 -0
  94. package/dist/types/tools/search/utils.d.ts +10 -0
  95. package/package.json +10 -7
  96. package/src/common/enum.ts +1 -0
  97. package/src/events.ts +49 -15
  98. package/src/graphs/Graph.ts +6 -2
  99. package/src/index.ts +2 -0
  100. package/src/messages/ids.ts +26 -0
  101. package/src/messages/index.ts +1 -0
  102. package/src/scripts/search.ts +146 -0
  103. package/src/splitStream.test.ts +132 -71
  104. package/src/splitStream.ts +2 -1
  105. package/src/stream.ts +94 -183
  106. package/src/tools/ToolNode.ts +37 -14
  107. package/src/tools/handlers.ts +167 -0
  108. package/src/tools/search/content.test.ts +173 -0
  109. package/src/tools/search/content.ts +147 -0
  110. package/src/tools/search/firecrawl.ts +158 -0
  111. package/src/tools/search/format.ts +252 -0
  112. package/src/tools/search/highlights.ts +320 -0
  113. package/src/tools/search/index.ts +2 -0
  114. package/src/tools/search/output.md +2775 -0
  115. package/src/tools/search/rerankers.ts +269 -0
  116. package/src/tools/search/schema.ts +63 -0
  117. package/src/tools/search/search.ts +680 -0
  118. package/src/tools/search/test.html +884 -0
  119. package/src/tools/search/test.md +643 -0
  120. package/src/tools/search/test.ts +159 -0
  121. package/src/tools/search/tool.ts +427 -0
  122. package/src/tools/search/types.ts +621 -0
  123. package/src/tools/search/utils.ts +79 -0
  124. package/src/utils/llmConfig.ts +1 -1
@@ -0,0 +1,290 @@
1
+ import { z } from 'zod';
2
+ import { tool } from '@langchain/core/tools';
3
+ import { newsSchema, videosSchema, imagesSchema, dateSchema, querySchema, countrySchema } from './schema.mjs';
4
+ import { createSearchAPI, createSourceProcessor } from './search.mjs';
5
+ import { createFirecrawlScraper } from './firecrawl.mjs';
6
+ import { expandHighlights } from './highlights.mjs';
7
+ import { formatResultsForLLM } from './format.mjs';
8
+ import { createDefaultLogger } from './utils.mjs';
9
+ import { createReranker } from './rerankers.mjs';
10
+ import { Constants } from '../../common/enum.mjs';
11
+
12
+ /**
13
+ * Executes parallel searches and merges the results
14
+ */
15
+ async function executeParallelSearches({ searchAPI, query, date, country, safeSearch, images, videos, news, logger, }) {
16
+ // Prepare all search tasks to run in parallel
17
+ const searchTasks = [
18
+ // Main search
19
+ searchAPI.getSources({
20
+ query,
21
+ date,
22
+ country,
23
+ safeSearch,
24
+ }),
25
+ ];
26
+ if (images) {
27
+ searchTasks.push(searchAPI
28
+ .getSources({
29
+ query,
30
+ date,
31
+ country,
32
+ safeSearch,
33
+ type: 'images',
34
+ })
35
+ .catch((error) => {
36
+ logger.error('Error fetching images:', error);
37
+ return {
38
+ success: false,
39
+ error: `Images search failed: ${error instanceof Error ? error.message : String(error)}`,
40
+ };
41
+ }));
42
+ }
43
+ if (videos) {
44
+ searchTasks.push(searchAPI
45
+ .getSources({
46
+ query,
47
+ date,
48
+ country,
49
+ safeSearch,
50
+ type: 'videos',
51
+ })
52
+ .catch((error) => {
53
+ logger.error('Error fetching videos:', error);
54
+ return {
55
+ success: false,
56
+ error: `Videos search failed: ${error instanceof Error ? error.message : String(error)}`,
57
+ };
58
+ }));
59
+ }
60
+ if (news) {
61
+ searchTasks.push(searchAPI
62
+ .getSources({
63
+ query,
64
+ date,
65
+ country,
66
+ safeSearch,
67
+ type: 'news',
68
+ })
69
+ .catch((error) => {
70
+ logger.error('Error fetching news:', error);
71
+ return {
72
+ success: false,
73
+ error: `News search failed: ${error instanceof Error ? error.message : String(error)}`,
74
+ };
75
+ }));
76
+ }
77
+ // Run all searches in parallel
78
+ const results = await Promise.all(searchTasks);
79
+ // Get the main search result (first result)
80
+ const mainResult = results[0];
81
+ if (!mainResult.success) {
82
+ throw new Error(mainResult.error ?? 'Search failed');
83
+ }
84
+ // Merge additional results with the main results
85
+ const mergedResults = { ...mainResult.data };
86
+ // Convert existing news to topStories if present
87
+ if (mergedResults.news !== undefined && mergedResults.news.length > 0) {
88
+ const existingNewsAsTopStories = mergedResults.news
89
+ .filter((newsItem) => newsItem.link !== undefined && newsItem.link !== '')
90
+ .map((newsItem) => ({
91
+ title: newsItem.title ?? '',
92
+ link: newsItem.link ?? '',
93
+ source: newsItem.source ?? '',
94
+ date: newsItem.date ?? '',
95
+ imageUrl: newsItem.imageUrl ?? '',
96
+ processed: false,
97
+ }));
98
+ mergedResults.topStories = [
99
+ ...(mergedResults.topStories ?? []),
100
+ ...existingNewsAsTopStories,
101
+ ];
102
+ delete mergedResults.news;
103
+ }
104
+ results.slice(1).forEach((result) => {
105
+ if (result.success && result.data !== undefined) {
106
+ if (result.data.images !== undefined && result.data.images.length > 0) {
107
+ mergedResults.images = [
108
+ ...(mergedResults.images ?? []),
109
+ ...result.data.images,
110
+ ];
111
+ }
112
+ if (result.data.videos !== undefined && result.data.videos.length > 0) {
113
+ mergedResults.videos = [
114
+ ...(mergedResults.videos ?? []),
115
+ ...result.data.videos,
116
+ ];
117
+ }
118
+ if (result.data.news !== undefined && result.data.news.length > 0) {
119
+ const newsAsTopStories = result.data.news.map((newsItem) => ({
120
+ ...newsItem,
121
+ link: newsItem.link ?? '',
122
+ }));
123
+ mergedResults.topStories = [
124
+ ...(mergedResults.topStories ?? []),
125
+ ...newsAsTopStories,
126
+ ];
127
+ }
128
+ }
129
+ });
130
+ return { success: true, data: mergedResults };
131
+ }
132
+ function createSearchProcessor({ searchAPI, safeSearch, sourceProcessor, onGetHighlights, logger, }) {
133
+ return async function ({ query, date, country, proMode = true, maxSources = 5, onSearchResults, images = false, videos = false, news = false, }) {
134
+ try {
135
+ // Execute parallel searches and merge results
136
+ const searchResult = await executeParallelSearches({
137
+ searchAPI,
138
+ query,
139
+ date,
140
+ country,
141
+ safeSearch,
142
+ images,
143
+ videos,
144
+ news,
145
+ logger,
146
+ });
147
+ onSearchResults?.(searchResult);
148
+ const processedSources = await sourceProcessor.processSources({
149
+ query,
150
+ news,
151
+ result: searchResult,
152
+ proMode,
153
+ onGetHighlights,
154
+ numElements: maxSources,
155
+ });
156
+ return expandHighlights(processedSources);
157
+ }
158
+ catch (error) {
159
+ logger.error('Error in search:', error);
160
+ return {
161
+ organic: [],
162
+ topStories: [],
163
+ images: [],
164
+ videos: [],
165
+ news: [],
166
+ relatedSearches: [],
167
+ error: error instanceof Error ? error.message : String(error),
168
+ };
169
+ }
170
+ };
171
+ }
172
+ function createOnSearchResults({ runnableConfig, onSearchResults, }) {
173
+ return function (results) {
174
+ if (!onSearchResults) {
175
+ return;
176
+ }
177
+ onSearchResults(results, runnableConfig);
178
+ };
179
+ }
180
+ function createTool({ schema, search, onSearchResults: _onSearchResults, }) {
181
+ return tool(async (params, runnableConfig) => {
182
+ const { query, date, country: _c, images, videos, news } = params;
183
+ const country = typeof _c === 'string' && _c ? _c : undefined;
184
+ const searchResult = await search({
185
+ query,
186
+ date,
187
+ country,
188
+ images,
189
+ videos,
190
+ news,
191
+ onSearchResults: createOnSearchResults({
192
+ runnableConfig,
193
+ onSearchResults: _onSearchResults,
194
+ }),
195
+ });
196
+ const turn = runnableConfig.toolCall?.turn ?? 0;
197
+ const { output, references } = formatResultsForLLM(turn, searchResult);
198
+ const data = { turn, ...searchResult, references };
199
+ return [output, { [Constants.WEB_SEARCH]: data }];
200
+ }, {
201
+ name: Constants.WEB_SEARCH,
202
+ description: `Real-time search. Results have required citation anchors.
203
+
204
+ Note: Use ONCE per reply unless instructed otherwise.
205
+
206
+ Anchors:
207
+ - \\ue202turnXtypeY
208
+ - X = turn idx, type = 'search' | 'news' | 'image' | 'ref', Y = item idx
209
+
210
+ Special Markers:
211
+ - \\ue203...\\ue204 — highlight start/end of cited text (for Standalone or Group citations)
212
+ - \\ue200...\\ue201 — group block (e.g. \\ue200\\ue202turn0search1\\ue202turn0news2\\ue201)
213
+
214
+ **CITE EVERY NON-OBVIOUS FACT/QUOTE:**
215
+ Use anchor marker(s) immediately after the statement:
216
+ - Standalone: "Pure functions produce same output. \\ue202turn0search0"
217
+ - Standalone (multiple): "Today's News \\ue202turn0search0\\ue202turn0news0"
218
+ - Highlight: "\\ue203Highlight text.\\ue204\\ue202turn0news1"
219
+ - Group: "Sources. \\ue200\\ue202turn0search0\\ue202turn0news1\\ue201"
220
+ - Group Highlight: "\\ue203Highlight for group.\\ue204 \\ue200\\ue202turn0search0\\ue202turn0news1\\ue201"
221
+ - Image: "See photo \\ue202turn0image0."
222
+
223
+ **NEVER use markdown links, [1], or footnotes. CITE ONLY with anchors provided.**
224
+ `.trim(),
225
+ schema: schema,
226
+ responseFormat: Constants.CONTENT_AND_ARTIFACT,
227
+ });
228
+ }
229
+ /**
230
+ * Creates a search tool with a schema that dynamically includes the country field
231
+ * only when the searchProvider is 'serper'.
232
+ *
233
+ * @param config - The search tool configuration
234
+ * @returns A DynamicStructuredTool with a schema that depends on the searchProvider
235
+ */
236
+ const createSearchTool = (config = {}) => {
237
+ const { searchProvider = 'serper', serperApiKey, searxngInstanceUrl, searxngApiKey, rerankerType = 'cohere', topResults = 5, strategies = ['no_extraction'], filterContent = true, safeSearch = 1, firecrawlApiKey, firecrawlApiUrl, firecrawlFormats = ['markdown', 'html'], jinaApiKey, cohereApiKey, onSearchResults: _onSearchResults, onGetHighlights, } = config;
238
+ const logger = config.logger || createDefaultLogger();
239
+ const schemaObject = {
240
+ query: querySchema,
241
+ date: dateSchema,
242
+ images: imagesSchema,
243
+ videos: videosSchema,
244
+ news: newsSchema,
245
+ };
246
+ if (searchProvider === 'serper') {
247
+ schemaObject.country = countrySchema;
248
+ }
249
+ const toolSchema = z.object(schemaObject);
250
+ const searchAPI = createSearchAPI({
251
+ searchProvider,
252
+ serperApiKey,
253
+ searxngInstanceUrl,
254
+ searxngApiKey,
255
+ });
256
+ const firecrawlScraper = createFirecrawlScraper({
257
+ apiKey: firecrawlApiKey ?? process.env.FIRECRAWL_API_KEY,
258
+ apiUrl: firecrawlApiUrl,
259
+ formats: firecrawlFormats,
260
+ });
261
+ const selectedReranker = createReranker({
262
+ rerankerType,
263
+ jinaApiKey,
264
+ cohereApiKey,
265
+ logger,
266
+ });
267
+ if (!selectedReranker) {
268
+ logger.warn('No reranker selected. Using default ranking.');
269
+ }
270
+ const sourceProcessor = createSourceProcessor({
271
+ reranker: selectedReranker,
272
+ topResults,
273
+ logger,
274
+ }, firecrawlScraper);
275
+ const search = createSearchProcessor({
276
+ searchAPI,
277
+ safeSearch,
278
+ sourceProcessor,
279
+ onGetHighlights,
280
+ logger,
281
+ });
282
+ return createTool({
283
+ search,
284
+ schema: toolSchema,
285
+ onSearchResults: _onSearchResults,
286
+ });
287
+ };
288
+
289
+ export { createSearchTool };
290
+ //# sourceMappingURL=tool.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.mjs","sources":["../../../../src/tools/search/tool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport type { RunnableConfig } from '@langchain/core/runnables';\nimport type * as t from './types';\nimport {\n DATE_RANGE,\n querySchema,\n dateSchema,\n countrySchema,\n imagesSchema,\n videosSchema,\n newsSchema,\n} from './schema';\nimport { createSearchAPI, createSourceProcessor } from './search';\nimport { createFirecrawlScraper } from './firecrawl';\nimport { expandHighlights } from './highlights';\nimport { formatResultsForLLM } from './format';\nimport { createDefaultLogger } from './utils';\nimport { createReranker } from './rerankers';\nimport { Constants } from '@/common';\n\n/**\n * Executes parallel searches and merges the results\n */\nasync function executeParallelSearches({\n searchAPI,\n query,\n date,\n country,\n safeSearch,\n images,\n videos,\n news,\n logger,\n}: {\n searchAPI: ReturnType<typeof createSearchAPI>;\n query: string;\n date?: DATE_RANGE;\n country?: string;\n safeSearch: t.SearchToolConfig['safeSearch'];\n images: boolean;\n videos: boolean;\n news: boolean;\n logger: t.Logger;\n}): Promise<t.SearchResult> {\n // Prepare all search tasks to run in parallel\n const searchTasks: Promise<t.SearchResult>[] = [\n // Main search\n searchAPI.getSources({\n query,\n date,\n country,\n safeSearch,\n }),\n ];\n\n if (images) {\n searchTasks.push(\n searchAPI\n .getSources({\n query,\n date,\n country,\n safeSearch,\n type: 'images',\n })\n .catch((error) => {\n logger.error('Error fetching images:', error);\n return {\n success: false,\n error: `Images search failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n })\n );\n }\n if (videos) {\n searchTasks.push(\n searchAPI\n .getSources({\n query,\n date,\n country,\n safeSearch,\n type: 'videos',\n })\n .catch((error) => {\n logger.error('Error fetching videos:', error);\n return {\n success: false,\n error: `Videos search failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n })\n );\n }\n if (news) {\n searchTasks.push(\n searchAPI\n .getSources({\n query,\n date,\n country,\n safeSearch,\n type: 'news',\n })\n .catch((error) => {\n logger.error('Error fetching news:', error);\n return {\n success: false,\n error: `News search failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n })\n );\n }\n\n // Run all searches in parallel\n const results = await Promise.all(searchTasks);\n\n // Get the main search result (first result)\n const mainResult = results[0];\n if (!mainResult.success) {\n throw new Error(mainResult.error ?? 'Search failed');\n }\n\n // Merge additional results with the main results\n const mergedResults = { ...mainResult.data };\n\n // Convert existing news to topStories if present\n if (mergedResults.news !== undefined && mergedResults.news.length > 0) {\n const existingNewsAsTopStories = mergedResults.news\n .filter((newsItem) => newsItem.link !== undefined && newsItem.link !== '')\n .map((newsItem) => ({\n title: newsItem.title ?? '',\n link: newsItem.link ?? '',\n source: newsItem.source ?? '',\n date: newsItem.date ?? '',\n imageUrl: newsItem.imageUrl ?? '',\n processed: false,\n }));\n mergedResults.topStories = [\n ...(mergedResults.topStories ?? []),\n ...existingNewsAsTopStories,\n ];\n delete mergedResults.news;\n }\n\n results.slice(1).forEach((result) => {\n if (result.success && result.data !== undefined) {\n if (result.data.images !== undefined && result.data.images.length > 0) {\n mergedResults.images = [\n ...(mergedResults.images ?? []),\n ...result.data.images,\n ];\n }\n if (result.data.videos !== undefined && result.data.videos.length > 0) {\n mergedResults.videos = [\n ...(mergedResults.videos ?? []),\n ...result.data.videos,\n ];\n }\n if (result.data.news !== undefined && result.data.news.length > 0) {\n const newsAsTopStories = result.data.news.map((newsItem) => ({\n ...newsItem,\n link: newsItem.link ?? '',\n }));\n mergedResults.topStories = [\n ...(mergedResults.topStories ?? []),\n ...newsAsTopStories,\n ];\n }\n }\n });\n\n return { success: true, data: mergedResults };\n}\n\nfunction createSearchProcessor({\n searchAPI,\n safeSearch,\n sourceProcessor,\n onGetHighlights,\n logger,\n}: {\n safeSearch: t.SearchToolConfig['safeSearch'];\n searchAPI: ReturnType<typeof createSearchAPI>;\n sourceProcessor: ReturnType<typeof createSourceProcessor>;\n onGetHighlights: t.SearchToolConfig['onGetHighlights'];\n logger: t.Logger;\n}) {\n return async function ({\n query,\n date,\n country,\n proMode = true,\n maxSources = 5,\n onSearchResults,\n images = false,\n videos = false,\n news = false,\n }: {\n query: string;\n country?: string;\n date?: DATE_RANGE;\n proMode?: boolean;\n maxSources?: number;\n onSearchResults: t.SearchToolConfig['onSearchResults'];\n images?: boolean;\n videos?: boolean;\n news?: boolean;\n }): Promise<t.SearchResultData> {\n try {\n // Execute parallel searches and merge results\n const searchResult = await executeParallelSearches({\n searchAPI,\n query,\n date,\n country,\n safeSearch,\n images,\n videos,\n news,\n logger,\n });\n\n onSearchResults?.(searchResult);\n\n const processedSources = await sourceProcessor.processSources({\n query,\n news,\n result: searchResult,\n proMode,\n onGetHighlights,\n numElements: maxSources,\n });\n\n return expandHighlights(processedSources);\n } catch (error) {\n logger.error('Error in search:', error);\n return {\n organic: [],\n topStories: [],\n images: [],\n videos: [],\n news: [],\n relatedSearches: [],\n error: error instanceof Error ? error.message : String(error),\n };\n }\n };\n}\n\nfunction createOnSearchResults({\n runnableConfig,\n onSearchResults,\n}: {\n runnableConfig: RunnableConfig;\n onSearchResults: t.SearchToolConfig['onSearchResults'];\n}) {\n return function (results: t.SearchResult): void {\n if (!onSearchResults) {\n return;\n }\n onSearchResults(results, runnableConfig);\n };\n}\n\nfunction createTool({\n schema,\n search,\n onSearchResults: _onSearchResults,\n}: {\n schema: t.SearchToolSchema;\n search: ReturnType<typeof createSearchProcessor>;\n onSearchResults: t.SearchToolConfig['onSearchResults'];\n}): DynamicStructuredTool<typeof schema> {\n return tool<typeof schema>(\n async (params, runnableConfig) => {\n const { query, date, country: _c, images, videos, news } = params;\n const country = typeof _c === 'string' && _c ? _c : undefined;\n const searchResult = await search({\n query,\n date,\n country,\n images,\n videos,\n news,\n onSearchResults: createOnSearchResults({\n runnableConfig,\n onSearchResults: _onSearchResults,\n }),\n });\n const turn = runnableConfig.toolCall?.turn ?? 0;\n const { output, references } = formatResultsForLLM(turn, searchResult);\n const data: t.SearchResultData = { turn, ...searchResult, references };\n return [output, { [Constants.WEB_SEARCH]: data }];\n },\n {\n name: Constants.WEB_SEARCH,\n description: `Real-time search. Results have required citation anchors.\n\nNote: Use ONCE per reply unless instructed otherwise.\n\nAnchors:\n- \\\\ue202turnXtypeY\n- X = turn idx, type = 'search' | 'news' | 'image' | 'ref', Y = item idx\n\nSpecial Markers:\n- \\\\ue203...\\\\ue204 — highlight start/end of cited text (for Standalone or Group citations)\n- \\\\ue200...\\\\ue201 — group block (e.g. \\\\ue200\\\\ue202turn0search1\\\\ue202turn0news2\\\\ue201)\n\n**CITE EVERY NON-OBVIOUS FACT/QUOTE:**\nUse anchor marker(s) immediately after the statement:\n- Standalone: \"Pure functions produce same output. \\\\ue202turn0search0\"\n- Standalone (multiple): \"Today's News \\\\ue202turn0search0\\\\ue202turn0news0\"\n- Highlight: \"\\\\ue203Highlight text.\\\\ue204\\\\ue202turn0news1\"\n- Group: \"Sources. \\\\ue200\\\\ue202turn0search0\\\\ue202turn0news1\\\\ue201\"\n- Group Highlight: \"\\\\ue203Highlight for group.\\\\ue204 \\\\ue200\\\\ue202turn0search0\\\\ue202turn0news1\\\\ue201\"\n- Image: \"See photo \\\\ue202turn0image0.\"\n\n**NEVER use markdown links, [1], or footnotes. CITE ONLY with anchors provided.**\n`.trim(),\n schema: schema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\n/**\n * Creates a search tool with a schema that dynamically includes the country field\n * only when the searchProvider is 'serper'.\n *\n * @param config - The search tool configuration\n * @returns A DynamicStructuredTool with a schema that depends on the searchProvider\n */\nexport const createSearchTool = (\n config: t.SearchToolConfig = {}\n): DynamicStructuredTool<typeof toolSchema> => {\n const {\n searchProvider = 'serper',\n serperApiKey,\n searxngInstanceUrl,\n searxngApiKey,\n rerankerType = 'cohere',\n topResults = 5,\n strategies = ['no_extraction'],\n filterContent = true,\n safeSearch = 1,\n firecrawlApiKey,\n firecrawlApiUrl,\n firecrawlFormats = ['markdown', 'html'],\n jinaApiKey,\n cohereApiKey,\n onSearchResults: _onSearchResults,\n onGetHighlights,\n } = config;\n\n const logger = config.logger || createDefaultLogger();\n\n const schemaObject: {\n query: z.ZodString;\n date: z.ZodOptional<z.ZodNativeEnum<typeof DATE_RANGE>>;\n country?: z.ZodOptional<z.ZodString>;\n images: z.ZodOptional<z.ZodBoolean>;\n videos: z.ZodOptional<z.ZodBoolean>;\n news: z.ZodOptional<z.ZodBoolean>;\n } = {\n query: querySchema,\n date: dateSchema,\n images: imagesSchema,\n videos: videosSchema,\n news: newsSchema,\n };\n\n if (searchProvider === 'serper') {\n schemaObject.country = countrySchema;\n }\n\n const toolSchema = z.object(schemaObject);\n\n const searchAPI = createSearchAPI({\n searchProvider,\n serperApiKey,\n searxngInstanceUrl,\n searxngApiKey,\n });\n\n const firecrawlScraper = createFirecrawlScraper({\n apiKey: firecrawlApiKey ?? process.env.FIRECRAWL_API_KEY,\n apiUrl: firecrawlApiUrl,\n formats: firecrawlFormats,\n });\n\n const selectedReranker = createReranker({\n rerankerType,\n jinaApiKey,\n cohereApiKey,\n logger,\n });\n\n if (!selectedReranker) {\n logger.warn('No reranker selected. Using default ranking.');\n }\n\n const sourceProcessor = createSourceProcessor(\n {\n reranker: selectedReranker,\n topResults,\n strategies,\n filterContent,\n logger,\n },\n firecrawlScraper\n );\n\n const search = createSearchProcessor({\n searchAPI,\n safeSearch,\n sourceProcessor,\n onGetHighlights,\n logger,\n });\n\n return createTool({\n search,\n schema: toolSchema,\n onSearchResults: _onSearchResults,\n });\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /* eslint-disable no-console */
2
+ /**
3
+ * Singleton instance of the default logger
4
+ */
5
+ let defaultLoggerInstance = null;
6
+ /**
7
+ * Creates a default logger that maps to console methods
8
+ * Uses a singleton pattern to avoid creating multiple instances
9
+ * @returns A default logger that implements the Logger interface
10
+ */
11
+ const createDefaultLogger = () => {
12
+ if (!defaultLoggerInstance) {
13
+ defaultLoggerInstance = {
14
+ error: console.error,
15
+ warn: console.warn,
16
+ info: console.info,
17
+ debug: console.debug,
18
+ };
19
+ }
20
+ return defaultLoggerInstance;
21
+ };
22
+ const fileExtRegex = /\.(pdf|jpe?g|png|gif|svg|webp|bmp|ico|tiff?|avif|heic|doc[xm]?|xls[xm]?|ppt[xm]?|zip|rar|mp[34]|mov|avi|wav)(?:\?.*)?$/i;
23
+ const getDomainName = (link, metadata, logger) => {
24
+ try {
25
+ const url = metadata?.sourceURL ?? metadata?.url ?? (link || '');
26
+ const domain = new URL(url).hostname.replace(/^www\./, '');
27
+ if (domain) {
28
+ return domain;
29
+ }
30
+ }
31
+ catch (e) {
32
+ // URL parsing failed
33
+ if (logger) {
34
+ logger.error('Error parsing URL:', e);
35
+ }
36
+ else {
37
+ console.error('Error parsing URL:', e);
38
+ }
39
+ }
40
+ return;
41
+ };
42
+ function getAttribution(link, metadata, logger) {
43
+ if (!metadata)
44
+ return getDomainName(link, metadata, logger);
45
+ const twitterSite = metadata['twitter:site'];
46
+ const twitterSiteFormatted = typeof twitterSite === 'string' ? twitterSite.replace(/^@/, '') : undefined;
47
+ const possibleAttributions = [
48
+ metadata.ogSiteName,
49
+ metadata['og:site_name'],
50
+ metadata.title?.split('|').pop()?.trim(),
51
+ twitterSiteFormatted,
52
+ ];
53
+ const attribution = possibleAttributions.find((attr) => attr != null && typeof attr === 'string' && attr.trim() !== '');
54
+ if (attribution != null) {
55
+ return attribution;
56
+ }
57
+ return getDomainName(link, metadata, logger);
58
+ }
59
+
60
+ export { createDefaultLogger, fileExtRegex, getAttribution, getDomainName };
61
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.mjs","sources":["../../../../src/tools/search/utils.ts"],"sourcesContent":["/* eslint-disable no-console */\n\nimport type * as t from './types';\n\n/**\n * Singleton instance of the default logger\n */\nlet defaultLoggerInstance: t.Logger | null = null;\n\n/**\n * Creates a default logger that maps to console methods\n * Uses a singleton pattern to avoid creating multiple instances\n * @returns A default logger that implements the Logger interface\n */\nexport const createDefaultLogger = (): t.Logger => {\n if (!defaultLoggerInstance) {\n defaultLoggerInstance = {\n error: console.error,\n warn: console.warn,\n info: console.info,\n debug: console.debug,\n } as t.Logger;\n }\n return defaultLoggerInstance;\n};\n\nexport const fileExtRegex =\n /\\.(pdf|jpe?g|png|gif|svg|webp|bmp|ico|tiff?|avif|heic|doc[xm]?|xls[xm]?|ppt[xm]?|zip|rar|mp[34]|mov|avi|wav)(?:\\?.*)?$/i;\n\nexport const getDomainName = (\n link: string,\n metadata?: t.ScrapeMetadata,\n logger?: t.Logger\n): string | undefined => {\n try {\n const url = metadata?.sourceURL ?? metadata?.url ?? (link || '');\n const domain = new URL(url).hostname.replace(/^www\\./, '');\n if (domain) {\n return domain;\n }\n } catch (e) {\n // URL parsing failed\n if (logger) {\n logger.error('Error parsing URL:', e);\n } else {\n console.error('Error parsing URL:', e);\n }\n }\n\n return;\n};\n\nexport function getAttribution(\n link: string,\n metadata?: t.ScrapeMetadata,\n logger?: t.Logger\n): string | undefined {\n if (!metadata) return getDomainName(link, metadata, logger);\n\n const twitterSite = metadata['twitter:site'];\n const twitterSiteFormatted =\n typeof twitterSite === 'string' ? twitterSite.replace(/^@/, '') : undefined;\n\n const possibleAttributions = [\n metadata.ogSiteName,\n metadata['og:site_name'],\n metadata.title?.split('|').pop()?.trim(),\n twitterSiteFormatted,\n ];\n\n const attribution = possibleAttributions.find(\n (attr) => attr != null && typeof attr === 'string' && attr.trim() !== ''\n );\n if (attribution != null) {\n return attribution;\n }\n\n return getDomainName(link, metadata, logger);\n}\n"],"names":[],"mappings":"AAAA;AAIA;;AAEG;AACH,IAAI,qBAAqB,GAAoB,IAAI;AAEjD;;;;AAIG;AACI,MAAM,mBAAmB,GAAG,MAAe;IAChD,IAAI,CAAC,qBAAqB,EAAE;AAC1B,QAAA,qBAAqB,GAAG;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;SACT;;AAEf,IAAA,OAAO,qBAAqB;AAC9B;AAEO,MAAM,YAAY,GACvB;AAEW,MAAA,aAAa,GAAG,CAC3B,IAAY,EACZ,QAA2B,EAC3B,MAAiB,KACK;AACtB,IAAA,IAAI;AACF,QAAA,MAAM,GAAG,GAAG,QAAQ,EAAE,SAAS,IAAI,QAAQ,EAAE,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC;AAChE,QAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;QAC1D,IAAI,MAAM,EAAE;AACV,YAAA,OAAO,MAAM;;;IAEf,OAAO,CAAC,EAAE;;QAEV,IAAI,MAAM,EAAE;AACV,YAAA,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC,CAAC;;aAChC;AACL,YAAA,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC,CAAC;;;IAI1C;AACF;SAEgB,cAAc,CAC5B,IAAY,EACZ,QAA2B,EAC3B,MAAiB,EAAA;AAEjB,IAAA,IAAI,CAAC,QAAQ;QAAE,OAAO,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC;AAE3D,IAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC;IAC5C,MAAM,oBAAoB,GACxB,OAAO,WAAW,KAAK,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,SAAS;AAE7E,IAAA,MAAM,oBAAoB,GAAG;AAC3B,QAAA,QAAQ,CAAC,UAAU;QACnB,QAAQ,CAAC,cAAc,CAAC;AACxB,QAAA,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE;QACxC,oBAAoB;KACrB;IAED,MAAM,WAAW,GAAG,oBAAoB,CAAC,IAAI,CAC3C,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CACzE;AACD,IAAA,IAAI,WAAW,IAAI,IAAI,EAAE;AACvB,QAAA,OAAO,WAAW;;IAGpB,OAAO,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC;AAC9C;;;;"}
@@ -112,6 +112,7 @@ export declare enum Callback {
112
112
  export declare enum Constants {
113
113
  OFFICIAL_CODE_BASEURL = "https://api.librechat.ai/v1",
114
114
  EXECUTE_CODE = "execute_code",
115
+ WEB_SEARCH = "web_search",
115
116
  CONTENT_AND_ARTIFACT = "content_and_artifact"
116
117
  }
117
118
  export declare enum EnvVar {
@@ -42,7 +42,7 @@ export declare abstract class Graph<T extends t.BaseGraphState = t.BaseGraphStat
42
42
  lastToken?: string;
43
43
  tokenTypeSwitch?: 'reasoning' | 'content';
44
44
  reasoningKey: 'reasoning_content' | 'reasoning';
45
- currentTokenType: ContentTypes.TEXT | ContentTypes.THINK;
45
+ currentTokenType: ContentTypes.TEXT | ContentTypes.THINK | 'think_and_text';
46
46
  messageStepHasToolCalls: Map<string, boolean>;
47
47
  messageIdsByStepKey: Map<string, string>;
48
48
  prelimMessageIdsByStepKey: Map<string, string>;
@@ -5,6 +5,8 @@ export * from './events';
5
5
  export * from './messages';
6
6
  export * from './graphs';
7
7
  export * from './tools/CodeExecutor';
8
+ export * from './tools/handlers';
9
+ export * from './tools/search';
8
10
  export * from './common';
9
11
  export * from './utils';
10
12
  export type * from './types';
@@ -0,0 +1,3 @@
1
+ import type { Graph } from '@/graphs';
2
+ import type * as t from '@/types';
3
+ export declare const getMessageId: (stepKey: string, graph: Graph<t.BaseGraphState>, returnExistingId?: boolean) => string | undefined;
@@ -1,3 +1,4 @@
1
1
  export * from './core';
2
+ export * from './ids';
2
3
  export * from './prune';
3
4
  export * from './format';
@@ -0,0 +1 @@
1
+ export {};
@@ -1,16 +1,8 @@
1
1
  import type { AIMessageChunk } from '@langchain/core/messages';
2
- import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
3
2
  import type { Graph } from '@/graphs';
4
3
  import type * as t from '@/types';
5
- export declare const getMessageId: (stepKey: string, graph: Graph<t.BaseGraphState>, returnExistingId?: boolean) => string | undefined;
6
- export declare const handleToolCalls: (toolCalls?: ToolCall[], metadata?: Record<string, unknown>, graph?: Graph) => void;
7
4
  export declare class ChatModelStreamHandler implements t.EventHandler {
8
5
  handle(event: string, data: t.StreamEventData, metadata?: Record<string, unknown>, graph?: Graph): void;
9
- handleToolCallChunks: ({ graph, stepKey, toolCallChunks, }: {
10
- graph: Graph;
11
- stepKey: string;
12
- toolCallChunks: ToolCallChunk[];
13
- }) => void;
14
6
  handleReasoning(chunk: Partial<AIMessageChunk>, graph: Graph): void;
15
7
  }
16
8
  export declare function createContentAggregator(): t.ContentAggregatorResult;
@@ -10,7 +10,13 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
10
10
  handleToolErrors: boolean;
11
11
  toolCallStepIds?: Map<string, string>;
12
12
  errorHandler?: t.ToolNodeConstructorParams['errorHandler'];
13
+ private toolUsageCount;
13
14
  constructor({ tools, toolMap, name, tags, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, }: t.ToolNodeConstructorParams);
15
+ /**
16
+ * Returns a snapshot of the current tool usage counts.
17
+ * @returns A ReadonlyMap where keys are tool names and values are their usage counts.
18
+ */
19
+ getToolUsageCounts(): ReadonlyMap<string, number>;
14
20
  protected run(input: any, config: RunnableConfig): Promise<T>;
15
21
  }
16
22
  export declare function toolsCondition(state: BaseMessage[] | typeof MessagesAnnotation.State): 'tools' | typeof END;
@@ -11,7 +11,17 @@ export declare const fetchRandomImageTool: DynamicStructuredTool<z.ZodObject<{
11
11
  input?: string | undefined;
12
12
  }, {
13
13
  input?: string | undefined;
14
- }>;
14
+ }, (string | undefined)[] | ({
15
+ type: string;
16
+ text: string;
17
+ }[] | {
18
+ content: {
19
+ type: string;
20
+ image_url: {
21
+ url: string;
22
+ };
23
+ }[];
24
+ })[]>;
15
25
  export declare const fetchRandomImageURL: DynamicStructuredTool<z.ZodObject<{
16
26
  input: z.ZodOptional<z.ZodString>;
17
27
  }, "strip", z.ZodTypeAny, {
@@ -22,7 +32,17 @@ export declare const fetchRandomImageURL: DynamicStructuredTool<z.ZodObject<{
22
32
  input?: string | undefined;
23
33
  }, {
24
34
  input?: string | undefined;
25
- }>;
35
+ }, (string | undefined)[] | ({
36
+ type: string;
37
+ text: string;
38
+ }[] | {
39
+ content: {
40
+ type: string;
41
+ image_url: {
42
+ url: string;
43
+ };
44
+ }[];
45
+ })[]>;
26
46
  export declare const chartTool: DynamicStructuredTool<z.ZodObject<{
27
47
  data: z.ZodArray<z.ZodObject<{
28
48
  label: z.ZodString;
@@ -54,5 +74,5 @@ export declare const chartTool: DynamicStructuredTool<z.ZodObject<{
54
74
  value: number;
55
75
  label: string;
56
76
  }[];
57
- }>;
77
+ }, string>;
58
78
  export declare const tavilyTool: TavilySearchResults;
@@ -0,0 +1,8 @@
1
+ import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
2
+ import type { Graph } from '@/graphs';
3
+ export declare function handleToolCallChunks({ graph, stepKey, toolCallChunks, }: {
4
+ graph: Graph;
5
+ stepKey: string;
6
+ toolCallChunks: ToolCallChunk[];
7
+ }): void;
8
+ export declare const handleToolCalls: (toolCalls?: ToolCall[], metadata?: Record<string, unknown>, graph?: Graph) => void;
@@ -0,0 +1,4 @@
1
+ import type { References } from './types';
2
+ export declare function processContent(html: string, markdown: string): {
3
+ markdown: string;
4
+ } & References;
@@ -0,0 +1,38 @@
1
+ import type * as t from './types';
2
+ /**
3
+ * Firecrawl scraper implementation
4
+ * Uses the Firecrawl API to scrape web pages
5
+ */
6
+ export declare class FirecrawlScraper {
7
+ private apiKey;
8
+ private apiUrl;
9
+ private defaultFormats;
10
+ private timeout;
11
+ private logger;
12
+ constructor(config?: t.FirecrawlScraperConfig);
13
+ /**
14
+ * Scrape a single URL
15
+ * @param url URL to scrape
16
+ * @param options Scrape options
17
+ * @returns Scrape response
18
+ */
19
+ scrapeUrl(url: string, options?: t.FirecrawlScrapeOptions): Promise<[string, t.FirecrawlScrapeResponse]>;
20
+ /**
21
+ * Extract content from scrape response
22
+ * @param response Scrape response
23
+ * @returns Extracted content or empty string if not available
24
+ */
25
+ extractContent(response: t.FirecrawlScrapeResponse): [string, undefined | t.References];
26
+ /**
27
+ * Extract metadata from scrape response
28
+ * @param response Scrape response
29
+ * @returns Metadata object
30
+ */
31
+ extractMetadata(response: t.FirecrawlScrapeResponse): t.ScrapeMetadata;
32
+ }
33
+ /**
34
+ * Create a Firecrawl scraper instance
35
+ * @param config Scraper configuration
36
+ * @returns Firecrawl scraper instance
37
+ */
38
+ export declare const createFirecrawlScraper: (config?: t.FirecrawlScraperConfig) => FirecrawlScraper;
@@ -0,0 +1,5 @@
1
+ import type * as t from './types';
2
+ export declare function formatResultsForLLM(turn: number, results: t.SearchResultData): {
3
+ output: string;
4
+ references: t.ResultReference[];
5
+ };
@@ -0,0 +1,13 @@
1
+ import type * as t from './types';
2
+ /**
3
+ * Expand highlights in search results using smart boundary detection.
4
+ *
5
+ * This implementation finds natural text boundaries like paragraphs, sentences,
6
+ * and phrases to provide context while maintaining readability.
7
+ *
8
+ * @param searchResults - Search results object
9
+ * @param mainExpandBy - Primary expansion size on each side (default: 300)
10
+ * @param separatorExpandBy - Additional range to look for separators (default: 150)
11
+ * @returns Copy of search results with expanded highlights and tracked references
12
+ */
13
+ export declare function expandHighlights(searchResults: t.SearchResultData, mainExpandBy?: number, separatorExpandBy?: number): t.SearchResultData;
@@ -0,0 +1,2 @@
1
+ export * from './tool';
2
+ export type * from './types';
@@ -0,0 +1,36 @@
1
+ import type * as t from './types';
2
+ export declare abstract class BaseReranker {
3
+ protected apiKey: string | undefined;
4
+ protected logger: t.Logger;
5
+ constructor(logger?: t.Logger);
6
+ abstract rerank(query: string, documents: string[], topK?: number): Promise<t.Highlight[]>;
7
+ protected getDefaultRanking(documents: string[], topK: number): t.Highlight[];
8
+ protected logDocumentSamples(documents: string[]): void;
9
+ }
10
+ export declare class JinaReranker extends BaseReranker {
11
+ constructor({ apiKey, logger, }: {
12
+ apiKey?: string;
13
+ logger?: t.Logger;
14
+ });
15
+ rerank(query: string, documents: string[], topK?: number): Promise<t.Highlight[]>;
16
+ }
17
+ export declare class CohereReranker extends BaseReranker {
18
+ constructor({ apiKey, logger, }: {
19
+ apiKey?: string;
20
+ logger?: t.Logger;
21
+ });
22
+ rerank(query: string, documents: string[], topK?: number): Promise<t.Highlight[]>;
23
+ }
24
+ export declare class InfinityReranker extends BaseReranker {
25
+ constructor(logger?: t.Logger);
26
+ rerank(query: string, documents: string[], topK?: number): Promise<t.Highlight[]>;
27
+ }
28
+ /**
29
+ * Creates the appropriate reranker based on type and configuration
30
+ */
31
+ export declare const createReranker: (config: {
32
+ rerankerType: t.RerankerType;
33
+ jinaApiKey?: string;
34
+ cohereApiKey?: string;
35
+ logger?: t.Logger;
36
+ }) => BaseReranker | undefined;
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod';
2
+ export declare enum DATE_RANGE {
3
+ PAST_HOUR = "h",
4
+ PAST_24_HOURS = "d",
5
+ PAST_WEEK = "w",
6
+ PAST_MONTH = "m",
7
+ PAST_YEAR = "y"
8
+ }
9
+ export declare const DEFAULT_QUERY_DESCRIPTION: string;
10
+ export declare const DEFAULT_COUNTRY_DESCRIPTION: string;
11
+ export declare const querySchema: z.ZodString;
12
+ export declare const dateSchema: z.ZodOptional<z.ZodNativeEnum<typeof DATE_RANGE>>;
13
+ export declare const countrySchema: z.ZodOptional<z.ZodString>;
14
+ export declare const imagesSchema: z.ZodOptional<z.ZodBoolean>;
15
+ export declare const videosSchema: z.ZodOptional<z.ZodBoolean>;
16
+ export declare const newsSchema: z.ZodOptional<z.ZodBoolean>;