mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
🔧 refactor: Optimize Agent Tool Loading and Fix Bedrock Tool Handling (#4641)
* fix: bedrock tool name regex * fix: pass args as single input, attempt json first. * refactor: remove toolMap from agent tool load as is not used * fix: update formatAgentMessages test to use strictEqual for args comparison, testing new behavior
This commit is contained in:
parent
3428c3c647
commit
0c2a583df8
9 changed files with 11 additions and 18 deletions
|
|
@ -120,7 +120,7 @@ describe('formatAgentMessages', () => {
|
||||||
];
|
];
|
||||||
const result = formatAgentMessages(payload);
|
const result = formatAgentMessages(payload);
|
||||||
expect(result).toHaveLength(2);
|
expect(result).toHaveLength(2);
|
||||||
expect(result[0].tool_calls[0].args).toBe('non-json-string');
|
expect(result[0].tool_calls[0].args).toStrictEqual({ input: 'non-json-string' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle complex tool calls with multiple steps', () => {
|
it('should handle complex tool calls with multiple steps', () => {
|
||||||
|
|
|
||||||
|
|
@ -189,10 +189,13 @@ const formatAgentMessages = (payload) => {
|
||||||
// TODO: investigate; args as dictionary may need to be provider-or-tool-specific
|
// TODO: investigate; args as dictionary may need to be provider-or-tool-specific
|
||||||
let args = _args;
|
let args = _args;
|
||||||
try {
|
try {
|
||||||
args = JSON.parse(args);
|
args = JSON.parse(_args);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// failed to parse, leave as is
|
if (typeof _args === 'string') {
|
||||||
|
args = { input: _args };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tool_call.args = args;
|
tool_call.args = args;
|
||||||
lastAIMessage.tool_calls.push(tool_call);
|
lastAIMessage.tool_calls.push(tool_call);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -461,7 +461,6 @@ class AgentClient extends BaseClient {
|
||||||
req: this.options.req,
|
req: this.options.req,
|
||||||
agent: this.options.agent,
|
agent: this.options.agent,
|
||||||
tools: this.options.tools,
|
tools: this.options.tools,
|
||||||
toolMap: this.options.toolMap,
|
|
||||||
runId: this.responseMessageId,
|
runId: this.responseMessageId,
|
||||||
modelOptions: this.modelOptions,
|
modelOptions: this.modelOptions,
|
||||||
customHandlers: this.options.eventHandlers,
|
customHandlers: this.options.eventHandlers,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ const { providerEndpointMap } = require('librechat-data-provider');
|
||||||
* @param {string | undefined} [options.runId] - Optional run ID; otherwise, a new run ID will be generated.
|
* @param {string | undefined} [options.runId] - Optional run ID; otherwise, a new run ID will be generated.
|
||||||
* @param {Agent} options.agent - The agent for this run.
|
* @param {Agent} options.agent - The agent for this run.
|
||||||
* @param {StructuredTool[] | undefined} [options.tools] - The tools to use in the run.
|
* @param {StructuredTool[] | undefined} [options.tools] - The tools to use in the run.
|
||||||
* @param {Record<string, StructuredTool[]> | undefined} [options.toolMap] - The tool map for the run.
|
|
||||||
* @param {Record<GraphEvents, EventHandler> | undefined} [options.customHandlers] - Custom event handlers.
|
* @param {Record<GraphEvents, EventHandler> | undefined} [options.customHandlers] - Custom event handlers.
|
||||||
* @param {ClientOptions} [options.modelOptions] - Optional model to use; if not provided, it will use the default from modelMap.
|
* @param {ClientOptions} [options.modelOptions] - Optional model to use; if not provided, it will use the default from modelMap.
|
||||||
* @param {boolean} [options.streaming=true] - Whether to use streaming.
|
* @param {boolean} [options.streaming=true] - Whether to use streaming.
|
||||||
|
|
@ -29,7 +28,6 @@ async function createRun({
|
||||||
runId,
|
runId,
|
||||||
tools,
|
tools,
|
||||||
agent,
|
agent,
|
||||||
toolMap,
|
|
||||||
modelOptions,
|
modelOptions,
|
||||||
customHandlers,
|
customHandlers,
|
||||||
streaming = true,
|
streaming = true,
|
||||||
|
|
@ -47,7 +45,6 @@ async function createRun({
|
||||||
|
|
||||||
const graphConfig = {
|
const graphConfig = {
|
||||||
tools,
|
tools,
|
||||||
toolMap,
|
|
||||||
llmConfig,
|
llmConfig,
|
||||||
instructions: agent.instructions,
|
instructions: agent.instructions,
|
||||||
additional_instructions: agent.additional_instructions,
|
additional_instructions: agent.additional_instructions,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ const { getLogStores } = require('~/cache');
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
|
|
||||||
const toolNameRegex = /^[a-zA-Z0-9_-]+$/;
|
const toolNameRegex = /^[a-zA-Z0-9_-]+$/;
|
||||||
|
const replaceSeparatorRegex = new RegExp(actionDomainSeparator, 'g');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates tool name against regex pattern and updates if necessary.
|
* Validates tool name against regex pattern and updates if necessary.
|
||||||
|
|
@ -83,8 +84,6 @@ async function domainParser(req, domain, inverse = false) {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
const replaceSeparatorRegex = new RegExp(actionDomainSeparator, 'g');
|
|
||||||
|
|
||||||
if (!cachedDomain) {
|
if (!cachedDomain) {
|
||||||
return domain.replace(replaceSeparatorRegex, '.');
|
return domain.replace(replaceSeparatorRegex, '.');
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +155,7 @@ async function createActionTool({ action, requestBuilder, zodSchema, name, descr
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
return tool(_call, {
|
return tool(_call, {
|
||||||
name,
|
name: name.replace(replaceSeparatorRegex, '_'),
|
||||||
description: description || '',
|
description: description || '',
|
||||||
schema: zodSchema,
|
schema: zodSchema,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ const initializeClient = async ({ req, res, endpointOption }) => {
|
||||||
throw new Error('Agent not found');
|
throw new Error('Agent not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { tools, toolMap } = await loadAgentTools({
|
const { tools } = await loadAgentTools({
|
||||||
req,
|
req,
|
||||||
tools: agent.tools,
|
tools: agent.tools,
|
||||||
agent_id: agent.id,
|
agent_id: agent.id,
|
||||||
|
|
@ -100,7 +100,6 @@ const initializeClient = async ({ req, res, endpointOption }) => {
|
||||||
agent,
|
agent,
|
||||||
tools,
|
tools,
|
||||||
sender,
|
sender,
|
||||||
toolMap,
|
|
||||||
contentParts,
|
contentParts,
|
||||||
modelOptions,
|
modelOptions,
|
||||||
eventHandlers,
|
eventHandlers,
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ const initializeClient = async ({ req, res, endpointOption }) => {
|
||||||
agent,
|
agent,
|
||||||
sender,
|
sender,
|
||||||
// tools,
|
// tools,
|
||||||
// toolMap,
|
|
||||||
modelOptions,
|
modelOptions,
|
||||||
contentParts,
|
contentParts,
|
||||||
eventHandlers,
|
eventHandlers,
|
||||||
|
|
|
||||||
|
|
@ -373,14 +373,14 @@ async function processRequiredActions(client, requiredActions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes the runtime tool calls and returns a combined toolMap.
|
* Processes the runtime tool calls and returns the tool classes.
|
||||||
* @param {Object} params - Run params containing user and request information.
|
* @param {Object} params - Run params containing user and request information.
|
||||||
* @param {ServerRequest} params.req - The request object.
|
* @param {ServerRequest} params.req - The request object.
|
||||||
* @param {string} params.agent_id - The agent ID.
|
* @param {string} params.agent_id - The agent ID.
|
||||||
* @param {Agent['tools']} params.tools - The agent's available tools.
|
* @param {Agent['tools']} params.tools - The agent's available tools.
|
||||||
* @param {Agent['tool_resources']} params.tool_resources - The agent's available tool resources.
|
* @param {Agent['tool_resources']} params.tool_resources - The agent's available tool resources.
|
||||||
* @param {string | undefined} [params.openAIApiKey] - The OpenAI API key.
|
* @param {string | undefined} [params.openAIApiKey] - The OpenAI API key.
|
||||||
* @returns {Promise<{ tools?: StructuredTool[]; toolMap?: Record<string, StructuredTool>}>} The combined toolMap.
|
* @returns {Promise<{ tools?: StructuredTool[] }>} The agent tools.
|
||||||
*/
|
*/
|
||||||
async function loadAgentTools({ req, agent_id, tools, tool_resources, openAIApiKey }) {
|
async function loadAgentTools({ req, agent_id, tools, tool_resources, openAIApiKey }) {
|
||||||
if (!tools || tools.length === 0) {
|
if (!tools || tools.length === 0) {
|
||||||
|
|
@ -482,10 +482,8 @@ async function loadAgentTools({ req, agent_id, tools, tool_resources, openAIApiK
|
||||||
throw new Error('No tools found for the specified tool calls.');
|
throw new Error('No tools found for the specified tool calls.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const toolMap = { ...ToolMap, ...ActionToolMap };
|
|
||||||
return {
|
return {
|
||||||
tools: agentTools,
|
tools: agentTools,
|
||||||
toolMap,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -958,7 +958,6 @@
|
||||||
* @property {Object} [headers] - Additional headers for requests
|
* @property {Object} [headers] - Additional headers for requests
|
||||||
* @property {string} [proxy] - Proxy configuration
|
* @property {string} [proxy] - Proxy configuration
|
||||||
* @property {Object} [tools] - Available tools for the agent
|
* @property {Object} [tools] - Available tools for the agent
|
||||||
* @property {Object} [toolMap] - Mapping of tool configurations
|
|
||||||
* @property {Object} [eventHandlers] - Custom event handlers
|
* @property {Object} [eventHandlers] - Custom event handlers
|
||||||
* @property {Object} [addParams] - Additional parameters to add to requests
|
* @property {Object} [addParams] - Additional parameters to add to requests
|
||||||
* @property {string[]} [dropParams] - Parameters to remove from requests
|
* @property {string[]} [dropParams] - Parameters to remove from requests
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue