mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-05-13 07:46:47 +00:00
Merge 48887a743d into 6b5596ec36
This commit is contained in:
commit
2b2a7fb99f
2 changed files with 75 additions and 0 deletions
|
|
@ -3,6 +3,16 @@ import { createMCPToolCacheService } from './tools';
|
|||
import type { LCAvailableTools } from './types';
|
||||
import type { MCPToolInput, MCPToolCacheDeps } from './tools';
|
||||
|
||||
jest.mock('@librechat/data-schemas', () => ({
|
||||
...jest.requireActual('@librechat/data-schemas'),
|
||||
logger: {
|
||||
debug: jest.fn(),
|
||||
info: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
function createMockDeps(overrides: Partial<MCPToolCacheDeps> = {}): MCPToolCacheDeps {
|
||||
return {
|
||||
getCachedTools: jest.fn().mockResolvedValue(null),
|
||||
|
|
@ -68,6 +78,49 @@ describe('createMCPToolCacheService', () => {
|
|||
updateMCPServerTools({ userId: 'u1', serverName: 'srv', tools }),
|
||||
).rejects.toThrow('Redis down');
|
||||
});
|
||||
|
||||
it('warns when the composed tool name exceeds the OpenAI 64-char limit', async () => {
|
||||
const { logger } = jest.requireMock('@librechat/data-schemas') as {
|
||||
logger: { warn: jest.Mock; debug: jest.Mock; error: jest.Mock };
|
||||
};
|
||||
logger.warn.mockClear();
|
||||
|
||||
const deps = createMockDeps();
|
||||
const { updateMCPServerTools } = createMCPToolCacheService(deps);
|
||||
|
||||
// 25 + 5 (delimiter "_mcp_") + 40 = 70 > 64
|
||||
const longServerName = 'my-very-long-mcp-server-1';
|
||||
const longToolName = 'execute_extremely_descriptive_action_name';
|
||||
const tools: MCPToolInput[] = [{ name: longToolName }];
|
||||
|
||||
await updateMCPServerTools({
|
||||
userId: 'u1',
|
||||
serverName: longServerName,
|
||||
tools,
|
||||
});
|
||||
|
||||
expect(logger.warn).toHaveBeenCalledTimes(1);
|
||||
const message = logger.warn.mock.calls[0][0] as string;
|
||||
expect(message).toContain(longServerName);
|
||||
expect(message).toContain(longToolName);
|
||||
expect(message).toContain('exceeds');
|
||||
expect(message).toContain('64');
|
||||
});
|
||||
|
||||
it('does not warn for tool names within the OpenAI 64-char limit', async () => {
|
||||
const { logger } = jest.requireMock('@librechat/data-schemas') as {
|
||||
logger: { warn: jest.Mock; debug: jest.Mock; error: jest.Mock };
|
||||
};
|
||||
logger.warn.mockClear();
|
||||
|
||||
const deps = createMockDeps();
|
||||
const { updateMCPServerTools } = createMCPToolCacheService(deps);
|
||||
|
||||
const tools: MCPToolInput[] = [{ name: 'search' }];
|
||||
await updateMCPServerTools({ userId: 'u1', serverName: 'brave', tools });
|
||||
|
||||
expect(logger.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('mergeAppTools', () => {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,18 @@ import { Constants } from 'librechat-data-provider';
|
|||
import type { JsonSchemaType } from '@librechat/agents';
|
||||
import type { LCAvailableTools, LCFunctionTool } from './types';
|
||||
|
||||
/**
|
||||
* Maximum allowed length for tool function names accepted by OpenAI-compatible
|
||||
* Chat Completions / Responses APIs. Tool calls whose names exceed this limit
|
||||
* are rejected with HTTP 400 ("string too long. Expected ... maximum length 64").
|
||||
* MCP tool names are constructed as `${toolName}${mcp_delimiter}${serverName}`,
|
||||
* so callers must keep the combined length within this bound.
|
||||
*
|
||||
* Refs: https://platform.openai.com/docs/api-reference/chat/create
|
||||
* https://github.com/danny-avila/LibreChat/issues/7435
|
||||
*/
|
||||
const MAX_OPENAI_TOOL_NAME_LENGTH = 64;
|
||||
|
||||
export interface MCPToolInput {
|
||||
name: string;
|
||||
description?: string;
|
||||
|
|
@ -40,6 +52,16 @@ export function createMCPToolCacheService(deps: MCPToolCacheDeps) {
|
|||
|
||||
for (const tool of tools) {
|
||||
const name = `${tool.name}${mcpDelimiter}${serverName}`;
|
||||
if (name.length > MAX_OPENAI_TOOL_NAME_LENGTH) {
|
||||
logger.warn(
|
||||
`[MCP Cache] Tool name "${name}" (${name.length} chars) exceeds the ` +
|
||||
`${MAX_OPENAI_TOOL_NAME_LENGTH}-char limit enforced by OpenAI-compatible APIs ` +
|
||||
`(server: "${serverName}", tool: "${tool.name}", delimiter: "${mcpDelimiter}"). ` +
|
||||
`Calls including this tool will be rejected with HTTP 400. ` +
|
||||
`Shorten the MCP server name or the tool name to fit within ` +
|
||||
`${MAX_OPENAI_TOOL_NAME_LENGTH - mcpDelimiter.length} characters combined.`,
|
||||
);
|
||||
}
|
||||
const entry: LCFunctionTool = {
|
||||
type: 'function',
|
||||
['function']: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue