@@ -4,13 +4,15 @@ import { OpenAiEmbedder } from "../embedders/openai"
44import { CodeIndexOllamaEmbedder } from "../embedders/ollama"
55import { OpenAICompatibleEmbedder } from "../embedders/openai-compatible"
66import { GeminiEmbedder } from "../embedders/gemini"
7+ import { CodeIndexLmStudioEmbedder } from "../embedders/lmstudio"
78import { QdrantVectorStore } from "../vector-store/qdrant-client"
89
910// Mock the embedders and vector store
1011vitest . mock ( "../embedders/openai" )
1112vitest . mock ( "../embedders/ollama" )
1213vitest . mock ( "../embedders/openai-compatible" )
1314vitest . mock ( "../embedders/gemini" )
15+ vitest . mock ( "../embedders/lmstudio" )
1416vitest . mock ( "../vector-store/qdrant-client" )
1517
1618// Mock the embedding models module
@@ -23,6 +25,7 @@ const MockedOpenAiEmbedder = OpenAiEmbedder as MockedClass<typeof OpenAiEmbedder
2325const MockedCodeIndexOllamaEmbedder = CodeIndexOllamaEmbedder as MockedClass < typeof CodeIndexOllamaEmbedder >
2426const MockedOpenAICompatibleEmbedder = OpenAICompatibleEmbedder as MockedClass < typeof OpenAICompatibleEmbedder >
2527const MockedGeminiEmbedder = GeminiEmbedder as MockedClass < typeof GeminiEmbedder >
28+ const MockedCodeIndexLmStudioEmbedder = CodeIndexLmStudioEmbedder as MockedClass < typeof CodeIndexLmStudioEmbedder >
2629const MockedQdrantVectorStore = QdrantVectorStore as MockedClass < typeof QdrantVectorStore >
2730
2831// Import the mocked functions
@@ -299,6 +302,77 @@ describe("CodeIndexServiceFactory", () => {
299302 expect ( ( ) => factory . createEmbedder ( ) ) . toThrow ( "serviceFactory.geminiConfigMissing" )
300303 } )
301304
305+ it ( "should pass model ID to LM Studio embedder when using LM Studio provider" , ( ) => {
306+ // Arrange
307+ const testModelId = "nomic-embed-text-v1.5"
308+ const testConfig = {
309+ embedderProvider : "lmstudio" ,
310+ modelId : testModelId ,
311+ lmStudioOptions : {
312+ lmStudioBaseUrl : "http://localhost:1234" ,
313+ } ,
314+ }
315+ mockConfigManager . getConfig . mockReturnValue ( testConfig as any )
316+
317+ // Act
318+ factory . createEmbedder ( )
319+
320+ // Assert
321+ expect ( MockedCodeIndexLmStudioEmbedder ) . toHaveBeenCalledWith ( {
322+ lmStudioBaseUrl : "http://localhost:1234" ,
323+ lmStudioModelId : testModelId ,
324+ } )
325+ } )
326+
327+ it ( "should handle undefined model ID for LM Studio embedder" , ( ) => {
328+ // Arrange
329+ const testConfig = {
330+ embedderProvider : "lmstudio" ,
331+ modelId : undefined ,
332+ lmStudioOptions : {
333+ lmStudioBaseUrl : "http://localhost:1234" ,
334+ } ,
335+ }
336+ mockConfigManager . getConfig . mockReturnValue ( testConfig as any )
337+
338+ // Act
339+ factory . createEmbedder ( )
340+
341+ // Assert
342+ expect ( MockedCodeIndexLmStudioEmbedder ) . toHaveBeenCalledWith ( {
343+ lmStudioBaseUrl : "http://localhost:1234" ,
344+ lmStudioModelId : undefined ,
345+ } )
346+ } )
347+
348+ it ( "should throw error when LM Studio base URL is missing" , ( ) => {
349+ // Arrange
350+ const testConfig = {
351+ embedderProvider : "lmstudio" ,
352+ modelId : "nomic-embed-text-v1.5" ,
353+ lmStudioOptions : {
354+ lmStudioBaseUrl : undefined ,
355+ } ,
356+ }
357+ mockConfigManager . getConfig . mockReturnValue ( testConfig as any )
358+
359+ // Act & Assert
360+ expect ( ( ) => factory . createEmbedder ( ) ) . toThrow ( "LM Studio configuration missing for embedder creation" )
361+ } )
362+
363+ it ( "should throw error when LM Studio options are missing" , ( ) => {
364+ // Arrange
365+ const testConfig = {
366+ embedderProvider : "lmstudio" ,
367+ modelId : "nomic-embed-text-v1.5" ,
368+ lmStudioOptions : undefined ,
369+ }
370+ mockConfigManager . getConfig . mockReturnValue ( testConfig as any )
371+
372+ // Act & Assert
373+ expect ( ( ) => factory . createEmbedder ( ) ) . toThrow ( "LM Studio configuration missing for embedder creation" )
374+ } )
375+
302376 it ( "should throw error for invalid embedder provider" , ( ) => {
303377 // Arrange
304378 const testConfig = {
@@ -522,6 +596,31 @@ describe("CodeIndexServiceFactory", () => {
522596 )
523597 } )
524598
599+ it ( "should use config.modelId for LM Studio provider" , ( ) => {
600+ // Arrange
601+ const testModelId = "nomic-embed-text-v1.5"
602+ const testConfig = {
603+ embedderProvider : "lmstudio" ,
604+ modelId : testModelId ,
605+ qdrantUrl : "http://localhost:6333" ,
606+ qdrantApiKey : "test-key" ,
607+ }
608+ mockConfigManager . getConfig . mockReturnValue ( testConfig as any )
609+ mockGetModelDimension . mockReturnValue ( 768 )
610+
611+ // Act
612+ factory . createVectorStore ( )
613+
614+ // Assert
615+ expect ( mockGetModelDimension ) . toHaveBeenCalledWith ( "lmstudio" , testModelId )
616+ expect ( MockedQdrantVectorStore ) . toHaveBeenCalledWith (
617+ "/test/workspace" ,
618+ "http://localhost:6333" ,
619+ 768 ,
620+ "test-key" ,
621+ )
622+ } )
623+
525624 it ( "should use default model when config.modelId is undefined" , ( ) => {
526625 // Arrange
527626 const testConfig = {
0 commit comments