@librechat/agents 2.4.316 → 2.4.318

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 (52) hide show
  1. package/dist/cjs/tools/search/content.cjs +140 -0
  2. package/dist/cjs/tools/search/content.cjs.map +1 -0
  3. package/dist/cjs/tools/search/firecrawl.cjs +17 -37
  4. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  5. package/dist/cjs/tools/search/format.cjs +79 -29
  6. package/dist/cjs/tools/search/format.cjs.map +1 -1
  7. package/dist/cjs/tools/search/highlights.cjs +64 -13
  8. package/dist/cjs/tools/search/highlights.cjs.map +1 -1
  9. package/dist/cjs/tools/search/search.cjs +13 -15
  10. package/dist/cjs/tools/search/search.cjs.map +1 -1
  11. package/dist/cjs/tools/search/tool.cjs +44 -12
  12. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  13. package/dist/cjs/tools/search/utils.cjs +35 -0
  14. package/dist/cjs/tools/search/utils.cjs.map +1 -0
  15. package/dist/esm/tools/search/content.mjs +119 -0
  16. package/dist/esm/tools/search/content.mjs.map +1 -0
  17. package/dist/esm/tools/search/firecrawl.mjs +18 -37
  18. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  19. package/dist/esm/tools/search/format.mjs +79 -29
  20. package/dist/esm/tools/search/format.mjs.map +1 -1
  21. package/dist/esm/tools/search/highlights.mjs +64 -13
  22. package/dist/esm/tools/search/highlights.mjs.map +1 -1
  23. package/dist/esm/tools/search/search.mjs +12 -14
  24. package/dist/esm/tools/search/search.mjs.map +1 -1
  25. package/dist/esm/tools/search/tool.mjs +44 -12
  26. package/dist/esm/tools/search/tool.mjs.map +1 -1
  27. package/dist/esm/tools/search/utils.mjs +32 -0
  28. package/dist/esm/tools/search/utils.mjs.map +1 -0
  29. package/dist/types/tools/search/content.d.ts +4 -0
  30. package/dist/types/tools/search/firecrawl.d.ts +6 -86
  31. package/dist/types/tools/search/format.d.ts +4 -1
  32. package/dist/types/tools/search/highlights.d.ts +1 -1
  33. package/dist/types/tools/search/search.d.ts +1 -1
  34. package/dist/types/tools/search/test.d.ts +1 -0
  35. package/dist/types/tools/search/tool.d.ts +12 -4
  36. package/dist/types/tools/search/types.d.ts +380 -46
  37. package/dist/types/tools/search/utils.d.ts +3 -0
  38. package/package.json +3 -2
  39. package/src/scripts/search.ts +5 -3
  40. package/src/tools/search/content.test.ts +173 -0
  41. package/src/tools/search/content.ts +147 -0
  42. package/src/tools/search/firecrawl.ts +27 -144
  43. package/src/tools/search/format.ts +89 -31
  44. package/src/tools/search/highlights.ts +99 -17
  45. package/src/tools/search/output.md +2775 -0
  46. package/src/tools/search/search.ts +42 -54
  47. package/src/tools/search/test.html +884 -0
  48. package/src/tools/search/test.md +643 -0
  49. package/src/tools/search/test.ts +159 -0
  50. package/src/tools/search/tool.ts +54 -15
  51. package/src/tools/search/types.ts +430 -52
  52. package/src/tools/search/utils.ts +43 -0
@@ -2,8 +2,9 @@
2
2
  import axios from 'axios';
3
3
  import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';
4
4
  import type * as t from './types';
5
- import { getAttribution, FirecrawlScraper } from './firecrawl';
5
+ import { FirecrawlScraper } from './firecrawl';
6
6
  import { BaseReranker } from './rerankers';
7
+ import { getAttribution } from './utils';
7
8
 
