| const fs = require('fs'); |
| const path = require('path'); |
| const { Tool } = require('@langchain/core/tools'); |
| const { Calculator } = require('@librechat/agents'); |
| const { logger } = require('@librechat/data-schemas'); |
| const { zodToJsonSchema } = require('zod-to-json-schema'); |
| const { Tools, ImageVisionTool } = require('librechat-data-provider'); |
| const { getToolkitKey, oaiToolkit, ytToolkit } = require('@librechat/api'); |
| const { toolkits } = require('~/app/clients/tools/manifest'); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function loadAndFormatTools({ directory, adminFilter = [], adminIncluded = [] }) { |
| const filter = new Set([...adminFilter]); |
| const included = new Set(adminIncluded); |
| const tools = []; |
| |
| const files = fs.readdirSync(directory); |
|
|
| if (included.size > 0 && adminFilter.length > 0) { |
| logger.warn( |
| 'Both `includedTools` and `filteredTools` are defined; `filteredTools` will be ignored.', |
| ); |
| } |
|
|
| for (const file of files) { |
| const filePath = path.join(directory, file); |
| if (!file.endsWith('.js') || (filter.has(file) && included.size === 0)) { |
| continue; |
| } |
|
|
| let ToolClass = null; |
| try { |
| ToolClass = require(filePath); |
| } catch (error) { |
| logger.error(`[loadAndFormatTools] Error loading tool from ${filePath}:`, error); |
| continue; |
| } |
|
|
| if (!ToolClass || !(ToolClass.prototype instanceof Tool)) { |
| continue; |
| } |
|
|
| let toolInstance = null; |
| try { |
| toolInstance = new ToolClass({ override: true }); |
| } catch (error) { |
| logger.error( |
| `[loadAndFormatTools] Error initializing \`${file}\` tool; if it requires authentication, is the \`override\` field configured?`, |
| error, |
| ); |
| continue; |
| } |
|
|
| if (!toolInstance) { |
| continue; |
| } |
|
|
| if (filter.has(toolInstance.name) && included.size === 0) { |
| continue; |
| } |
|
|
| if (included.size > 0 && !included.has(file) && !included.has(toolInstance.name)) { |
| continue; |
| } |
|
|
| const formattedTool = formatToOpenAIAssistantTool(toolInstance); |
| tools.push(formattedTool); |
| } |
|
|
| const basicToolInstances = [ |
| new Calculator(), |
| ...Object.values(oaiToolkit), |
| ...Object.values(ytToolkit), |
| ]; |
| for (const toolInstance of basicToolInstances) { |
| const formattedTool = formatToOpenAIAssistantTool(toolInstance); |
| let toolName = formattedTool[Tools.function].name; |
| toolName = getToolkitKey({ toolkits, toolName }) ?? toolName; |
| if (filter.has(toolName) && included.size === 0) { |
| continue; |
| } |
|
|
| if (included.size > 0 && !included.has(toolName)) { |
| continue; |
| } |
| tools.push(formattedTool); |
| } |
|
|
| tools.push(ImageVisionTool); |
|
|
| return tools.reduce((map, tool) => { |
| map[tool.function.name] = tool; |
| return map; |
| }, {}); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function formatToOpenAIAssistantTool(tool) { |
| return { |
| type: Tools.function, |
| [Tools.function]: { |
| name: tool.name, |
| description: tool.description, |
| parameters: zodToJsonSchema(tool.schema), |
| }, |
| }; |
| } |
|
|
| module.exports = { |
| loadAndFormatTools, |
| }; |
|
|