@librechat/agents 2.4.83 → 2.4.85
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/llm/google/utils/common.cjs +13 -0
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
- package/dist/cjs/main.cjs +1 -1
- package/dist/cjs/messages/format.cjs +52 -34
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/tools/search/firecrawl.cjs +3 -1
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +5 -5
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/serper-scraper.cjs +132 -0
- package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -0
- package/dist/cjs/tools/search/tool.cjs +45 -9
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs +13 -0
- package/dist/esm/llm/google/utils/common.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -1
- package/dist/esm/messages/format.mjs +52 -34
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/tools/search/firecrawl.mjs +3 -1
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +5 -5
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/serper-scraper.mjs +129 -0
- package/dist/esm/tools/search/serper-scraper.mjs.map +1 -0
- package/dist/esm/tools/search/tool.mjs +45 -9
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/types/messages/format.d.ts +23 -20
- package/dist/types/tools/search/firecrawl.d.ts +2 -1
- package/dist/types/tools/search/search.d.ts +1 -2
- package/dist/types/tools/search/serper-scraper.d.ts +59 -0
- package/dist/types/tools/search/tool.d.ts +21 -0
- package/dist/types/tools/search/types.d.ts +30 -1
- package/package.json +1 -1
- package/src/llm/google/utils/common.ts +14 -0
- package/src/messages/format.ts +67 -39
- package/src/messages/formatMessage.test.ts +418 -2
- package/src/scripts/search.ts +5 -1
- package/src/tools/search/firecrawl.ts +5 -2
- package/src/tools/search/search.ts +6 -8
- package/src/tools/search/serper-scraper.ts +155 -0
- package/src/tools/search/tool.ts +47 -8
- package/src/tools/search/types.ts +45 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type * as t from './types';
|
|
2
|
-
import { FirecrawlScraper } from './firecrawl';
|
|
3
2
|
export declare const createSearchAPI: (config: t.SearchConfig) => {
|
|
4
3
|
getSources: (params: t.GetSourcesParams) => Promise<t.SearchResult>;
|
|
5
4
|
};
|
|
6
|
-
export declare const createSourceProcessor: (config?: t.ProcessSourcesConfig, scraperInstance?:
|
|
5
|
+
export declare const createSourceProcessor: (config?: t.ProcessSourcesConfig, scraperInstance?: t.BaseScraper) => {
|
|
7
6
|
processSources: (fields: t.ProcessSourcesFields) => Promise<t.SearchResultData>;
|
|
8
7
|
topResults: number;
|
|
9
8
|
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type * as t from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Serper scraper implementation
|
|
4
|
+
* Uses the Serper Scrape API (https://scrape.serper.dev) to scrape web pages
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Simple API with single endpoint
|
|
8
|
+
* - Returns both text and markdown content
|
|
9
|
+
* - Includes metadata from scraped pages
|
|
10
|
+
* - Credits-based pricing model
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const scraper = createSerperScraper({
|
|
15
|
+
* apiKey: 'your-serper-api-key',
|
|
16
|
+
* includeMarkdown: true,
|
|
17
|
+
* timeout: 10000
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* const [url, response] = await scraper.scrapeUrl('https://example.com');
|
|
21
|
+
* if (response.success) {
|
|
22
|
+
* const [content] = scraper.extractContent(response);
|
|
23
|
+
* console.log(content);
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare class SerperScraper implements t.BaseScraper {
|
|
28
|
+
private apiKey;
|
|
29
|
+
private apiUrl;
|
|
30
|
+
private timeout;
|
|
31
|
+
private logger;
|
|
32
|
+
private includeMarkdown;
|
|
33
|
+
constructor(config?: t.SerperScraperConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Scrape a single URL
|
|
36
|
+
* @param url URL to scrape
|
|
37
|
+
* @param options Scrape options
|
|
38
|
+
* @returns Scrape response
|
|
39
|
+
*/
|
|
40
|
+
scrapeUrl(url: string, options?: t.SerperScrapeOptions): Promise<[string, t.SerperScrapeResponse]>;
|
|
41
|
+
/**
|
|
42
|
+
* Extract content from scrape response
|
|
43
|
+
* @param response Scrape response
|
|
44
|
+
* @returns Extracted content or empty string if not available
|
|
45
|
+
*/
|
|
46
|
+
extractContent(response: t.SerperScrapeResponse): [string, undefined | t.References];
|
|
47
|
+
/**
|
|
48
|
+
* Extract metadata from scrape response
|
|
49
|
+
* @param response Scrape response
|
|
50
|
+
* @returns Metadata object
|
|
51
|
+
*/
|
|
52
|
+
extractMetadata(response: t.SerperScrapeResponse): Record<string, string | number | boolean | null | undefined>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create a Serper scraper instance
|
|
56
|
+
* @param config Scraper configuration
|
|
57
|
+
* @returns Serper scraper instance
|
|
58
|
+
*/
|
|
59
|
+
export declare const createSerperScraper: (config?: t.SerperScraperConfig) => SerperScraper;
|
|
@@ -6,6 +6,27 @@ import { DATE_RANGE } from './schema';
|
|
|
6
6
|
* Creates a search tool with a schema that dynamically includes the country field
|
|
7
7
|
* only when the searchProvider is 'serper'.
|
|
8
8
|
*
|
|
9
|
+
* Supports multiple scraper providers:
|
|
10
|
+
* - Firecrawl (default): Full-featured web scraping with multiple formats
|
|
11
|
+
* - Serper: Lightweight scraping using Serper's scrape API
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // Using Firecrawl scraper (default)
|
|
16
|
+
* const searchTool = createSearchTool({
|
|
17
|
+
* searchProvider: 'serper',
|
|
18
|
+
* scraperProvider: 'firecrawl',
|
|
19
|
+
* firecrawlApiKey: 'your-firecrawl-key'
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Using Serper scraper
|
|
23
|
+
* const searchTool = createSearchTool({
|
|
24
|
+
* searchProvider: 'serper',
|
|
25
|
+
* scraperProvider: 'serper',
|
|
26
|
+
* serperApiKey: 'your-serper-key'
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
9
30
|
* @param config - The search tool configuration
|
|
10
31
|
* @returns A DynamicStructuredTool with a schema that depends on the searchProvider
|
|
11
32
|
*/
|
|
@@ -4,6 +4,7 @@ import type { RunnableConfig } from '@langchain/core/runnables';
|
|
|
4
4
|
import type { BaseReranker } from './rerankers';
|
|
5
5
|
import { DATE_RANGE } from './schema';
|
|
6
6
|
export type SearchProvider = 'serper' | 'searxng';
|
|
7
|
+
export type ScraperProvider = 'firecrawl' | 'serper';
|
|
7
8
|
export type RerankerType = 'infinity' | 'jina' | 'cohere' | 'none';
|
|
8
9
|
export interface Highlight {
|
|
9
10
|
score: number;
|
|
@@ -85,8 +86,16 @@ export interface ProcessSourcesConfig {
|
|
|
85
86
|
export interface FirecrawlConfig {
|
|
86
87
|
firecrawlApiKey?: string;
|
|
87
88
|
firecrawlApiUrl?: string;
|
|
89
|
+
firecrawlVersion?: string;
|
|
88
90
|
firecrawlOptions?: FirecrawlScraperConfig;
|
|
89
91
|
}
|
|
92
|
+
export interface SerperScraperConfig {
|
|
93
|
+
apiKey?: string;
|
|
94
|
+
apiUrl?: string;
|
|
95
|
+
timeout?: number;
|
|
96
|
+
logger?: Logger;
|
|
97
|
+
includeMarkdown?: boolean;
|
|
98
|
+
}
|
|
90
99
|
export interface ScraperContentResult {
|
|
91
100
|
content: string;
|
|
92
101
|
}
|
|
@@ -133,7 +142,9 @@ export interface SearchToolConfig extends SearchConfig, ProcessSourcesConfig, Fi
|
|
|
133
142
|
jinaApiUrl?: string;
|
|
134
143
|
cohereApiKey?: string;
|
|
135
144
|
rerankerType?: RerankerType;
|
|
145
|
+
scraperProvider?: ScraperProvider;
|
|
136
146
|
scraperTimeout?: number;
|
|
147
|
+
serperScraperOptions?: SerperScraperConfig;
|
|
137
148
|
onSearchResults?: (results: SearchResult, runnableConfig?: RunnableConfig) => void;
|
|
138
149
|
onGetHighlights?: (link: string) => void;
|
|
139
150
|
}
|
|
@@ -147,8 +158,15 @@ export type UsedReferences = {
|
|
|
147
158
|
originalIndex: number;
|
|
148
159
|
reference: MediaReference;
|
|
149
160
|
}[];
|
|
161
|
+
/** Base Scraper Interface */
|
|
162
|
+
export interface BaseScraper {
|
|
163
|
+
scrapeUrl(url: string, options?: unknown): Promise<[string, FirecrawlScrapeResponse | SerperScrapeResponse]>;
|
|
164
|
+
extractContent(response: FirecrawlScrapeResponse | SerperScrapeResponse): [string, undefined | References];
|
|
165
|
+
extractMetadata(response: FirecrawlScrapeResponse | SerperScrapeResponse): ScrapeMetadata | Record<string, string | number | boolean | null | undefined>;
|
|
166
|
+
}
|
|
150
167
|
/** Firecrawl */
|
|
151
|
-
export type FirecrawlScrapeOptions = Omit<FirecrawlScraperConfig, 'apiKey' | 'apiUrl' | 'logger'>;
|
|
168
|
+
export type FirecrawlScrapeOptions = Omit<FirecrawlScraperConfig, 'apiKey' | 'apiUrl' | 'version' | 'logger'>;
|
|
169
|
+
export type SerperScrapeOptions = Omit<SerperScraperConfig, 'apiKey' | 'apiUrl' | 'logger'>;
|
|
152
170
|
export interface ScrapeMetadata {
|
|
153
171
|
sourceURL?: string;
|
|
154
172
|
url?: string;
|
|
@@ -214,9 +232,20 @@ export interface FirecrawlScrapeResponse {
|
|
|
214
232
|
};
|
|
215
233
|
error?: string;
|
|
216
234
|
}
|
|
235
|
+
export interface SerperScrapeResponse {
|
|
236
|
+
success: boolean;
|
|
237
|
+
data?: {
|
|
238
|
+
text?: string;
|
|
239
|
+
markdown?: string;
|
|
240
|
+
metadata?: Record<string, string | number | boolean | null | undefined>;
|
|
241
|
+
credits?: number;
|
|
242
|
+
};
|
|
243
|
+
error?: string;
|
|
244
|
+
}
|
|
217
245
|
export interface FirecrawlScraperConfig {
|
|
218
246
|
apiKey?: string;
|
|
219
247
|
apiUrl?: string;
|
|
248
|
+
version?: string;
|
|
220
249
|
formats?: string[];
|
|
221
250
|
timeout?: number;
|
|
222
251
|
logger?: Logger;
|
package/package.json
CHANGED
|
@@ -301,6 +301,20 @@ function _convertLangChainContentToPart(
|
|
|
301
301
|
mimeType,
|
|
302
302
|
},
|
|
303
303
|
};
|
|
304
|
+
} else if (
|
|
305
|
+
content.type === 'document' ||
|
|
306
|
+
content.type === 'audio' ||
|
|
307
|
+
content.type === 'video'
|
|
308
|
+
) {
|
|
309
|
+
if (!isMultimodalModel) {
|
|
310
|
+
throw new Error(`This model does not support ${content.type}s`);
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
inlineData: {
|
|
314
|
+
data: content.data,
|
|
315
|
+
mimeType: content.mimeType,
|
|
316
|
+
},
|
|
317
|
+
};
|
|
304
318
|
} else if (content.type === 'media') {
|
|
305
319
|
return messageContentMedia(content);
|
|
306
320
|
} else if (content.type === 'tool_use') {
|
package/src/messages/format.ts
CHANGED
|
@@ -17,28 +17,28 @@ import type {
|
|
|
17
17
|
} from '@/types';
|
|
18
18
|
import { Providers, ContentTypes } from '@/common';
|
|
19
19
|
|
|
20
|
-
interface
|
|
20
|
+
interface MediaMessageParams {
|
|
21
21
|
message: {
|
|
22
22
|
role: string;
|
|
23
23
|
content: string;
|
|
24
24
|
name?: string;
|
|
25
25
|
[key: string]: any;
|
|
26
26
|
};
|
|
27
|
-
|
|
27
|
+
mediaParts: MessageContentComplex[];
|
|
28
28
|
endpoint?: Providers;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* Formats a message
|
|
32
|
+
* Formats a message with media content (images, documents, videos, audios) to API payload format.
|
|
33
33
|
*
|
|
34
|
-
* @param
|
|
35
|
-
* @returns
|
|
34
|
+
* @param params - The parameters for formatting.
|
|
35
|
+
* @returns - The formatted message.
|
|
36
36
|
*/
|
|
37
|
-
export const
|
|
37
|
+
export const formatMediaMessage = ({
|
|
38
38
|
message,
|
|
39
|
-
image_urls,
|
|
40
39
|
endpoint,
|
|
41
|
-
|
|
40
|
+
mediaParts,
|
|
41
|
+
}: MediaMessageParams): {
|
|
42
42
|
role: string;
|
|
43
43
|
content: MessageContentComplex[];
|
|
44
44
|
name?: string;
|
|
@@ -57,7 +57,7 @@ export const formatVisionMessage = ({
|
|
|
57
57
|
|
|
58
58
|
if (endpoint === Providers.ANTHROPIC) {
|
|
59
59
|
result.content = [
|
|
60
|
-
...
|
|
60
|
+
...mediaParts,
|
|
61
61
|
{ type: ContentTypes.TEXT, text: message.content },
|
|
62
62
|
] as MessageContentComplex[];
|
|
63
63
|
return result;
|
|
@@ -65,7 +65,7 @@ export const formatVisionMessage = ({
|
|
|
65
65
|
|
|
66
66
|
result.content = [
|
|
67
67
|
{ type: ContentTypes.TEXT, text: message.content },
|
|
68
|
-
...
|
|
68
|
+
...mediaParts,
|
|
69
69
|
] as MessageContentComplex[];
|
|
70
70
|
|
|
71
71
|
return result;
|
|
@@ -78,6 +78,9 @@ interface MessageInput {
|
|
|
78
78
|
text?: string;
|
|
79
79
|
content?: string | MessageContentComplex[];
|
|
80
80
|
image_urls?: MessageContentImageUrl[];
|
|
81
|
+
documents?: MessageContentComplex[];
|
|
82
|
+
videos?: MessageContentComplex[];
|
|
83
|
+
audios?: MessageContentComplex[];
|
|
81
84
|
lc_id?: string[];
|
|
82
85
|
[key: string]: any;
|
|
83
86
|
}
|
|
@@ -100,14 +103,14 @@ interface FormattedMessage {
|
|
|
100
103
|
/**
|
|
101
104
|
* Formats a message to OpenAI payload format based on the provided options.
|
|
102
105
|
*
|
|
103
|
-
* @param
|
|
104
|
-
* @returns
|
|
106
|
+
* @param params - The parameters for formatting.
|
|
107
|
+
* @returns - The formatted message.
|
|
105
108
|
*/
|
|
106
109
|
export const formatMessage = ({
|
|
107
110
|
message,
|
|
108
111
|
userName,
|
|
109
|
-
assistantName,
|
|
110
112
|
endpoint,
|
|
113
|
+
assistantName,
|
|
111
114
|
langChain = false,
|
|
112
115
|
}: FormatMessageParams):
|
|
113
116
|
| FormattedMessage
|
|
@@ -135,21 +138,7 @@ export const formatMessage = ({
|
|
|
135
138
|
content,
|
|
136
139
|
};
|
|
137
140
|
|
|
138
|
-
|
|
139
|
-
if (Array.isArray(image_urls) && image_urls.length > 0 && role === 'user') {
|
|
140
|
-
return formatVisionMessage({
|
|
141
|
-
message: {
|
|
142
|
-
...formattedMessage,
|
|
143
|
-
content:
|
|
144
|
-
typeof formattedMessage.content === 'string'
|
|
145
|
-
? formattedMessage.content
|
|
146
|
-
: '',
|
|
147
|
-
},
|
|
148
|
-
image_urls,
|
|
149
|
-
endpoint,
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
141
|
+
// Set name fields first
|
|
153
142
|
if (_name != null && _name) {
|
|
154
143
|
formattedMessage.name = _name;
|
|
155
144
|
}
|
|
@@ -179,6 +168,45 @@ export const formatMessage = ({
|
|
|
179
168
|
}
|
|
180
169
|
}
|
|
181
170
|
|
|
171
|
+
const { image_urls, documents, videos, audios } = message;
|
|
172
|
+
const mediaParts: MessageContentComplex[] = [];
|
|
173
|
+
|
|
174
|
+
if (Array.isArray(documents) && documents.length > 0) {
|
|
175
|
+
mediaParts.push(...documents);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (Array.isArray(videos) && videos.length > 0) {
|
|
179
|
+
mediaParts.push(...videos);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (Array.isArray(audios) && audios.length > 0) {
|
|
183
|
+
mediaParts.push(...audios);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (Array.isArray(image_urls) && image_urls.length > 0) {
|
|
187
|
+
mediaParts.push(...image_urls);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (mediaParts.length > 0 && role === 'user') {
|
|
191
|
+
const mediaMessage = formatMediaMessage({
|
|
192
|
+
message: {
|
|
193
|
+
...formattedMessage,
|
|
194
|
+
content:
|
|
195
|
+
typeof formattedMessage.content === 'string'
|
|
196
|
+
? formattedMessage.content
|
|
197
|
+
: '',
|
|
198
|
+
},
|
|
199
|
+
mediaParts,
|
|
200
|
+
endpoint,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
if (!langChain) {
|
|
204
|
+
return mediaMessage;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return new HumanMessage(mediaMessage);
|
|
208
|
+
}
|
|
209
|
+
|
|
182
210
|
if (!langChain) {
|
|
183
211
|
return formattedMessage;
|
|
184
212
|
}
|
|
@@ -195,9 +223,9 @@ export const formatMessage = ({
|
|
|
195
223
|
/**
|
|
196
224
|
* Formats an array of messages for LangChain.
|
|
197
225
|
*
|
|
198
|
-
* @param
|
|
199
|
-
* @param
|
|
200
|
-
* @returns
|
|
226
|
+
* @param messages - The array of messages to format.
|
|
227
|
+
* @param formatOptions - The options for formatting each message.
|
|
228
|
+
* @returns - The array of formatted LangChain messages.
|
|
201
229
|
*/
|
|
202
230
|
export const formatLangChainMessages = (
|
|
203
231
|
messages: Array<MessageInput>,
|
|
@@ -228,8 +256,8 @@ interface LangChainMessage {
|
|
|
228
256
|
/**
|
|
229
257
|
* Formats a LangChain message object by merging properties from `lc_kwargs` or `kwargs` and `additional_kwargs`.
|
|
230
258
|
*
|
|
231
|
-
* @param
|
|
232
|
-
* @returns
|
|
259
|
+
* @param message - The message object to format.
|
|
260
|
+
* @returns - The formatted LangChain message.
|
|
233
261
|
*/
|
|
234
262
|
export const formatFromLangChain = (
|
|
235
263
|
message: LangChainMessage
|
|
@@ -357,10 +385,10 @@ function formatAssistantMessage(
|
|
|
357
385
|
/**
|
|
358
386
|
* Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.
|
|
359
387
|
*
|
|
360
|
-
* @param
|
|
361
|
-
* @param
|
|
362
|
-
* @param
|
|
363
|
-
* @returns
|
|
388
|
+
* @param payload - The array of messages to format.
|
|
389
|
+
* @param indexTokenCountMap - Optional map of message indices to token counts.
|
|
390
|
+
* @param tools - Optional set of tool names that are allowed in the request.
|
|
391
|
+
* @returns - Object containing formatted messages and updated indexTokenCountMap if provided.
|
|
364
392
|
*/
|
|
365
393
|
export const formatAgentMessages = (
|
|
366
394
|
payload: TPayload,
|
|
@@ -539,8 +567,8 @@ export const formatAgentMessages = (
|
|
|
539
567
|
|
|
540
568
|
/**
|
|
541
569
|
* Formats an array of messages for LangChain, making sure all content fields are strings
|
|
542
|
-
* @param
|
|
543
|
-
* @returns
|
|
570
|
+
* @param payload - The array of messages to format.
|
|
571
|
+
* @returns - The array of formatted LangChain messages, including ToolMessages for tool calls.
|
|
544
572
|
*/
|
|
545
573
|
export const formatContentStrings = (
|
|
546
574
|
payload: Array<BaseMessage>
|