8
9
  const chunker = {
9
10
  cleanText: (text: string): string => {
@@ -116,16 +117,11 @@ const getHighlights = async ({
116
117
  const createSerperAPI = (
117
118
  apiKey?: string
118
119
  ): {
119
- getSources: (
120
- query: string,
121
- numResults?: number,
122
- storedLocation?: string
123
- ) => Promise<t.SearchResult>;
120
+ getSources: (params: t.GetSourcesParams) => Promise<t.SearchResult>;
124
121
  } => {
125
122
  const config = {
126
123
  apiKey: apiKey ?? process.env.SERPER_API_KEY,
127
124
  apiUrl: 'https://google.serper.dev/search',
128
- defaultLocation: 'us',
129
125
  timeout: 10000,
130
126
  };
131
127
 
@@ -133,43 +129,46 @@ const createSerperAPI = (
133
129
  throw new Error('SERPER_API_KEY is required for SerperAPI');
134
130
  }
135
131
 
136
- const getSources = async (
137
- query: string,
138
- numResults: number = 8,
139
- storedLocation?: string
140
- ): Promise<t.SearchResult> => {
132
+ const getSources = async ({
133
+ query,
134
+ country,
135
+ numResults = 8,
136
+ }: t.GetSourcesParams): Promise<t.SearchResult> => {
141
137
  if (!query.trim()) {
142
138
  return { success: false, error: 'Query cannot be empty' };
143
139
  }
144
140
 
145
141
  try {
146
- const searchLocation = (
147
- storedLocation ?? config.defaultLocation
148
- ).toLowerCase();
149
-
150
- const payload = {
142
+ const payload: t.SerperSearchPayload = {
151
143
  q: query,
152
144
  num: Math.min(Math.max(1, numResults), 10),
153
- gl: searchLocation,
154
145
  };
155
146
 
156
- const response = await axios.post(config.apiUrl, payload, {
157
- headers: {
158
- 'X-API-KEY': config.apiKey,
159
- 'Content-Type': 'application/json',
160
- },
161
- timeout: config.timeout,
162
- });
147
+ if (country != null && country !== '') {
148
+ payload['gl'] = country.toLowerCase();
149
+ }
150
+
151
+ const response = await axios.post<t.SerperResultData>(
152
+ config.apiUrl,
153
+ payload,
154
+ {
155
+ headers: {
156
+ 'X-API-KEY': config.apiKey,
157
+ 'Content-Type': 'application/json',
158
+ },
159
+ timeout: config.timeout,
160
+ }
161
+ );
163
162
 
164
163
  const data = response.data;
165
164
  const results: t.SearchResultData = {
166
165
  organic: data.organic,
167
166
  images: data.images ?? [],
167
+ answerBox: data.answerBox,
168
168
  topStories: data.topStories ?? [],
169
- knowledgeGraph: data.knowledgeGraph as t.KnowledgeGraphResult,
170
- answerBox: data.answerBox as t.AnswerBoxResult,
171
- peopleAlsoAsk: data.peopleAlsoAsk as t.PeopleAlsoAskResult[],
172
- relatedSearches: data.relatedSearches as string[],
169
+ peopleAlsoAsk: data.peopleAlsoAsk,
170
+ knowledgeGraph: data.knowledgeGraph,
171
+ relatedSearches: data.relatedSearches,
173
172
  };
174
173
 
175
174
  return { success: true, data: results };
@@ -187,11 +186,7 @@ const createSearXNGAPI = (
187
186
  instanceUrl?: string,
188
187
  apiKey?: string
189
188
  ): {
190
- getSources: (
191
- query: string,
192
- numResults?: number,
193
- storedLocation?: string
194
- ) => Promise<t.SearchResult>;
189
+ getSources: (params: t.GetSourcesParams) => Promise<t.SearchResult>;
195
190
  } => {
196
191
  const config = {
197
192
  instanceUrl: instanceUrl ?? process.env.SEARXNG_INSTANCE_URL,
@@ -204,11 +199,10 @@ const createSearXNGAPI = (
204
199
  throw new Error('SEARXNG_INSTANCE_URL is required for SearXNG API');
205
200
  }
206
201
 
207
- const getSources = async (
208
- query: string,
209
- numResults: number = 8,
210
- storedLocation?: string
211
- ): Promise<t.SearchResult> => {
202
+ const getSources = async ({
203
+ query,
204
+ numResults = 8,
205
+ }: t.GetSourcesParams): Promise<t.SearchResult> => {
212
206
  if (!query.trim()) {
213
207
  return { success: false, error: 'Query cannot be empty' };
214
208
  }
@@ -225,7 +219,7 @@ const createSearXNGAPI = (
225
219
  }
226
220
 
227
221
  // Prepare parameters for SearXNG
228
- const params: Record<string, string | number> = {
222
+ const params: t.SearxNGSearchPayload = {
229
223
  q: query,
230
224
  format: 'json',
231
225
  pageno: 1,
@@ -233,13 +227,8 @@ const createSearXNGAPI = (
233
227
  language: 'all',
234
228
  safesearch: 0,
235
229
  engines: 'google,bing,duckduckgo',
236
- max_results: Math.min(Math.max(1, numResults), 20),
237
230
  };
238
231
 
239
- if (storedLocation != null && storedLocation !== 'all') {
240
- params.language = storedLocation;
241
- }
242
-
243
232
  const headers: Record<string, string> = {
244
233
  'Content-Type': 'application/json',
245
234
  };
@@ -301,11 +290,7 @@ const createSearXNGAPI = (
301
290
  export const createSearchAPI = (
302
291
  config: t.SearchConfig
303
292
  ): {
304
- getSources: (
305
- query: string,
306
- numResults?: number,
307
- storedLocation?: string
308
- ) => Promise<t.SearchResult>;
293
+ getSources: (params: t.GetSourcesParams) => Promise<t.SearchResult>;
309
294
  } => {
310
295
  const {
311
296
  searchProvider = 'serper',
@@ -366,12 +351,14 @@ export const createSourceProcessor = (
366
351
  .then(([url, response]) => {
367
352
  const attribution = getAttribution(url, response.data?.metadata);
368
353
  if (response.success && response.data) {
369
- const content = firecrawlScraper.extractContent(response);
354
+ const [content, references] =
355
+ firecrawlScraper.extractContent(response);
370
356
  return {
371
357
  url,
358
+ references,
372
359
  attribution,
373
360
  content: chunker.cleanText(content),
374
- };
361
+ } as t.ScrapeResult;
375
362
  }
376
363
 
377
364
  return {
@@ -379,7 +366,7 @@ export const createSourceProcessor = (
379
366
  attribution,
380
367
  error: true,
381
368
  content: `Failed to scrape ${url}: ${response.error ?? 'Unknown error'}`,
382
- };
369
+ } as t.ScrapeResult;
383
370
  })
384
371
  .then(async (result) => {
385
372
  try {
@@ -443,10 +430,11 @@ export const createSourceProcessor = (
443
430
  if (result.error === true) {
444
431
  continue;
445
432
  }
446
- const { url, content, attribution, highlights } = result;
433
+ const { url, content, attribution, references, highlights } = result;
447
434
  onContentScraped?.(url, {
448
435
  content,
449
436
  attribution,
437
+ references,
450
438
  highlights,
451
439
  });
452
440
  }