diff --git a/src/services/code-index/__tests__/config-manager.spec.ts b/src/services/code-index/__tests__/config-manager.spec.ts index 9fc096ba742b..089e039ff8f7 100644 --- a/src/services/code-index/__tests__/config-manager.spec.ts +++ b/src/services/code-index/__tests__/config-manager.spec.ts @@ -1807,6 +1807,124 @@ describe("CodeIndexConfigManager", () => { // Should return undefined since custom dimension is invalid expect(configManager.currentModelDimension).toBe(undefined) }) + + describe("OpenRouter provider dimension handling", () => { + it("should correctly handle OpenRouter mistral model dimensions across restarts", async () => { + // Mock getModelDimension to return correct dimensions for OpenRouter models + mockedGetModelDimension.mockImplementation((provider, modelId) => { + if (provider === "openrouter") { + if (modelId === "mistralai/codestral-embed-2505") return 1536 + if (modelId === "mistralai/mistral-embed-2312") return 1024 + if (modelId === "openai/text-embedding-3-large") return 3072 + } + return undefined + }) + + // Initial configuration with OpenRouter and Mistral model + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexEmbedderProvider: "openrouter", + codebaseIndexEmbedderModelId: "mistralai/codestral-embed-2505", + codebaseIndexQdrantUrl: "http://localhost:6333", + }) + mockContextProxy.getSecret.mockImplementation((key: string) => { + if (key === "codebaseIndexOpenRouterApiKey") return "test-openrouter-key" + if (key === "codeIndexQdrantApiKey") return "test-qdrant-key" + return undefined + }) + + configManager = new CodeIndexConfigManager(mockContextProxy) + await configManager.loadConfiguration() + + // Should correctly return the built-in dimension for the Mistral model + expect(configManager.currentModelDimension).toBe(1536) + expect(mockedGetModelDimension).toHaveBeenCalledWith("openrouter", "mistralai/codestral-embed-2505") + + // Simulate restart by creating a new config manager with same configuration + const restartConfigManager = new CodeIndexConfigManager(mockContextProxy) + await restartConfigManager.loadConfiguration() + + // After "restart", dimension should still be correct + expect(restartConfigManager.currentModelDimension).toBe(1536) + expect(restartConfigManager.isFeatureConfigured).toBe(true) + }) + + it("should not require restart for OpenRouter when same model dimensions are used", async () => { + // Mock both models to have same dimension + mockedGetModelDimension.mockImplementation((provider, modelId) => { + if (provider === "openrouter") { + if (modelId === "mistralai/codestral-embed-2505") return 1536 + if (modelId === "openai/text-embedding-3-small") return 1536 + } + return undefined + }) + + // Initial state with OpenRouter and Mistral model + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexEmbedderProvider: "openrouter", + codebaseIndexEmbedderModelId: "mistralai/codestral-embed-2505", + codebaseIndexQdrantUrl: "http://localhost:6333", + }) + mockContextProxy.getSecret.mockImplementation((key: string) => { + if (key === "codebaseIndexOpenRouterApiKey") return "test-key" + if (key === "codeIndexQdrantApiKey") return "test-key" + return undefined + }) + + await configManager.loadConfiguration() + + // Change to another model with same dimension + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexEmbedderProvider: "openrouter", + codebaseIndexEmbedderModelId: "openai/text-embedding-3-small", // Same 1536 dimension + codebaseIndexQdrantUrl: "http://localhost:6333", + }) + + const result = await configManager.loadConfiguration() + // Should NOT require restart since dimensions are the same + expect(result.requiresRestart).toBe(false) + }) + + it("should require restart for OpenRouter when model dimensions change", async () => { + // Mock models with different dimensions + mockedGetModelDimension.mockImplementation((provider, modelId) => { + if (provider === "openrouter") { + if (modelId === "mistralai/codestral-embed-2505") return 1536 + if (modelId === "mistralai/mistral-embed-2312") return 1024 + } + return undefined + }) + + // Initial state with 1536-dimension model + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexEmbedderProvider: "openrouter", + codebaseIndexEmbedderModelId: "mistralai/codestral-embed-2505", + codebaseIndexQdrantUrl: "http://localhost:6333", + }) + mockContextProxy.getSecret.mockImplementation((key: string) => { + if (key === "codebaseIndexOpenRouterApiKey") return "test-key" + if (key === "codeIndexQdrantApiKey") return "test-key" + return undefined + }) + + await configManager.loadConfiguration() + + // Change to model with different dimension + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexEmbedderProvider: "openrouter", + codebaseIndexEmbedderModelId: "mistralai/mistral-embed-2312", // Different 1024 dimension + codebaseIndexQdrantUrl: "http://localhost:6333", + }) + + const result = await configManager.loadConfiguration() + // Should require restart since dimensions changed + expect(result.requiresRestart).toBe(true) + }) + }) }) }) }) diff --git a/src/shared/embeddingModels.ts b/src/shared/embeddingModels.ts index 8c2f8fd44c7e..14015c80dbf7 100644 --- a/src/shared/embeddingModels.ts +++ b/src/shared/embeddingModels.ts @@ -86,7 +86,7 @@ export const EMBEDDING_MODEL_PROFILES: EmbeddingModelProfiles = { "google/gemini-embedding-001": { dimension: 3072, scoreThreshold: 0.4 }, // Mistral models via OpenRouter "mistralai/mistral-embed-2312": { dimension: 1024, scoreThreshold: 0.4 }, - "mistralai/codestral-embed-2505": { dimension: 3072, scoreThreshold: 0.4 }, + "mistralai/codestral-embed-2505": { dimension: 1536, scoreThreshold: 0.4 }, // Qwen models via OpenRouter "qwen/qwen3-embedding-8b": { dimension: 4096, scoreThreshold: 0.4 }, },