mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
* fix: get user-provided API key using environment variable names as keys * feat: Add error handling for missing API key and search engine ID * feat: Add GoogleSearch and TavilySearchResults specs for environment variables handling --------- Co-authored-by: Dongwoo Jeong <dongwoo.jeong@lge.com>
94 lines
3.2 KiB
JavaScript
94 lines
3.2 KiB
JavaScript
const { z } = require('zod');
|
|
const { Tool } = require('@langchain/core/tools');
|
|
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
|
|
|
|
class TavilySearchResults extends Tool {
|
|
static lc_name() {
|
|
return 'TavilySearchResults';
|
|
}
|
|
|
|
constructor(fields = {}) {
|
|
super(fields);
|
|
this.envVar = 'TAVILY_API_KEY';
|
|
/* Used to initialize the Tool without necessary variables. */
|
|
this.override = fields.override ?? false;
|
|
this.apiKey = fields[this.envVar] ?? this.getApiKey();
|
|
|
|
this.kwargs = fields?.kwargs ?? {};
|
|
this.name = 'tavily_search_results_json';
|
|
this.description =
|
|
'A search engine optimized for comprehensive, accurate, and trusted results. Useful for when you need to answer questions about current events.';
|
|
|
|
this.schema = z.object({
|
|
query: z.string().min(1).describe('The search query string.'),
|
|
max_results: z
|
|
.number()
|
|
.min(1)
|
|
.max(10)
|
|
.optional()
|
|
.describe('The maximum number of search results to return. Defaults to 5.'),
|
|
search_depth: z
|
|
.enum(['basic', 'advanced'])
|
|
.optional()
|
|
.describe(
|
|
'The depth of the search, affecting result quality and response time (`basic` or `advanced`). Default is basic for quick results and advanced for indepth high quality results but longer response time. Advanced calls equals 2 requests.',
|
|
),
|
|
include_images: z
|
|
.boolean()
|
|
.optional()
|
|
.describe(
|
|
'Whether to include a list of query-related images in the response. Default is False.',
|
|
),
|
|
include_answer: z
|
|
.boolean()
|
|
.optional()
|
|
.describe('Whether to include answers in the search results. Default is False.'),
|
|
// include_raw_content: z.boolean().optional().describe('Whether to include raw content in the search results. Default is False.'),
|
|
// include_domains: z.array(z.string()).optional().describe('A list of domains to specifically include in the search results.'),
|
|
// exclude_domains: z.array(z.string()).optional().describe('A list of domains to specifically exclude from the search results.'),
|
|
});
|
|
}
|
|
|
|
getApiKey() {
|
|
const apiKey = getEnvironmentVariable(this.envVar);
|
|
if (!apiKey && !this.override) {
|
|
throw new Error(`Missing ${this.envVar} environment variable.`);
|
|
}
|
|
return apiKey;
|
|
}
|
|
|
|
async _call(input) {
|
|
const validationResult = this.schema.safeParse(input);
|
|
if (!validationResult.success) {
|
|
throw new Error(`Validation failed: ${JSON.stringify(validationResult.error.issues)}`);
|
|
}
|
|
|
|
const { query, ...rest } = validationResult.data;
|
|
|
|
const requestBody = {
|
|
api_key: this.apiKey,
|
|
query,
|
|
...rest,
|
|
...this.kwargs,
|
|
};
|
|
|
|
const response = await fetch('https://api.tavily.com/search', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(requestBody),
|
|
});
|
|
|
|
const json = await response.json();
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
`Request failed with status ${response.status}: ${json?.detail?.error || json?.error}`,
|
|
);
|
|
}
|
|
|
|
return JSON.stringify(json);
|
|
}
|
|
}
|
|
|
|
module.exports = TavilySearchResults;
|