@@ -113,6 +113,7 @@ describe("QdrantVectorStore", () => {
113113 host : "qdrant.ashbyfam.com" ,
114114 https : true ,
115115 port : 443 ,
116+ prefix : undefined , // No prefix for root path
116117 apiKey : undefined ,
117118 headers : {
118119 "User-Agent" : "Roo-Code" ,
@@ -127,6 +128,7 @@ describe("QdrantVectorStore", () => {
127128 host : "example.com" ,
128129 https : true ,
129130 port : 9000 ,
131+ prefix : undefined , // No prefix for root path
130132 apiKey : undefined ,
131133 headers : {
132134 "User-Agent" : "Roo-Code" ,
@@ -145,6 +147,7 @@ describe("QdrantVectorStore", () => {
145147 host : "example.com" ,
146148 https : true ,
147149 port : 443 ,
150+ prefix : "/api/v1" , // Should have prefix
148151 apiKey : undefined ,
149152 headers : {
150153 "User-Agent" : "Roo-Code" ,
@@ -161,6 +164,7 @@ describe("QdrantVectorStore", () => {
161164 host : "example.com" ,
162165 https : false ,
163166 port : 80 ,
167+ prefix : undefined , // No prefix for root path
164168 apiKey : undefined ,
165169 headers : {
166170 "User-Agent" : "Roo-Code" ,
@@ -175,6 +179,7 @@ describe("QdrantVectorStore", () => {
175179 host : "localhost" ,
176180 https : false ,
177181 port : 8080 ,
182+ prefix : undefined , // No prefix for root path
178183 apiKey : undefined ,
179184 headers : {
180185 "User-Agent" : "Roo-Code" ,
@@ -193,6 +198,7 @@ describe("QdrantVectorStore", () => {
193198 host : "example.com" ,
194199 https : false ,
195200 port : 80 ,
201+ prefix : "/api/v1" , // Should have prefix
196202 apiKey : undefined ,
197203 headers : {
198204 "User-Agent" : "Roo-Code" ,
@@ -337,6 +343,159 @@ describe("QdrantVectorStore", () => {
337343 } )
338344 } )
339345
346+ describe ( "URL Prefix Handling" , ( ) => {
347+ it ( "should pass the URL pathname as prefix to QdrantClient if not root" , ( ) => {
348+ const vectorStoreWithPrefix = new QdrantVectorStore (
349+ mockWorkspacePath ,
350+ "http://localhost:6333/some/path" ,
351+ mockVectorSize ,
352+ )
353+ expect ( QdrantClient ) . toHaveBeenLastCalledWith ( {
354+ host : "localhost" ,
355+ https : false ,
356+ port : 6333 ,
357+ prefix : "/some/path" ,
358+ apiKey : undefined ,
359+ headers : {
360+ "User-Agent" : "Roo-Code" ,
361+ } ,
362+ } )
363+ expect ( ( vectorStoreWithPrefix as any ) . qdrantUrl ) . toBe ( "http://localhost:6333/some/path" )
364+ } )
365+
366+ it ( "should not pass prefix if the URL pathname is root ('/')" , ( ) => {
367+ const vectorStoreWithoutPrefix = new QdrantVectorStore (
368+ mockWorkspacePath ,
369+ "http://localhost:6333/" ,
370+ mockVectorSize ,
371+ )
372+ expect ( QdrantClient ) . toHaveBeenLastCalledWith ( {
373+ host : "localhost" ,
374+ https : false ,
375+ port : 6333 ,
376+ prefix : undefined ,
377+ apiKey : undefined ,
378+ headers : {
379+ "User-Agent" : "Roo-Code" ,
380+ } ,
381+ } )
382+ expect ( ( vectorStoreWithoutPrefix as any ) . qdrantUrl ) . toBe ( "http://localhost:6333/" )
383+ } )
384+
385+ it ( "should handle HTTPS URL with path as prefix" , ( ) => {
386+ const vectorStoreWithHttpsPrefix = new QdrantVectorStore (
387+ mockWorkspacePath ,
388+ "https://qdrant.ashbyfam.com/api" ,
389+ mockVectorSize ,
390+ )
391+ expect ( QdrantClient ) . toHaveBeenLastCalledWith ( {
392+ host : "qdrant.ashbyfam.com" ,
393+ https : true ,
394+ port : 443 ,
395+ prefix : "/api" ,
396+ apiKey : undefined ,
397+ headers : {
398+ "User-Agent" : "Roo-Code" ,
399+ } ,
400+ } )
401+ expect ( ( vectorStoreWithHttpsPrefix as any ) . qdrantUrl ) . toBe ( "https://qdrant.ashbyfam.com/api" )
402+ } )
403+
404+ it ( "should normalize URL pathname by removing trailing slash for prefix" , ( ) => {
405+ const vectorStoreWithTrailingSlash = new QdrantVectorStore (
406+ mockWorkspacePath ,
407+ "http://localhost:6333/api/" ,
408+ mockVectorSize ,
409+ )
410+ expect ( QdrantClient ) . toHaveBeenLastCalledWith ( {
411+ host : "localhost" ,
412+ https : false ,
413+ port : 6333 ,
414+ prefix : "/api" , // Trailing slash should be removed
415+ apiKey : undefined ,
416+ headers : {
417+ "User-Agent" : "Roo-Code" ,
418+ } ,
419+ } )
420+ expect ( ( vectorStoreWithTrailingSlash as any ) . qdrantUrl ) . toBe ( "http://localhost:6333/api/" )
421+ } )
422+
423+ it ( "should normalize URL pathname by removing multiple trailing slashes for prefix" , ( ) => {
424+ const vectorStoreWithMultipleTrailingSlashes = new QdrantVectorStore (
425+ mockWorkspacePath ,
426+ "http://localhost:6333/api///" ,
427+ mockVectorSize ,
428+ )
429+ expect ( QdrantClient ) . toHaveBeenLastCalledWith ( {
430+ host : "localhost" ,
431+ https : false ,
432+ port : 6333 ,
433+ prefix : "/api" , // All trailing slashes should be removed
434+ apiKey : undefined ,
435+ headers : {
436+ "User-Agent" : "Roo-Code" ,
437+ } ,
438+ } )
439+ expect ( ( vectorStoreWithMultipleTrailingSlashes as any ) . qdrantUrl ) . toBe ( "http://localhost:6333/api///" )
440+ } )
441+
442+ it ( "should handle multiple path segments correctly for prefix" , ( ) => {
443+ const vectorStoreWithMultiSegment = new QdrantVectorStore (
444+ mockWorkspacePath ,
445+ "http://localhost:6333/api/v1/qdrant" ,
446+ mockVectorSize ,
447+ )
448+ expect ( QdrantClient ) . toHaveBeenLastCalledWith ( {
449+ host : "localhost" ,
450+ https : false ,
451+ port : 6333 ,
452+ prefix : "/api/v1/qdrant" ,
453+ apiKey : undefined ,
454+ headers : {
455+ "User-Agent" : "Roo-Code" ,
456+ } ,
457+ } )
458+ expect ( ( vectorStoreWithMultiSegment as any ) . qdrantUrl ) . toBe ( "http://localhost:6333/api/v1/qdrant" )
459+ } )
460+
461+ it ( "should handle complex URL with multiple segments, multiple trailing slashes, query params, and fragment" , ( ) => {
462+ const complexUrl = "https://example.com/ollama/api/v1///?key=value#pos"
463+ const vectorStoreComplex = new QdrantVectorStore ( mockWorkspacePath , complexUrl , mockVectorSize )
464+ expect ( QdrantClient ) . toHaveBeenLastCalledWith ( {
465+ host : "example.com" ,
466+ https : true ,
467+ port : 443 ,
468+ prefix : "/ollama/api/v1" , // Trailing slash removed, query/fragment ignored
469+ apiKey : undefined ,
470+ headers : {
471+ "User-Agent" : "Roo-Code" ,
472+ } ,
473+ } )
474+ expect ( ( vectorStoreComplex as any ) . qdrantUrl ) . toBe ( complexUrl )
475+ } )
476+
477+ it ( "should ignore query parameters and fragments when determining prefix" , ( ) => {
478+ const vectorStoreWithQueryParams = new QdrantVectorStore (
479+ mockWorkspacePath ,
480+ "http://localhost:6333/api/path?key=value#fragment" ,
481+ mockVectorSize ,
482+ )
483+ expect ( QdrantClient ) . toHaveBeenLastCalledWith ( {
484+ host : "localhost" ,
485+ https : false ,
486+ port : 6333 ,
487+ prefix : "/api/path" , // Query params and fragment should be ignored
488+ apiKey : undefined ,
489+ headers : {
490+ "User-Agent" : "Roo-Code" ,
491+ } ,
492+ } )
493+ expect ( ( vectorStoreWithQueryParams as any ) . qdrantUrl ) . toBe (
494+ "http://localhost:6333/api/path?key=value#fragment" ,
495+ )
496+ } )
497+ } )
498+
340499 describe ( "initialize" , ( ) => {
341500 it ( "should create a new collection if none exists and return true" , async ( ) => {
342501 // Mock getCollection to throw a 404-like error
0 commit comments