Compare commits

...

3 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
18cacca2d0 Fix test for vectorSearchService
Co-authored-by: samanhappy <2755122+samanhappy@users.noreply.github.com>
2025-11-30 12:19:44 +00:00
copilot-swe-agent[bot]
1f19ac392f Fix $smart/group routing to return empty results for empty groups
Co-authored-by: samanhappy <2755122+samanhappy@users.noreply.github.com>
2025-11-30 12:16:15 +00:00
copilot-swe-agent[bot]
840b1b34f1 Initial plan 2025-11-30 12:10:28 +00:00
2 changed files with 139 additions and 0 deletions

View File

@@ -283,6 +283,12 @@ export const searchToolsByVector = async (
}> }>
> => { > => {
try { try {
// If serverNames is an empty array (not undefined), return empty results
// This happens when using $smart/{group} with an empty or non-existent group
if (serverNames !== undefined && serverNames.length === 0) {
return [];
}
const vectorRepository = getRepositoryFactory( const vectorRepository = getRepositoryFactory(
'vectorEmbeddings', 'vectorEmbeddings',
)() as VectorEmbeddingRepository; )() as VectorEmbeddingRepository;

View File

@@ -0,0 +1,133 @@
import { describe, it, expect, jest, beforeEach } from '@jest/globals';
// Mock dependencies before importing vectorSearchService
jest.mock('../../src/db/index.js', () => ({
getRepositoryFactory: jest.fn(() => () => ({
searchByText: jest.fn(),
saveEmbedding: jest.fn(),
})),
}));
jest.mock('../../src/db/connection.js', () => ({
getAppDataSource: jest.fn(() => ({
isInitialized: true,
query: jest.fn(),
})),
initializeDatabase: jest.fn(),
}));
jest.mock('../../src/utils/smartRouting.js', () => ({
getSmartRoutingConfig: jest.fn(() => ({
enabled: true,
openaiApiKey: 'test-key',
openaiApiBaseUrl: 'https://api.openai.com/v1',
openaiApiEmbeddingModel: 'text-embedding-3-small',
})),
}));
jest.mock('openai', () => {
return {
default: jest.fn().mockImplementation(() => ({
apiKey: 'test-key',
embeddings: {
create: jest.fn().mockResolvedValue({
data: [{ embedding: new Array(1536).fill(0.1) }],
}),
},
})),
};
});
// Import after mocks are set up
import { searchToolsByVector } from '../../src/services/vectorSearchService.js';
import { getRepositoryFactory } from '../../src/db/index.js';
describe('vectorSearchService', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('searchToolsByVector', () => {
it('should return empty array when serverNames is an empty array', async () => {
// This test verifies the fix for the $smart/group routing issue
// When serverNames is an empty array (empty group), no results should be returned
const result = await searchToolsByVector('test query', 10, 0.3, []);
// Result should be empty when an empty server list is passed
expect(result).toEqual([]);
});
it('should search all servers when serverNames is undefined', async () => {
const mockSearchResults = [
{
similarity: 0.9,
embedding: {
text_content: 'test tool description',
metadata: JSON.stringify({
serverName: 'server1',
toolName: 'tool1',
description: 'Test tool 1',
inputSchema: {},
}),
},
},
];
const mockRepository = {
searchByText: jest.fn().mockResolvedValue(mockSearchResults),
saveEmbedding: jest.fn(),
};
(getRepositoryFactory as jest.Mock).mockReturnValue(() => mockRepository);
const result = await searchToolsByVector('test query', 10, 0.3, undefined);
// searchByText should be called since serverNames is undefined
expect(mockRepository.searchByText).toHaveBeenCalled();
expect(result.length).toBeGreaterThan(0);
expect(result[0].serverName).toBe('server1');
});
it('should filter results by serverNames when provided', async () => {
const mockSearchResults = [
{
similarity: 0.9,
embedding: {
text_content: 'test tool 1',
metadata: JSON.stringify({
serverName: 'server1',
toolName: 'tool1',
description: 'Test tool 1',
inputSchema: {},
}),
},
},
{
similarity: 0.85,
embedding: {
text_content: 'test tool 2',
metadata: JSON.stringify({
serverName: 'server2',
toolName: 'tool2',
description: 'Test tool 2',
inputSchema: {},
}),
},
},
];
const mockRepository = {
searchByText: jest.fn().mockResolvedValue(mockSearchResults),
saveEmbedding: jest.fn(),
};
(getRepositoryFactory as jest.Mock).mockReturnValue(() => mockRepository);
// Filter to only server1
const result = await searchToolsByVector('test query', 10, 0.3, ['server1']);
expect(result.length).toBe(1);
expect(result[0].serverName).toBe('server1');
});
});
});