@librechat/agents 2.4.321 → 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 +6 -0
- 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 +62 -25
- 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 +7 -1
- 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 +63 -26
- 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 +34 -0
- package/dist/types/tools/search/utils.d.ts +9 -2
- package/package.json +3 -2
- package/src/scripts/search.ts +3 -3
- package/src/tools/search/firecrawl.ts +9 -4
- package/src/tools/search/format.ts +8 -1
- package/src/tools/search/rerankers.ts +57 -36
- package/src/tools/search/schema.ts +63 -0
- package/src/tools/search/search.ts +74 -22
- package/src/tools/search/tool.ts +217 -44
- package/src/tools/search/types.ts +35 -0
- package/src/tools/search/utils.ts +37 -5
- package/src/utils/llmConfig.ts +1 -1
|
@@ -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>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
3
3
|
import type * as t from './types';
|
|
4
|
+
import { DATE_RANGE } from './schema';
|
|
4
5
|
/**
|
|
5
6
|
* Creates a search tool with a schema that dynamically includes the country field
|
|
6
7
|
* only when the searchProvider is 'serper'.
|
|
@@ -10,11 +11,23 @@ import type * as t from './types';
|
|
|
10
11
|
*/
|
|
11
12
|
export declare const createSearchTool: (config?: t.SearchToolConfig) => DynamicStructuredTool<z.ZodObject<{
|
|
12
13
|
query: z.ZodString;
|
|
14
|
+
date: z.ZodOptional<z.ZodNativeEnum<typeof DATE_RANGE>>;
|
|
13
15
|
country?: z.ZodOptional<z.ZodString>;
|
|
16
|
+
images: z.ZodOptional<z.ZodBoolean>;
|
|
17
|
+
videos: z.ZodOptional<z.ZodBoolean>;
|
|
18
|
+
news: z.ZodOptional<z.ZodBoolean>;
|
|
14
19
|
}, "strip", z.ZodTypeAny, {
|
|
15
20
|
query: string;
|
|
21
|
+
date?: DATE_RANGE | undefined;
|
|
22
|
+
images?: boolean | undefined;
|
|
23
|
+
videos?: boolean | undefined;
|
|
24
|
+
news?: boolean | undefined;
|
|
16
25
|
country?: unknown;
|
|
17
26
|
}, {
|
|
18
27
|
query: string;
|
|
28
|
+
date?: DATE_RANGE | undefined;
|
|
29
|
+
images?: boolean | undefined;
|
|
30
|
+
videos?: boolean | undefined;
|
|
31
|
+
news?: boolean | undefined;
|
|
19
32
|
country?: unknown;
|
|
20
33
|
}>>;
|
|
@@ -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
|
export type SearchProvider = 'serper' | 'searxng';
|
|
5
7
|
export type RerankerType = 'infinity' | 'jina' | 'cohere' | 'none';
|
|
6
8
|
export interface Highlight {
|
|
@@ -78,6 +80,7 @@ export interface ProcessSourcesConfig {
|
|
|
78
80
|
strategies?: string[];
|
|
79
81
|
filterContent?: boolean;
|
|
80
82
|
reranker?: BaseReranker;
|
|
83
|
+
logger?: Logger;
|
|
81
84
|
}
|
|
82
85
|
export interface FirecrawlConfig {
|
|
83
86
|
firecrawlApiKey?: string;
|
|
@@ -121,7 +124,11 @@ export interface CohereRerankerResponse {
|
|
|
121
124
|
};
|
|
122
125
|
};
|
|
123
126
|
}
|
|
127
|
+
export type SafeSearchLevel = 0 | 1 | 2;
|
|
128
|
+
export type Logger = WinstonLogger;
|
|
124
129
|
export interface SearchToolConfig extends SearchConfig, ProcessSourcesConfig, FirecrawlConfig {
|
|
130
|
+
logger?: Logger;
|
|
131
|
+
safeSearch?: SafeSearchLevel;
|
|
125
132
|
jinaApiKey?: string;
|
|
126
133
|
cohereApiKey?: string;
|
|
127
134
|
rerankerType?: RerankerType;
|
|
@@ -217,11 +224,18 @@ export interface FirecrawlScraperConfig {
|
|
|
217
224
|
apiUrl?: string;
|
|
218
225
|
formats?: string[];
|
|
219
226
|
timeout?: number;
|
|
227
|
+
logger?: Logger;
|
|
220
228
|
}
|
|
221
229
|
export type GetSourcesParams = {
|
|
222
230
|
query: string;
|
|
231
|
+
date?: DATE_RANGE;
|
|
223
232
|
country?: string;
|
|
224
233
|
numResults?: number;
|
|
234
|
+
safeSearch?: SearchToolConfig['safeSearch'];
|
|
235
|
+
images?: boolean;
|
|
236
|
+
videos?: boolean;
|
|
237
|
+
news?: boolean;
|
|
238
|
+
type?: 'search' | 'images' | 'videos' | 'news';
|
|
225
239
|
};
|
|
226
240
|
/** Serper API */
|
|
227
241
|
export interface VideoResult {
|
|
@@ -382,6 +396,13 @@ export interface SerperSearchInput {
|
|
|
382
396
|
*/
|
|
383
397
|
autocorrect?: boolean;
|
|
384
398
|
page?: number;
|
|
399
|
+
/**
|
|
400
|
+
* Date range for search results
|
|
401
|
+
* Options: "h" (past hour), "d" (past 24 hours), "w" (past week),
|
|
402
|
+
* "m" (past month), "y" (past year)
|
|
403
|
+
* `qdr:${DATE_RANGE}`
|
|
404
|
+
*/
|
|
405
|
+
tbs?: string;
|
|
385
406
|
}
|
|
386
407
|
export type SerperResultData = {
|
|
387
408
|
searchParameters: SerperSearchPayload;
|
|
@@ -491,16 +512,29 @@ export type ProcessSourcesFields = {
|
|
|
491
512
|
result: SearchResult;
|
|
492
513
|
numElements: number;
|
|
493
514
|
query: string;
|
|
515
|
+
news: boolean;
|
|
494
516
|
proMode: boolean;
|
|
495
517
|
onGetHighlights: SearchToolConfig['onGetHighlights'];
|
|
496
518
|
};
|
|
497
519
|
export type SearchToolSchema = z.ZodObject<{
|
|
498
520
|
query: z.ZodString;
|
|
521
|
+
date: z.ZodOptional<z.ZodNativeEnum<typeof DATE_RANGE>>;
|
|
499
522
|
country?: z.ZodOptional<z.ZodString>;
|
|
523
|
+
images: z.ZodOptional<z.ZodBoolean>;
|
|
524
|
+
videos: z.ZodOptional<z.ZodBoolean>;
|
|
525
|
+
news: z.ZodOptional<z.ZodBoolean>;
|
|
500
526
|
}, 'strip', z.ZodTypeAny, {
|
|
501
527
|
query: string;
|
|
528
|
+
date?: DATE_RANGE;
|
|
502
529
|
country?: unknown;
|
|
530
|
+
images?: boolean;
|
|
531
|
+
videos?: boolean;
|
|
532
|
+
news?: boolean;
|
|
503
533
|
}, {
|
|
504
534
|
query: string;
|
|
535
|
+
date?: DATE_RANGE;
|
|
505
536
|
country?: unknown;
|
|
537
|
+
images?: boolean;
|
|
538
|
+
videos?: boolean;
|
|
539
|
+
news?: boolean;
|
|
506
540
|
}>;
|
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import type * as t from './types';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Creates a default logger that maps to console methods
|
|
4
|
+
* Uses a singleton pattern to avoid creating multiple instances
|
|
5
|
+
* @returns A default logger that implements the Logger interface
|
|
6
|
+
*/
|
|
7
|
+
export declare const createDefaultLogger: () => t.Logger;
|
|
8
|
+
export declare const fileExtRegex: RegExp;
|
|
9
|
+
export declare const getDomainName: (link: string, metadata?: t.ScrapeMetadata, logger?: t.Logger) => string | undefined;
|
|
10
|
+
export declare function getAttribution(link: string, metadata?: t.ScrapeMetadata, logger?: t.Logger): string | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@librechat/agents",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.322",
|
|
4
4
|
"main": "./dist/cjs/main.cjs",
|
|
5
5
|
"module": "./dist/esm/main.mjs",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -122,7 +122,8 @@
|
|
|
122
122
|
"tsc-alias": "^1.8.10",
|
|
123
123
|
"tsconfig-paths": "^4.2.0",
|
|
124
124
|
"tslib": "^2.6.3",
|
|
125
|
-
"typescript": "^5.5.3"
|
|
125
|
+
"typescript": "^5.5.3",
|
|
126
|
+
"winston": "^3.17.0"
|
|
126
127
|
},
|
|
127
128
|
"lint-staged": {
|
|
128
129
|
"*.{js,ts}": [
|
package/src/scripts/search.ts
CHANGED
|
@@ -111,10 +111,10 @@ async function testStandardStreaming(): Promise<void> {
|
|
|
111
111
|
// `;
|
|
112
112
|
// const userMessage = 'Are massage guns good?';
|
|
113
113
|
// const userMessage = 'What is functional programming?';
|
|
114
|
-
|
|
114
|
+
const userMessage = "Get me today's trending news.";
|
|
115
115
|
// const userMessage = "search recent italy earthquake volcano activity";
|
|
116
|
-
const userMessage =
|
|
117
|
-
|
|
116
|
+
// const userMessage =
|
|
117
|
+
// "use 'Trump' as the exact search query and tell me what you find.";
|
|
118
118
|
|
|
119
119
|
conversationHistory.push(new HumanMessage(userMessage));
|
|
120
120
|
|
|
@@ -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,7 @@ export class FirecrawlScraper {
|
|
|
12
12
|
private apiUrl: string;
|
|
13
13
|
private defaultFormats: string[];
|
|
14
14
|
private timeout: number;
|
|
15
|
+
private logger: t.Logger;
|
|
15
16
|
|
|
16
17
|
constructor(config: t.FirecrawlScraperConfig = {}) {
|
|
17
18
|
this.apiKey = config.apiKey ?? process.env.FIRECRAWL_API_KEY ?? '';
|
|
@@ -25,11 +26,15 @@ export class FirecrawlScraper {
|
|
|
25
26
|
this.defaultFormats = config.formats ?? ['markdown', 'html'];
|
|
26
27
|
this.timeout = config.timeout ?? 15000;
|
|
27
28
|
|
|
29
|
+
this.logger = config.logger || createDefaultLogger();
|
|
30
|
+
|
|
28
31
|
if (!this.apiKey) {
|
|
29
|
-
|
|
32
|
+
this.logger.warn('FIRECRAWL_API_KEY is not set. Scraping will not work.');
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
this.logger.debug(
|
|
36
|
+
`Firecrawl scraper initialized with API URL: ${this.apiUrl}`
|
|
37
|
+
);
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
/**
|
|
@@ -107,7 +112,7 @@ export class FirecrawlScraper {
|
|
|
107
112
|
);
|
|
108
113
|
return [markdown, rest];
|
|
109
114
|
} catch (error) {
|
|
110
|
-
|
|
115
|
+
this.logger.error('Error processing content:', error);
|
|
111
116
|
return [response.data.markdown, undefined];
|
|
112
117
|
}
|
|
113
118
|
} else if (response.data.markdown != null) {
|
|
@@ -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,9 @@ 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
|
+
}
|
|
65
68
|
references.push({
|
|
66
69
|
type: ref.type,
|
|
67
70
|
link: ref.reference.originalUrl,
|
|
@@ -76,6 +79,10 @@ function formatSource(
|
|
|
76
79
|
continue;
|
|
77
80
|
}
|
|
78
81
|
|
|
82
|
+
if (fileExtRegex.test(ref.reference.originalUrl)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
79
86
|
if (!hasHeader) {
|
|
80
87
|
refLines.push('Core References:');
|
|
81
88
|
hasHeader = true;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
import axios from 'axios';
|
|
3
2
|
import type * as t from './types';
|
|
3
|
+
import { createDefaultLogger } from './utils';
|
|
4
4
|
|
|
5
5
|
export abstract class BaseReranker {
|
|
6
6
|
protected apiKey: string | undefined;
|
|
7
|
+
protected logger: t.Logger;
|
|
7
8
|
|
|
8
|
-
constructor() {
|
|
9
|
+
constructor(logger?: t.Logger) {
|
|
9
10
|
// Each specific reranker will set its API key
|
|
11
|
+
this.logger = logger || createDefaultLogger();
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
abstract rerank(
|
|
@@ -25,16 +27,22 @@ export abstract class BaseReranker {
|
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
protected logDocumentSamples(documents: string[]): void {
|
|
28
|
-
|
|
30
|
+
this.logger.debug('Sample documents being sent to API:');
|
|
29
31
|
for (let i = 0; i < Math.min(3, documents.length); i++) {
|
|
30
|
-
|
|
32
|
+
this.logger.debug(`Document ${i}: ${documents[i].substring(0, 100)}...`);
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export class JinaReranker extends BaseReranker {
|
|
36
|
-
constructor({
|
|
37
|
-
|
|
38
|
+
constructor({
|
|
39
|
+
apiKey = process.env.JINA_API_KEY,
|
|
40
|
+
logger,
|
|
41
|
+
}: {
|
|
42
|
+
apiKey?: string;
|
|
43
|
+
logger?: t.Logger;
|
|
44
|
+
}) {
|
|
45
|
+
super(logger);
|
|
38
46
|
this.apiKey = apiKey;
|
|
39
47
|
}
|
|
40
48
|
|
|
@@ -43,11 +51,11 @@ export class JinaReranker extends BaseReranker {
|
|
|
43
51
|
documents: string[],
|
|
44
52
|
topK: number = 5
|
|
45
53
|
): Promise<t.Highlight[]> {
|
|
46
|
-
|
|
54
|
+
this.logger.debug(`Reranking ${documents.length} documents with Jina`);
|
|
47
55
|
|
|
48
56
|
try {
|
|
49
57
|
if (this.apiKey == null || this.apiKey === '') {
|
|
50
|
-
|
|
58
|
+
this.logger.warn('JINA_API_KEY is not set. Using default ranking.');
|
|
51
59
|
return this.getDefaultRanking(documents, topK);
|
|
52
60
|
}
|
|
53
61
|
|
|
@@ -73,14 +81,14 @@ export class JinaReranker extends BaseReranker {
|
|
|
73
81
|
);
|
|
74
82
|
|
|
75
83
|
// Log the response data structure
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
this.logger.debug('Jina API response structure:');
|
|
85
|
+
this.logger.debug('Model:', response.data?.model);
|
|
86
|
+
this.logger.debug('Usage:', response.data?.usage);
|
|
87
|
+
this.logger.debug('Results count:', response.data?.results.length);
|
|
80
88
|
|
|
81
89
|
// Log a sample of the results
|
|
82
90
|
if ((response.data?.results.length ?? 0) > 0) {
|
|
83
|
-
|
|
91
|
+
this.logger.debug(
|
|
84
92
|
'Sample result:',
|
|
85
93
|
JSON.stringify(response.data?.results[0], null, 2)
|
|
86
94
|
);
|
|
@@ -108,13 +116,13 @@ export class JinaReranker extends BaseReranker {
|
|
|
108
116
|
return { text, score };
|
|
109
117
|
});
|
|
110
118
|
} else {
|
|
111
|
-
|
|
119
|
+
this.logger.warn(
|
|
112
120
|
'Unexpected response format from Jina API. Using default ranking.'
|
|
113
121
|
);
|
|
114
122
|
return this.getDefaultRanking(documents, topK);
|
|
115
123
|
}
|
|
116
124
|
} catch (error) {
|
|
117
|
-
|
|
125
|
+
this.logger.error('Error using Jina reranker:', error);
|
|
118
126
|
// Fallback to default ranking on error
|
|
119
127
|
return this.getDefaultRanking(documents, topK);
|
|
120
128
|
}
|
|
@@ -122,8 +130,14 @@ export class JinaReranker extends BaseReranker {
|
|
|
122
130
|
}
|
|
123
131
|
|
|
124
132
|
export class CohereReranker extends BaseReranker {
|
|
125
|
-
constructor({
|
|
126
|
-
|
|
133
|
+
constructor({
|
|
134
|
+
apiKey = process.env.COHERE_API_KEY,
|
|
135
|
+
logger,
|
|
136
|
+
}: {
|
|
137
|
+
apiKey?: string;
|
|
138
|
+
logger?: t.Logger;
|
|
139
|
+
}) {
|
|
140
|
+
super(logger);
|
|
127
141
|
this.apiKey = apiKey;
|
|
128
142
|
}
|
|
129
143
|
|
|
@@ -132,11 +146,11 @@ export class CohereReranker extends BaseReranker {
|
|
|
132
146
|
documents: string[],
|
|
133
147
|
topK: number = 5
|
|
134
148
|
): Promise<t.Highlight[]> {
|
|
135
|
-
|
|
149
|
+
this.logger.debug(`Reranking ${documents.length} documents with Cohere`);
|
|
136
150
|
|
|
137
151
|
try {
|
|
138
152
|
if (this.apiKey == null || this.apiKey === '') {
|
|
139
|
-
|
|
153
|
+
this.logger.warn('COHERE_API_KEY is not set. Using default ranking.');
|
|
140
154
|
return this.getDefaultRanking(documents, topK);
|
|
141
155
|
}
|
|
142
156
|
|
|
@@ -161,14 +175,14 @@ export class CohereReranker extends BaseReranker {
|
|
|
161
175
|
);
|
|
162
176
|
|
|
163
177
|
// Log the response data structure
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
this.logger.debug('Cohere API response structure:');
|
|
179
|
+
this.logger.debug('ID:', response.data?.id);
|
|
180
|
+
this.logger.debug('Meta:', response.data?.meta);
|
|
181
|
+
this.logger.debug('Results count:', response.data?.results.length);
|
|
168
182
|
|
|
169
183
|
// Log a sample of the results
|
|
170
184
|
if ((response.data?.results.length ?? 0) > 0) {
|
|
171
|
-
|
|
185
|
+
this.logger.debug(
|
|
172
186
|
'Sample result:',
|
|
173
187
|
JSON.stringify(response.data?.results[0], null, 2)
|
|
174
188
|
);
|
|
@@ -182,13 +196,13 @@ export class CohereReranker extends BaseReranker {
|
|
|
182
196
|
return { text, score };
|
|
183
197
|
});
|
|
184
198
|
} else {
|
|
185
|
-
|
|
199
|
+
this.logger.warn(
|
|
186
200
|
'Unexpected response format from Cohere API. Using default ranking.'
|
|
187
201
|
);
|
|
188
202
|
return this.getDefaultRanking(documents, topK);
|
|
189
203
|
}
|
|
190
204
|
} catch (error) {
|
|
191
|
-
|
|
205
|
+
this.logger.error('Error using Cohere reranker:', error);
|
|
192
206
|
// Fallback to default ranking on error
|
|
193
207
|
return this.getDefaultRanking(documents, topK);
|
|
194
208
|
}
|
|
@@ -196,8 +210,8 @@ export class CohereReranker extends BaseReranker {
|
|
|
196
210
|
}
|
|
197
211
|
|
|
198
212
|
export class InfinityReranker extends BaseReranker {
|
|
199
|
-
constructor() {
|
|
200
|
-
super();
|
|
213
|
+
constructor(logger?: t.Logger) {
|
|
214
|
+
super(logger);
|
|
201
215
|
// No API key needed for the placeholder implementation
|
|
202
216
|
}
|
|
203
217
|
|
|
@@ -206,7 +220,7 @@ export class InfinityReranker extends BaseReranker {
|
|
|
206
220
|
documents: string[],
|
|
207
221
|
topK: number = 5
|
|
208
222
|
): Promise<t.Highlight[]> {
|
|
209
|
-
|
|
223
|
+
this.logger.debug(
|
|
210
224
|
`Reranking ${documents.length} documents with Infinity (placeholder)`
|
|
211
225
|
);
|
|
212
226
|
// This would be replaced with actual Infinity reranker implementation
|
|
@@ -221,24 +235,31 @@ export const createReranker = (config: {
|
|
|
221
235
|
rerankerType: t.RerankerType;
|
|
222
236
|
jinaApiKey?: string;
|
|
223
237
|
cohereApiKey?: string;
|
|
238
|
+
logger?: t.Logger;
|
|
224
239
|
}): BaseReranker | undefined => {
|
|
225
|
-
const { rerankerType, jinaApiKey, cohereApiKey } = config;
|
|
240
|
+
const { rerankerType, jinaApiKey, cohereApiKey, logger } = config;
|
|
241
|
+
|
|
242
|
+
// Create a default logger if none is provided
|
|
243
|
+
const defaultLogger = logger || createDefaultLogger();
|
|
226
244
|
|
|
227
245
|
switch (rerankerType.toLowerCase()) {
|
|
228
246
|
case 'jina':
|
|
229
|
-
return new JinaReranker({ apiKey: jinaApiKey });
|
|
247
|
+
return new JinaReranker({ apiKey: jinaApiKey, logger: defaultLogger });
|
|
230
248
|
case 'cohere':
|
|
231
|
-
return new CohereReranker({
|
|
249
|
+
return new CohereReranker({
|
|
250
|
+
apiKey: cohereApiKey,
|
|
251
|
+
logger: defaultLogger,
|
|
252
|
+
});
|
|
232
253
|
case 'infinity':
|
|
233
|
-
return new InfinityReranker();
|
|
254
|
+
return new InfinityReranker(defaultLogger);
|
|
234
255
|
case 'none':
|
|
235
|
-
|
|
256
|
+
defaultLogger.debug('Skipping reranking as reranker is set to "none"');
|
|
236
257
|
return undefined;
|
|
237
258
|
default:
|
|
238
|
-
|
|
259
|
+
defaultLogger.warn(
|
|
239
260
|
`Unknown reranker type: ${rerankerType}. Defaulting to InfinityReranker.`
|
|
240
261
|
);
|
|
241
|
-
return new JinaReranker({ apiKey: jinaApiKey });
|
|
262
|
+
return new JinaReranker({ apiKey: jinaApiKey, logger: defaultLogger });
|
|
242
263
|
}
|
|
243
264
|
};
|
|
244
265
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export enum DATE_RANGE {
|
|
4
|
+
PAST_HOUR = 'h',
|
|
5
|
+
PAST_24_HOURS = 'd',
|
|
6
|
+
PAST_WEEK = 'w',
|
|
7
|
+
PAST_MONTH = 'm',
|
|
8
|
+
PAST_YEAR = 'y',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_QUERY_DESCRIPTION = `
|
|
12
|
+
GUIDELINES:
|
|
13
|
+
- Start broad, then narrow: Begin with key concepts, then refine with specifics
|
|
14
|
+
- Think like sources: Use terminology experts would use in the field
|
|
15
|
+
- Consider perspective: Frame queries from different viewpoints for better results
|
|
16
|
+
- Quality over quantity: A precise 3-4 word query often beats lengthy sentences
|
|
17
|
+
|
|
18
|
+
TECHNIQUES (combine for power searches):
|
|
19
|
+
- EXACT PHRASES: Use quotes ("climate change report")
|
|
20
|
+
- EXCLUDE TERMS: Use minus to remove unwanted results (-wikipedia)
|
|
21
|
+
- SITE-SPECIFIC: Restrict to websites (site:edu research)
|
|
22
|
+
- FILETYPE: Find specific documents (filetype:pdf study)
|
|
23
|
+
- OR OPERATOR: Find alternatives (electric OR hybrid cars)
|
|
24
|
+
- DATE RANGE: Recent information (data after:2020)
|
|
25
|
+
- WILDCARDS: Use * for unknown terms (how to * bread)
|
|
26
|
+
- SPECIFIC QUESTIONS: Use who/what/when/where/why/how
|
|
27
|
+
- DOMAIN TERMS: Include technical terminology for specialized topics
|
|
28
|
+
- CONCISE TERMS: Prioritize keywords over sentences
|
|
29
|
+
`.trim();
|
|
30
|
+
|
|
31
|
+
export const DEFAULT_COUNTRY_DESCRIPTION =
|
|
32
|
+
`Country code to localize search results.
|
|
33
|
+
Use standard 2-letter country codes: "us", "uk", "ca", "de", "fr", "jp", "br", etc.
|
|
34
|
+
Provide this when the search should return results specific to a particular country.
|
|
35
|
+
Examples:
|
|
36
|
+
- "us" for United States (default)
|
|
37
|
+
- "de" for Germany
|
|
38
|
+
- "in" for India
|
|
39
|
+
`.trim();
|
|
40
|
+
|
|
41
|
+
export const querySchema = z.string().describe(DEFAULT_QUERY_DESCRIPTION);
|
|
42
|
+
export const dateSchema = z
|
|
43
|
+
.nativeEnum(DATE_RANGE)
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('Date range for search results.');
|
|
46
|
+
export const countrySchema = z
|
|
47
|
+
.string()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe(DEFAULT_COUNTRY_DESCRIPTION);
|
|
50
|
+
export const imagesSchema = z
|
|
51
|
+
.boolean()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Whether to also run an image search.');
|
|
54
|
+
|
|
55
|
+
export const videosSchema = z
|
|
56
|
+
.boolean()
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Whether to also run a video search.');
|
|
59
|
+
|
|
60
|
+
export const newsSchema = z
|
|
61
|
+
.boolean()
|
|
62
|
+
.optional()
|
|
63
|
+
.describe('Whether to also run a news search.');
|