mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
* fix: agent initialization, add `collectedUsage` handling * style: improve side panel styling * refactor(loadAgent): Optimize order agent project ID retrieval * feat: code execution * fix: typing issues * feat: ExecuteCode content part * refactor: use local state for default collapsed state of analysis content parts * fix: code parsing in ExecuteCode component * chore: bump agents package, export loadAuthValues * refactor: Update handleTools.js to use EnvVar for code execution tool authentication * WIP * feat: download code outputs * fix(useEventHandlers): type issues * feat: backend handling for code outputs * Refactor: Remove console.log statement in Part.tsx * refactor: add attachments to TMessage/messageSchema * WIP: prelim handling for code outputs * feat: attachments rendering * refactor: improve attachments rendering * fix: attachments, nullish edge case, handle attachments from event stream, bump agents package * fix filename download * fix: tool assignment for 'run code' on agent creation * fix: image handling by adding attachments * refactor: prevent agent creation without provider/model * refactor: remove unnecessary space in agent creation success message * refactor: select first model if selecting provider from empty on form * fix: Agent avatar bug * fix: `defaultAgentFormValues` causing boolean typing issue and typeerror * fix: capabilities counting as tools, causing duplication of them * fix: formatted messages edge case where consecutive content text type parts with the latter having tool_call_ids would cause consecutive AI messages to be created. furthermore, content could not be an array for tool_use messages (anthropic limitation) * chore: bump @librechat/agents dependency to version 1.6.9 * feat: bedrock agents * feat: new Agents icon * feat: agent titling * feat: agent landing * refactor: allow sharing agent globally only if user is admin or author * feat: initial AgentPanelSkeleton * feat: AgentPanelSkeleton * feat: collaborative agents * chore: add potential authorName as part of schema * chore: Remove unnecessary console.log statement * WIP: agent model parameters * chore: ToolsDialog typing and tool related localization chnages * refactor: update tool instance type (latest langchain class), and rename google tool to 'google' proper * chore: add back tools * feat: Agent knowledge files upload * refactor: better verbiage for disabled knowledge * chore: debug logs for file deletions * chore: debug logs for file deletions * feat: upload/delete agent knowledge/file-search files * feat: file search UI for agents * feat: first pass, file search tool * chore: update default agent capabilities and info
104 lines
3.3 KiB
JavaScript
104 lines
3.3 KiB
JavaScript
const { z } = require('zod');
|
|
const axios = require('axios');
|
|
const { tool } = require('@langchain/core/tools');
|
|
const { Tools, EToolResources } = require('librechat-data-provider');
|
|
const { getFiles } = require('~/models/File');
|
|
const { logger } = require('~/config');
|
|
|
|
/**
|
|
*
|
|
* @param {Object} options
|
|
* @param {ServerRequest} options.req
|
|
* @param {Agent['tool_resources']} options.tool_resources
|
|
* @returns
|
|
*/
|
|
const createFileSearchTool = async (options) => {
|
|
const { req, tool_resources } = options;
|
|
const file_ids = tool_resources?.[EToolResources.file_search]?.file_ids ?? [];
|
|
const files = (await getFiles({ file_id: { $in: file_ids } })).map((file) => ({
|
|
file_id: file.file_id,
|
|
filename: file.filename,
|
|
}));
|
|
|
|
const fileList = files.map((file) => `- ${file.filename}`).join('\n');
|
|
const toolDescription = `Performs a semantic search based on a natural language query across the following files:\n${fileList}`;
|
|
|
|
const FileSearch = tool(
|
|
async ({ query }) => {
|
|
if (files.length === 0) {
|
|
return 'No files to search. Instruct the user to add files for the search.';
|
|
}
|
|
const jwtToken = req.headers.authorization.split(' ')[1];
|
|
if (!jwtToken) {
|
|
return 'There was an error authenticating the file search request.';
|
|
}
|
|
const queryPromises = files.map((file) =>
|
|
axios
|
|
.post(
|
|
`${process.env.RAG_API_URL}/query`,
|
|
{
|
|
file_id: file.file_id,
|
|
query,
|
|
k: 5,
|
|
},
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${jwtToken}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
},
|
|
)
|
|
.catch((error) => {
|
|
logger.error(
|
|
`Error encountered in \`file_search\` while querying file_id ${file._id}:`,
|
|
error,
|
|
);
|
|
return null;
|
|
}),
|
|
);
|
|
|
|
const results = await Promise.all(queryPromises);
|
|
const validResults = results.filter((result) => result !== null);
|
|
|
|
if (validResults.length === 0) {
|
|
return 'No results found or errors occurred while searching the files.';
|
|
}
|
|
|
|
const formattedResults = validResults
|
|
.flatMap((result) =>
|
|
result.data.map(([docInfo, relevanceScore]) => ({
|
|
filename: docInfo.metadata.source.split('/').pop(),
|
|
content: docInfo.page_content,
|
|
relevanceScore,
|
|
})),
|
|
)
|
|
.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
|
|
const formattedString = formattedResults
|
|
.map(
|
|
(result) =>
|
|
`File: ${result.filename}\nRelevance: ${result.relevanceScore.toFixed(4)}\nContent: ${
|
|
result.content
|
|
}\n`,
|
|
)
|
|
.join('\n---\n');
|
|
|
|
return formattedString;
|
|
},
|
|
{
|
|
name: Tools.file_search,
|
|
description: toolDescription,
|
|
schema: z.object({
|
|
query: z
|
|
.string()
|
|
.describe(
|
|
'A natural language query to search for relevant information in the files. Be specific and use keywords related to the information you\'re looking for. The query will be used for semantic similarity matching against the file contents.',
|
|
),
|
|
}),
|
|
},
|
|
);
|
|
|
|
return FileSearch;
|
|
};
|
|
|
|
module.exports = createFileSearchTool;
|