@librechat/agents 2.4.320 → 2.4.322
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.
- package/dist/cjs/tools/search/firecrawl.cjs +6 -4
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/format.cjs +117 -80
- package/dist/cjs/tools/search/format.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs +43 -36
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/schema.cjs +70 -0
- package/dist/cjs/tools/search/schema.cjs.map +1 -0
- package/dist/cjs/tools/search/search.cjs +125 -52
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +162 -47
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/search/utils.cjs +34 -5
- package/dist/cjs/tools/search/utils.cjs.map +1 -1
- package/dist/esm/tools/search/firecrawl.mjs +6 -4
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/format.mjs +118 -81
- package/dist/esm/tools/search/format.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs +43 -36
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/schema.mjs +61 -0
- package/dist/esm/tools/search/schema.mjs.map +1 -0
- package/dist/esm/tools/search/search.mjs +126 -53
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +161 -46
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/search/utils.mjs +33 -6
- package/dist/esm/tools/search/utils.mjs.map +1 -1
- package/dist/types/tools/search/firecrawl.d.ts +1 -0
- package/dist/types/tools/search/rerankers.d.ts +8 -4
- package/dist/types/tools/search/schema.d.ts +16 -0
- package/dist/types/tools/search/tool.d.ts +13 -0
- package/dist/types/tools/search/types.d.ts +36 -0
- package/dist/types/tools/search/utils.d.ts +9 -2
- package/package.json +3 -2
- package/src/scripts/search.ts +3 -0
- package/src/tools/search/firecrawl.ts +9 -4
- package/src/tools/search/format.ts +157 -87
- package/src/tools/search/rerankers.ts +57 -36
- package/src/tools/search/schema.ts +63 -0
- package/src/tools/search/search.ts +165 -52
- package/src/tools/search/tool.ts +217 -44
- package/src/tools/search/types.ts +37 -0
- package/src/tools/search/utils.ts +37 -5
- package/src/utils/llmConfig.ts +1 -1
package/src/tools/search/tool.ts
CHANGED
|
@@ -1,88 +1,246 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
import { z } from 'zod';
|
|
3
2
|
import { tool, DynamicStructuredTool } from '@langchain/core/tools';
|
|
4
3
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
5
4
|
import type * as t from './types';
|
|
5
|
+
import {
|
|
6
|
+
DATE_RANGE,
|
|
7
|
+
querySchema,
|
|
8
|
+
dateSchema,
|
|
9
|
+
countrySchema,
|
|
10
|
+
imagesSchema,
|
|
11
|
+
videosSchema,
|
|
12
|
+
newsSchema,
|
|
13
|
+
} from './schema';
|
|
6
14
|
import { createSearchAPI, createSourceProcessor } from './search';
|
|
7
15
|
import { createFirecrawlScraper } from './firecrawl';
|
|
8
16
|
import { expandHighlights } from './highlights';
|
|
9
17
|
import { formatResultsForLLM } from './format';
|
|
18
|
+
import { createDefaultLogger } from './utils';
|
|
10
19
|
import { createReranker } from './rerankers';
|
|
11
20
|
import { Constants } from '@/common';
|
|
12
21
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Executes parallel searches and merges the results
|
|
24
|
+
*/
|
|
25
|
+
async function executeParallelSearches({
|
|
26
|
+
searchAPI,
|
|
27
|
+
query,
|
|
28
|
+
date,
|
|
29
|
+
country,
|
|
30
|
+
safeSearch,
|
|
31
|
+
images,
|
|
32
|
+
videos,
|
|
33
|
+
news,
|
|
34
|
+
logger,
|
|
35
|
+
}: {
|
|
36
|
+
searchAPI: ReturnType<typeof createSearchAPI>;
|
|
37
|
+
query: string;
|
|
38
|
+
date?: DATE_RANGE;
|
|
39
|
+
country?: string;
|
|
40
|
+
safeSearch: t.SearchToolConfig['safeSearch'];
|
|
41
|
+
images: boolean;
|
|
42
|
+
videos: boolean;
|
|
43
|
+
news: boolean;
|
|
44
|
+
logger: t.Logger;
|
|
45
|
+
}): Promise<t.SearchResult> {
|
|
46
|
+
// Prepare all search tasks to run in parallel
|
|
47
|
+
const searchTasks: Promise<t.SearchResult>[] = [
|
|
48
|
+
// Main search
|
|
49
|
+
searchAPI.getSources({
|
|
50
|
+
query,
|
|
51
|
+
date,
|
|
52
|
+
country,
|
|
53
|
+
safeSearch,
|
|
54
|
+
}),
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
if (images) {
|
|
58
|
+
searchTasks.push(
|
|
59
|
+
searchAPI
|
|
60
|
+
.getSources({
|
|
61
|
+
query,
|
|
62
|
+
date,
|
|
63
|
+
country,
|
|
64
|
+
safeSearch,
|
|
65
|
+
type: 'images',
|
|
66
|
+
})
|
|
67
|
+
.catch((error) => {
|
|
68
|
+
logger.error('Error fetching images:', error);
|
|
69
|
+
return {
|
|
70
|
+
success: false,
|
|
71
|
+
error: `Images search failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
72
|
+
};
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (videos) {
|
|
77
|
+
searchTasks.push(
|
|
78
|
+
searchAPI
|
|
79
|
+
.getSources({
|
|
80
|
+
query,
|
|
81
|
+
date,
|
|
82
|
+
country,
|
|
83
|
+
safeSearch,
|
|
84
|
+
type: 'videos',
|
|
85
|
+
})
|
|
86
|
+
.catch((error) => {
|
|
87
|
+
logger.error('Error fetching videos:', error);
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
error: `Videos search failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
91
|
+
};
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (news) {
|
|
96
|
+
searchTasks.push(
|
|
97
|
+
searchAPI
|
|
98
|
+
.getSources({
|
|
99
|
+
query,
|
|
100
|
+
date,
|
|
101
|
+
country,
|
|
102
|
+
safeSearch,
|
|
103
|
+
type: 'news',
|
|
104
|
+
})
|
|
105
|
+
.catch((error) => {
|
|
106
|
+
logger.error('Error fetching news:', error);
|
|
107
|
+
return {
|
|
108
|
+
success: false,
|
|
109
|
+
error: `News search failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
110
|
+
};
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Run all searches in parallel
|
|
116
|
+
const results = await Promise.all(searchTasks);
|
|
117
|
+
|
|
118
|
+
// Get the main search result (first result)
|
|
119
|
+
const mainResult = results[0];
|
|
120
|
+
if (!mainResult.success) {
|
|
121
|
+
throw new Error(mainResult.error ?? 'Search failed');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Merge additional results with the main results
|
|
125
|
+
const mergedResults = { ...mainResult.data };
|
|
126
|
+
|
|
127
|
+
// Convert existing news to topStories if present
|
|
128
|
+
if (mergedResults.news !== undefined && mergedResults.news.length > 0) {
|
|
129
|
+
const existingNewsAsTopStories = mergedResults.news
|
|
130
|
+
.filter((newsItem) => newsItem.link !== undefined && newsItem.link !== '')
|
|
131
|
+
.map((newsItem) => ({
|
|
132
|
+
title: newsItem.title ?? '',
|
|
133
|
+
link: newsItem.link ?? '',
|
|
134
|
+
source: newsItem.source ?? '',
|
|
135
|
+
date: newsItem.date ?? '',
|
|
136
|
+
imageUrl: newsItem.imageUrl ?? '',
|
|
137
|
+
processed: false,
|
|
138
|
+
}));
|
|
139
|
+
mergedResults.topStories = [
|
|
140
|
+
...(mergedResults.topStories ?? []),
|
|
141
|
+
...existingNewsAsTopStories,
|
|
142
|
+
];
|
|
143
|
+
delete mergedResults.news;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
results.slice(1).forEach((result) => {
|
|
147
|
+
if (result.success && result.data !== undefined) {
|
|
148
|
+
if (result.data.images !== undefined && result.data.images.length > 0) {
|
|
149
|
+
mergedResults.images = [
|
|
150
|
+
...(mergedResults.images ?? []),
|
|
151
|
+
...result.data.images,
|
|
152
|
+
];
|
|
153
|
+
}
|
|
154
|
+
if (result.data.videos !== undefined && result.data.videos.length > 0) {
|
|
155
|
+
mergedResults.videos = [
|
|
156
|
+
...(mergedResults.videos ?? []),
|
|
157
|
+
...result.data.videos,
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
if (result.data.news !== undefined && result.data.news.length > 0) {
|
|
161
|
+
const newsAsTopStories = result.data.news.map((newsItem) => ({
|
|
162
|
+
...newsItem,
|
|
163
|
+
link: newsItem.link ?? '',
|
|
164
|
+
}));
|
|
165
|
+
mergedResults.topStories = [
|
|
166
|
+
...(mergedResults.topStories ?? []),
|
|
167
|
+
...newsAsTopStories,
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return { success: true, data: mergedResults };
|
|
174
|
+
}
|
|
41
175
|
|
|
42
176
|
function createSearchProcessor({
|
|
43
177
|
searchAPI,
|
|
178
|
+
safeSearch,
|
|
44
179
|
sourceProcessor,
|
|
45
180
|
onGetHighlights,
|
|
181
|
+
logger,
|
|
46
182
|
}: {
|
|
183
|
+
safeSearch: t.SearchToolConfig['safeSearch'];
|
|
47
184
|
searchAPI: ReturnType<typeof createSearchAPI>;
|
|
48
185
|
sourceProcessor: ReturnType<typeof createSourceProcessor>;
|
|
49
186
|
onGetHighlights: t.SearchToolConfig['onGetHighlights'];
|
|
187
|
+
logger: t.Logger;
|
|
50
188
|
}) {
|
|
51
189
|
return async function ({
|
|
52
190
|
query,
|
|
191
|
+
date,
|
|
53
192
|
country,
|
|
54
193
|
proMode = true,
|
|
55
194
|
maxSources = 5,
|
|
56
195
|
onSearchResults,
|
|
196
|
+
images = false,
|
|
197
|
+
videos = false,
|
|
198
|
+
news = false,
|
|
57
199
|
}: {
|
|
58
200
|
query: string;
|
|
59
201
|
country?: string;
|
|
60
|
-
|
|
202
|
+
date?: DATE_RANGE;
|
|
61
203
|
proMode?: boolean;
|
|
204
|
+
maxSources?: number;
|
|
62
205
|
onSearchResults: t.SearchToolConfig['onSearchResults'];
|
|
206
|
+
images?: boolean;
|
|
207
|
+
videos?: boolean;
|
|
208
|
+
news?: boolean;
|
|
63
209
|
}): Promise<t.SearchResultData> {
|
|
64
210
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
211
|
+
// Execute parallel searches and merge results
|
|
212
|
+
const searchResult = await executeParallelSearches({
|
|
213
|
+
searchAPI,
|
|
214
|
+
query,
|
|
215
|
+
date,
|
|
216
|
+
country,
|
|
217
|
+
safeSearch,
|
|
218
|
+
images,
|
|
219
|
+
videos,
|
|
220
|
+
news,
|
|
221
|
+
logger,
|
|
222
|
+
});
|
|
67
223
|
|
|
68
|
-
|
|
69
|
-
throw new Error(result.error ?? 'Search failed');
|
|
70
|
-
}
|
|
224
|
+
onSearchResults?.(searchResult);
|
|
71
225
|
|
|
72
226
|
const processedSources = await sourceProcessor.processSources({
|
|
73
227
|
query,
|
|
74
|
-
|
|
228
|
+
news,
|
|
229
|
+
result: searchResult,
|
|
75
230
|
proMode,
|
|
76
231
|
onGetHighlights,
|
|
77
232
|
numElements: maxSources,
|
|
78
233
|
});
|
|
234
|
+
|
|
79
235
|
return expandHighlights(processedSources);
|
|
80
236
|
} catch (error) {
|
|
81
|
-
|
|
237
|
+
logger.error('Error in search:', error);
|
|
82
238
|
return {
|
|
83
239
|
organic: [],
|
|
84
240
|
topStories: [],
|
|
85
241
|
images: [],
|
|
242
|
+
videos: [],
|
|
243
|
+
news: [],
|
|
86
244
|
relatedSearches: [],
|
|
87
245
|
error: error instanceof Error ? error.message : String(error),
|
|
88
246
|
};
|
|
@@ -116,11 +274,15 @@ function createTool({
|
|
|
116
274
|
}): DynamicStructuredTool<typeof schema> {
|
|
117
275
|
return tool<typeof schema>(
|
|
118
276
|
async (params, runnableConfig) => {
|
|
119
|
-
const { query, country: _c } = params;
|
|
277
|
+
const { query, date, country: _c, images, videos, news } = params;
|
|
120
278
|
const country = typeof _c === 'string' && _c ? _c : undefined;
|
|
121
279
|
const searchResult = await search({
|
|
122
280
|
query,
|
|
281
|
+
date,
|
|
123
282
|
country,
|
|
283
|
+
images,
|
|
284
|
+
videos,
|
|
285
|
+
news,
|
|
124
286
|
onSearchResults: createOnSearchResults({
|
|
125
287
|
runnableConfig,
|
|
126
288
|
onSearchResults: _onSearchResults,
|
|
@@ -181,6 +343,7 @@ export const createSearchTool = (
|
|
|
181
343
|
topResults = 5,
|
|
182
344
|
strategies = ['no_extraction'],
|
|
183
345
|
filterContent = true,
|
|
346
|
+
safeSearch = 1,
|
|
184
347
|
firecrawlApiKey,
|
|
185
348
|
firecrawlApiUrl,
|
|
186
349
|
firecrawlFormats = ['markdown', 'html'],
|
|
@@ -190,19 +353,25 @@ export const createSearchTool = (
|
|
|
190
353
|
onGetHighlights,
|
|
191
354
|
} = config;
|
|
192
355
|
|
|
193
|
-
const
|
|
356
|
+
const logger = config.logger || createDefaultLogger();
|
|
357
|
+
|
|
194
358
|
const schemaObject: {
|
|
195
359
|
query: z.ZodString;
|
|
360
|
+
date: z.ZodOptional<z.ZodNativeEnum<typeof DATE_RANGE>>;
|
|
196
361
|
country?: z.ZodOptional<z.ZodString>;
|
|
362
|
+
images: z.ZodOptional<z.ZodBoolean>;
|
|
363
|
+
videos: z.ZodOptional<z.ZodBoolean>;
|
|
364
|
+
news: z.ZodOptional<z.ZodBoolean>;
|
|
197
365
|
} = {
|
|
198
366
|
query: querySchema,
|
|
367
|
+
date: dateSchema,
|
|
368
|
+
images: imagesSchema,
|
|
369
|
+
videos: videosSchema,
|
|
370
|
+
news: newsSchema,
|
|
199
371
|
};
|
|
200
372
|
|
|
201
373
|
if (searchProvider === 'serper') {
|
|
202
|
-
schemaObject.country =
|
|
203
|
-
.string()
|
|
204
|
-
.optional()
|
|
205
|
-
.describe(DEFAULT_COUNTRY_DESCRIPTION);
|
|
374
|
+
schemaObject.country = countrySchema;
|
|
206
375
|
}
|
|
207
376
|
|
|
208
377
|
const toolSchema = z.object(schemaObject);
|
|
@@ -224,10 +393,11 @@ export const createSearchTool = (
|
|
|
224
393
|
rerankerType,
|
|
225
394
|
jinaApiKey,
|
|
226
395
|
cohereApiKey,
|
|
396
|
+
logger,
|
|
227
397
|
});
|
|
228
398
|
|
|
229
399
|
if (!selectedReranker) {
|
|
230
|
-
|
|
400
|
+
logger.warn('No reranker selected. Using default ranking.');
|
|
231
401
|
}
|
|
232
402
|
|
|
233
403
|
const sourceProcessor = createSourceProcessor(
|
|
@@ -236,14 +406,17 @@ export const createSearchTool = (
|
|
|
236
406
|
topResults,
|
|
237
407
|
strategies,
|
|
238
408
|
filterContent,
|
|
409
|
+
logger,
|
|
239
410
|
},
|
|
240
411
|
firecrawlScraper
|
|
241
412
|
);
|
|
242
413
|
|
|
243
414
|
const search = createSearchProcessor({
|
|
244
415
|
searchAPI,
|
|
416
|
+
safeSearch,
|
|
245
417
|
sourceProcessor,
|
|
246
418
|
onGetHighlights,
|
|
419
|
+
logger,
|
|
247
420
|
});
|
|
248
421
|
|
|
249
422
|
return createTool({
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import type { Logger as WinstonLogger } from 'winston';
|
|
2
3
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
3
4
|
import type { BaseReranker } from './rerankers';
|
|
5
|
+
import { DATE_RANGE } from './schema';
|
|
4
6
|
|
|
5
7
|
export type SearchProvider = 'serper' | 'searxng';
|
|
6
8
|
export type RerankerType = 'infinity' | 'jina' | 'cohere' | 'none';
|
|
@@ -16,6 +18,7 @@ export type ProcessedSource = {
|
|
|
16
18
|
attribution?: string;
|
|
17
19
|
references?: References;
|
|
18
20
|
highlights?: Highlight[];
|
|
21
|
+
processed?: boolean;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
export type ProcessedOrganic = OrganicResult & ProcessedSource;
|
|
@@ -24,6 +27,7 @@ export type ValidSource = ProcessedOrganic | ProcessedTopStory;
|
|
|
24
27
|
|
|
25
28
|
export type ResultReference = {
|
|
26
29
|
link: string;
|
|
30
|
+
type: 'link' | 'image' | 'video';
|
|
27
31
|
title?: string;
|
|
28
32
|
attribution?: string;
|
|
29
33
|
};
|
|
@@ -84,6 +88,7 @@ export interface ProcessSourcesConfig {
|
|
|
84
88
|
strategies?: string[];
|
|
85
89
|
filterContent?: boolean;
|
|
86
90
|
reranker?: BaseReranker;
|
|
91
|
+
logger?: Logger;
|
|
87
92
|
}
|
|
88
93
|
|
|
89
94
|
export interface FirecrawlConfig {
|
|
@@ -133,10 +138,15 @@ export interface CohereRerankerResponse {
|
|
|
133
138
|
};
|
|
134
139
|
}
|
|
135
140
|
|
|
141
|
+
export type SafeSearchLevel = 0 | 1 | 2;
|
|
142
|
+
|
|
143
|
+
export type Logger = WinstonLogger;
|
|
136
144
|
export interface SearchToolConfig
|
|
137
145
|
extends SearchConfig,
|
|
138
146
|
ProcessSourcesConfig,
|
|
139
147
|
FirecrawlConfig {
|
|
148
|
+
logger?: Logger;
|
|
149
|
+
safeSearch?: SafeSearchLevel;
|
|
140
150
|
jinaApiKey?: string;
|
|
141
151
|
cohereApiKey?: string;
|
|
142
152
|
rerankerType?: RerankerType;
|
|
@@ -249,12 +259,19 @@ export interface FirecrawlScraperConfig {
|
|
|
249
259
|
apiUrl?: string;
|
|
250
260
|
formats?: string[];
|
|
251
261
|
timeout?: number;
|
|
262
|
+
logger?: Logger;
|
|
252
263
|
}
|
|
253
264
|
|
|
254
265
|
export type GetSourcesParams = {
|
|
255
266
|
query: string;
|
|
267
|
+
date?: DATE_RANGE;
|
|
256
268
|
country?: string;
|
|
257
269
|
numResults?: number;
|
|
270
|
+
safeSearch?: SearchToolConfig['safeSearch'];
|
|
271
|
+
images?: boolean;
|
|
272
|
+
videos?: boolean;
|
|
273
|
+
news?: boolean;
|
|
274
|
+
type?: 'search' | 'images' | 'videos' | 'news';
|
|
258
275
|
};
|
|
259
276
|
|
|
260
277
|
/** Serper API */
|
|
@@ -433,6 +450,13 @@ export interface SerperSearchInput {
|
|
|
433
450
|
*/
|
|
434
451
|
autocorrect?: boolean;
|
|
435
452
|
page?: number;
|
|
453
|
+
/**
|
|
454
|
+
* Date range for search results
|
|
455
|
+
* Options: "h" (past hour), "d" (past 24 hours), "w" (past week),
|
|
456
|
+
* "m" (past month), "y" (past year)
|
|
457
|
+
* `qdr:${DATE_RANGE}`
|
|
458
|
+
*/
|
|
459
|
+
tbs?: string;
|
|
436
460
|
}
|
|
437
461
|
|
|
438
462
|
export type SerperResultData = {
|
|
@@ -562,6 +586,7 @@ export type ProcessSourcesFields = {
|
|
|
562
586
|
result: SearchResult;
|
|
563
587
|
numElements: number;
|
|
564
588
|
query: string;
|
|
589
|
+
news: boolean;
|
|
565
590
|
proMode: boolean;
|
|
566
591
|
onGetHighlights: SearchToolConfig['onGetHighlights'];
|
|
567
592
|
};
|
|
@@ -569,16 +594,28 @@ export type ProcessSourcesFields = {
|
|
|
569
594
|
export type SearchToolSchema = z.ZodObject<
|
|
570
595
|
{
|
|
571
596
|
query: z.ZodString;
|
|
597
|
+
date: z.ZodOptional<z.ZodNativeEnum<typeof DATE_RANGE>>;
|
|
572
598
|
country?: z.ZodOptional<z.ZodString>;
|
|
599
|
+
images: z.ZodOptional<z.ZodBoolean>;
|
|
600
|
+
videos: z.ZodOptional<z.ZodBoolean>;
|
|
601
|
+
news: z.ZodOptional<z.ZodBoolean>;
|
|
573
602
|
},
|
|
574
603
|
'strip',
|
|
575
604
|
z.ZodTypeAny,
|
|
576
605
|
{
|
|
577
606
|
query: string;
|
|
607
|
+
date?: DATE_RANGE;
|
|
578
608
|
country?: unknown;
|
|
609
|
+
images?: boolean;
|
|
610
|
+
videos?: boolean;
|
|
611
|
+
news?: boolean;
|
|
579
612
|
},
|
|
580
613
|
{
|
|
581
614
|
query: string;
|
|
615
|
+
date?: DATE_RANGE;
|
|
582
616
|
country?: unknown;
|
|
617
|
+
images?: boolean;
|
|
618
|
+
videos?: boolean;
|
|
619
|
+
news?: boolean;
|
|
583
620
|
}
|
|
584
621
|
>;
|
|
@@ -1,9 +1,36 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
+
|
|
2
3
|
import type * as t from './types';
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Singleton instance of the default logger
|
|
7
|
+
*/
|
|
8
|
+
let defaultLoggerInstance: t.Logger | null = null;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a default logger that maps to console methods
|
|
12
|
+
* Uses a singleton pattern to avoid creating multiple instances
|
|
13
|
+
* @returns A default logger that implements the Logger interface
|
|
14
|
+
*/
|
|
15
|
+
export const createDefaultLogger = (): t.Logger => {
|
|
16
|
+
if (!defaultLoggerInstance) {
|
|
17
|
+
defaultLoggerInstance = {
|
|
18
|
+
error: console.error,
|
|
19
|
+
warn: console.warn,
|
|
20
|
+
info: console.info,
|
|
21
|
+
debug: console.debug,
|
|
22
|
+
} as t.Logger;
|
|
23
|
+
}
|
|
24
|
+
return defaultLoggerInstance;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const fileExtRegex =
|
|
28
|
+
/\.(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;
|
|
29
|
+
|
|
4
30
|
export const getDomainName = (
|
|
5
31
|
link: string,
|
|
6
|
-
metadata?: t.ScrapeMetadata
|
|
32
|
+
metadata?: t.ScrapeMetadata,
|
|
33
|
+
logger?: t.Logger
|
|
7
34
|
): string | undefined => {
|
|
8
35
|
try {
|
|
9
36
|
const url = metadata?.sourceURL ?? metadata?.url ?? (link || '');
|
|
@@ -13,7 +40,11 @@ export const getDomainName = (
|
|
|
13
40
|
}
|
|
14
41
|
} catch (e) {
|
|
15
42
|
// URL parsing failed
|
|
16
|
-
|
|
43
|
+
if (logger) {
|
|
44
|
+
logger.error('Error parsing URL:', e);
|
|
45
|
+
} else {
|
|
46
|
+
console.error('Error parsing URL:', e);
|
|
47
|
+
}
|
|
17
48
|
}
|
|
18
49
|
|
|
19
50
|
return;
|
|
@@ -21,9 +52,10 @@ export const getDomainName = (
|
|
|
21
52
|
|
|
22
53
|
export function getAttribution(
|
|
23
54
|
link: string,
|
|
24
|
-
metadata?: t.ScrapeMetadata
|
|
55
|
+
metadata?: t.ScrapeMetadata,
|
|
56
|
+
logger?: t.Logger
|
|
25
57
|
): string | undefined {
|
|
26
|
-
if (!metadata) return getDomainName(link, metadata);
|
|
58
|
+
if (!metadata) return getDomainName(link, metadata, logger);
|
|
27
59
|
|
|
28
60
|
const twitterSite = metadata['twitter:site'];
|
|
29
61
|
const twitterSiteFormatted =
|
|
@@ -43,5 +75,5 @@ export function getAttribution(
|
|
|
43
75
|
return attribution;
|
|
44
76
|
}
|
|
45
77
|
|
|
46
|
-
return getDomainName(link, metadata);
|
|
78
|
+
return getDomainName(link, metadata, logger);
|
|
47
79
|
}
|
package/src/utils/llmConfig.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type * as t from '@/types';
|
|
|
6
6
|
export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
|
|
7
7
|
[Providers.OPENAI]: {
|
|
8
8
|
provider: Providers.OPENAI,
|
|
9
|
-
model: 'gpt-
|
|
9
|
+
model: 'gpt-4.1',
|
|
10
10
|
temperature: 0.7,
|
|
11
11
|
streaming: true,
|
|
12
12
|
streamUsage: true,
|