@alvinveroy/codecompass
Version:
AI-powered MCP server for codebase navigation and LLM prompt optimization
280 lines (279 loc) • 15.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const vitest_1 = require("vitest");
const llm_provider_1 = require("../lib/llm-provider");
const ollama = __importStar(require("../lib/ollama")); // Mocked
const deepseek = __importStar(require("../lib/deepseek"));
// modelPersistence is removed, configService will be used/mocked for persistence checks
const config_service_1 = require("../lib/config-service");
// Mock the dependencies
vitest_1.vi.mock('../lib/ollama', () => ({
checkOllama: vitest_1.vi.fn(),
generateSuggestion: vitest_1.vi.fn(),
generateEmbedding: vitest_1.vi.fn(),
processFeedback: vitest_1.vi.fn()
}));
vitest_1.vi.mock('../lib/deepseek', () => ({
testDeepSeekConnection: vitest_1.vi.fn(),
generateWithDeepSeek: vitest_1.vi.fn(),
generateEmbeddingWithDeepSeek: vitest_1.vi.fn(),
checkDeepSeekApiKey: vitest_1.vi.fn().mockResolvedValue(true)
}));
// Mock configService for persistence checks
vitest_1.vi.mock('../lib/config-service', async (importOriginal) => {
const actualConfigServiceModule = await importOriginal();
const actualInstance = actualConfigServiceModule.configService; // The real singleton
const mockConfigServiceInstance = {
// Provide constants used by retry-utils and potentially others from the actual instance
OLLAMA_HOST: actualInstance.OLLAMA_HOST,
QDRANT_HOST: actualInstance.QDRANT_HOST,
COLLECTION_NAME: actualInstance.COLLECTION_NAME,
MAX_INPUT_LENGTH: actualInstance.MAX_INPUT_LENGTH,
MAX_SNIPPET_LENGTH: actualInstance.MAX_SNIPPET_LENGTH,
REQUEST_TIMEOUT: actualInstance.REQUEST_TIMEOUT,
MAX_RETRIES: actualInstance.MAX_RETRIES,
RETRY_DELAY: actualInstance.RETRY_DELAY,
CONFIG_DIR: actualInstance.CONFIG_DIR,
MODEL_CONFIG_FILE: actualInstance.MODEL_CONFIG_FILE,
DEEPSEEK_CONFIG_FILE: actualInstance.DEEPSEEK_CONFIG_FILE,
LOG_DIR: actualInstance.LOG_DIR,
DEEPSEEK_RPM_LIMIT_DEFAULT: actualInstance.DEEPSEEK_RPM_LIMIT_DEFAULT,
AGENT_QUERY_TIMEOUT_DEFAULT: actualInstance.AGENT_QUERY_TIMEOUT_DEFAULT,
DEFAULT_MAX_FILE_CONTENT_LENGTH_FOR_CAPABILITY: actualInstance.DEFAULT_MAX_FILE_CONTENT_LENGTH_FOR_CAPABILITY || 10000,
DEFAULT_MAX_DIR_LISTING_ENTRIES_FOR_CAPABILITY: actualInstance.DEFAULT_MAX_DIR_LISTING_ENTRIES_FOR_CAPABILITY || 50,
// Ensure all readonly properties from the actual ConfigService class are here if accessed (getters will handle the actual values)
// For direct value properties in the mock:
MAX_FILE_CONTENT_LENGTH_FOR_CAPABILITY: actualInstance.MAX_FILE_CONTENT_LENGTH_FOR_CAPABILITY || 10000,
MAX_DIR_LISTING_ENTRIES_FOR_CAPABILITY: actualInstance.MAX_DIR_LISTING_ENTRIES_FOR_CAPABILITY || 50,
// Mocked Getters that read from process.env
get SUGGESTION_MODEL() { return String(process.env.SUGGESTION_MODEL ?? 'llama3.1:8b'); },
get SUGGESTION_PROVIDER() { return String(process.env.SUGGESTION_PROVIDER ?? 'ollama'); },
get EMBEDDING_PROVIDER() { return String(process.env.EMBEDDING_PROVIDER ?? 'ollama'); },
get DEEPSEEK_API_KEY() { return String(process.env.DEEPSEEK_API_KEY ?? ''); },
get DEEPSEEK_API_URL() { return String(process.env.DEEPSEEK_API_URL ?? 'https://api.deepseek.com/chat/completions'); },
get DEEPSEEK_MODEL() { return String(process.env.DEEPSEEK_MODEL ?? 'deepseek-coder'); },
get LLM_PROVIDER() { return String(process.env.LLM_PROVIDER ?? 'ollama'); },
// Add other getters if they are accessed by the code under test
// Mocked Methods/Setters
persistModelConfiguration: vitest_1.vi.fn(),
reloadConfigsFromFile: vitest_1.vi.fn(), // Mock this as it might be called by other parts
setSuggestionModel: vitest_1.vi.fn((model) => {
process.env.SUGGESTION_MODEL = model;
global.CURRENT_SUGGESTION_MODEL = model;
}),
setSuggestionProvider: vitest_1.vi.fn((provider) => {
process.env.SUGGESTION_PROVIDER = provider;
process.env.LLM_PROVIDER = provider;
global.CURRENT_SUGGESTION_PROVIDER = provider;
global.CURRENT_LLM_PROVIDER = provider;
}),
setEmbeddingProvider: vitest_1.vi.fn((provider) => {
process.env.EMBEDDING_PROVIDER = provider;
global.CURRENT_EMBEDDING_PROVIDER = provider;
}),
// Add other setters if needed by the code under test
};
return {
...actualConfigServiceModule, // Export other members like 'logger' from the actual module
configService: mockConfigServiceInstance, // Override the configService export
};
});
(0, vitest_1.describe)('LLM Provider', () => {
// Store original environment variable values that might be changed by tests
const originalEnvValues = {};
const envKeysToManage = [
'LLM_PROVIDER',
'SUGGESTION_MODEL',
'SUGGESTION_PROVIDER',
'EMBEDDING_PROVIDER',
'DEEPSEEK_API_KEY', // Include any other env vars potentially modified
'NODE_ENV', // Often set during tests
'VITEST', // Vitest sets this
'TEST_PROVIDER_UNAVAILABLE' // Used in these tests
];
const originalGlobalValues = {
CURRENT_LLM_PROVIDER: global.CURRENT_LLM_PROVIDER,
CURRENT_SUGGESTION_MODEL: global.CURRENT_SUGGESTION_MODEL,
CURRENT_SUGGESTION_PROVIDER: global.CURRENT_SUGGESTION_PROVIDER,
CURRENT_EMBEDDING_PROVIDER: global.CURRENT_EMBEDDING_PROVIDER,
};
(0, vitest_1.beforeEach)(() => {
// Reset mocks before each test
vitest_1.vi.resetAllMocks();
// Save current values and then delete specific environment variables
// This ensures we are modifying the actual process.env object
envKeysToManage.forEach(key => {
originalEnvValues[key] = process.env[key];
delete process.env[key];
});
// Restore NODE_ENV and VITEST as they are needed for test environment detection
if (originalEnvValues['NODE_ENV'])
process.env.NODE_ENV = originalEnvValues['NODE_ENV'];
if (originalEnvValues['VITEST'])
process.env.VITEST = originalEnvValues['VITEST'];
// Reset global variables
global.CURRENT_SUGGESTION_MODEL = undefined;
global.CURRENT_SUGGESTION_PROVIDER = ""; // Ensure it's a string as per type
global.CURRENT_EMBEDDING_PROVIDER = ""; // Ensure it's a string
global.CURRENT_LLM_PROVIDER = ""; // Ensure it's a string
// Clear provider cache
(0, llm_provider_1.clearProviderCache)();
});
(0, vitest_1.afterEach)(() => {
// Restore specific environment variables to their original states
envKeysToManage.forEach(key => {
if (originalEnvValues[key] === undefined) {
delete process.env[key];
}
else {
process.env[key] = originalEnvValues[key];
}
});
// Restore global variables
global.CURRENT_SUGGESTION_MODEL = originalGlobalValues.CURRENT_SUGGESTION_MODEL;
global.CURRENT_SUGGESTION_PROVIDER = originalGlobalValues.CURRENT_SUGGESTION_PROVIDER;
global.CURRENT_EMBEDDING_PROVIDER = originalGlobalValues.CURRENT_EMBEDDING_PROVIDER;
global.CURRENT_LLM_PROVIDER = originalGlobalValues.CURRENT_LLM_PROVIDER;
});
// switchLLMProvider tests are removed as the function is removed.
(0, vitest_1.describe)('switchSuggestionModel', () => {
(0, vitest_1.it)('should switch to deepseek model', async () => {
// Mock the DeepSeek connection test to return true
deepseek.testDeepSeekConnection.mockResolvedValue(true);
deepseek.checkDeepSeekApiKey.mockResolvedValue(true);
// Call the function to switch to DeepSeek model
const result = await (0, llm_provider_1.switchSuggestionModel)('deepseek-coder');
// Verify the result is true (success)
(0, vitest_1.expect)(result).toBe(true);
// Verify that configService methods were called with correct arguments
// eslint-disable-next-line @typescript-eslint/unbound-method
(0, vitest_1.expect)(config_service_1.configService.setSuggestionModel).toHaveBeenCalledWith('deepseek-coder');
// eslint-disable-next-line @typescript-eslint/unbound-method
(0, vitest_1.expect)(config_service_1.configService.setSuggestionProvider).toHaveBeenCalledWith('deepseek');
// Verify the DeepSeek connection was tested
(0, vitest_1.expect)(deepseek.testDeepSeekConnection).toHaveBeenCalled();
// Verify model persistence was called via configService
// eslint-disable-next-line @typescript-eslint/unbound-method
(0, vitest_1.expect)(config_service_1.configService.persistModelConfiguration).toHaveBeenCalled();
});
(0, vitest_1.it)('should switch to ollama model', async () => {
// Mock the Ollama connection test to return true
ollama.checkOllama.mockResolvedValue(true);
// Call the function to switch to Ollama model
const result = await (0, llm_provider_1.switchSuggestionModel)('llama3.1:8b');
// Verify the result is true (success)
(0, vitest_1.expect)(result).toBe(true);
// Verify that configService methods were called with correct arguments
// eslint-disable-next-line @typescript-eslint/unbound-method
(0, vitest_1.expect)(config_service_1.configService.setSuggestionModel).toHaveBeenCalledWith('llama3.1:8b');
// eslint-disable-next-line @typescript-eslint/unbound-method
(0, vitest_1.expect)(config_service_1.configService.setSuggestionProvider).toHaveBeenCalledWith('ollama');
// Verify the Ollama connection was tested
(0, vitest_1.expect)(ollama.checkOllama).toHaveBeenCalled();
// Verify model persistence was called via configService
// eslint-disable-next-line @typescript-eslint/unbound-method
(0, vitest_1.expect)(config_service_1.configService.persistModelConfiguration).toHaveBeenCalled();
});
});
(0, vitest_1.describe)('getLLMProvider', () => {
(0, vitest_1.it)('should return DeepSeek provider when SUGGESTION_PROVIDER is set to deepseek', async () => {
// Set the environment variable
process.env.SUGGESTION_PROVIDER = 'deepseek';
process.env.SUGGESTION_MODEL = 'deepseek-coder';
process.env.NODE_ENV = 'test';
// Mock the DeepSeek connection test
deepseek.testDeepSeekConnection.mockResolvedValue(true);
deepseek.checkDeepSeekApiKey.mockResolvedValue(true);
// Force a call to ensure the spy is registered
await deepseek.testDeepSeekConnection();
// Get the provider
const provider = await (0, llm_provider_1.getLLMProvider)();
// Verify the provider is DeepSeek by checking its methods
(0, vitest_1.expect)(provider).toBeDefined();
(0, vitest_1.expect)(typeof provider.checkConnection).toBe('function');
(0, vitest_1.expect)(typeof provider.generateText).toBe('function');
(0, vitest_1.expect)(typeof provider.generateEmbedding).toBe('function');
// Verify the DeepSeek spy was called
(0, vitest_1.expect)(deepseek.testDeepSeekConnection).toHaveBeenCalled();
// modelPersistence.loadModelConfig is not directly called by getLLMProvider.
// ConfigService handles its own loading.
});
(0, vitest_1.it)('should return Ollama provider when SUGGESTION_PROVIDER is set to ollama', async () => {
// Set the environment variable
process.env.SUGGESTION_PROVIDER = 'ollama';
process.env.SUGGESTION_MODEL = 'llama3.1:8b';
process.env.NODE_ENV = 'test';
// Mock the Ollama connection test
ollama.checkOllama.mockResolvedValue(true);
// Force a call to ensure the spy is registered
await ollama.checkOllama();
// Get the provider
const provider = await (0, llm_provider_1.getLLMProvider)();
// Verify the provider is Ollama by checking its methods
(0, vitest_1.expect)(provider).toBeDefined();
(0, vitest_1.expect)(typeof provider.checkConnection).toBe('function');
(0, vitest_1.expect)(typeof provider.generateText).toBe('function');
(0, vitest_1.expect)(typeof provider.generateEmbedding).toBe('function');
// Verify the Ollama spy was called
(0, vitest_1.expect)(ollama.checkOllama).toHaveBeenCalled();
// modelPersistence.loadModelConfig is not directly called by getLLMProvider.
// ConfigService handles its own loading.
});
(0, vitest_1.it)('should use provider cache when available', async () => {
// Set the environment variable
process.env.SUGGESTION_PROVIDER = 'ollama';
process.env.SUGGESTION_MODEL = 'llama3.1:8b';
process.env.NODE_ENV = 'test';
// Mock the Ollama connection test
ollama.checkOllama.mockResolvedValue(true);
// Clear the cache first to ensure a clean test
(0, llm_provider_1.clearProviderCache)();
// Get the provider first time
await (0, llm_provider_1.getLLMProvider)();
// Reset mocks but don't clear the cache
vitest_1.vi.resetAllMocks();
// Get the provider second time (should use cache)
const provider2 = await (0, llm_provider_1.getLLMProvider)();
// Instead of checking object identity, check that the spy wasn't called again
// This verifies the cache was used
(0, vitest_1.expect)(ollama.checkOllama).not.toHaveBeenCalled();
// And check that the providers have the same methods
(0, vitest_1.expect)(typeof provider2.checkConnection).toBe('function');
(0, vitest_1.expect)(typeof provider2.generateText).toBe('function');
(0, vitest_1.expect)(typeof provider2.generateEmbedding).toBe('function');
});
});
});