@mastra/qdrant 0.2.13-alpha.0 → 0.2.13-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +12 -0
- package/dist/index.cjs +16 -7
- package/dist/index.js +16 -7
- package/package.json +2 -2
- package/src/vector/index.test.ts +70 -2
- package/src/vector/index.ts +19 -8
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @mastra/qdrant@0.2.13-alpha.
|
|
2
|
+
> @mastra/qdrant@0.2.13-alpha.1 build /home/runner/work/mastra/mastra/stores/qdrant
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
6
6
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
7
|
[34mCLI[39m tsup v8.4.0
|
|
8
8
|
[34mTSC[39m Build start
|
|
9
|
-
[32mTSC[39m ⚡️ Build success in
|
|
9
|
+
[32mTSC[39m ⚡️ Build success in 7868ms
|
|
10
10
|
[34mDTS[39m Build start
|
|
11
11
|
[34mCLI[39m Target: es2022
|
|
12
12
|
Analysis will use the bundled TypeScript version 5.8.3
|
|
13
13
|
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/qdrant/dist/_tsup-dts-rollup.d.ts[39m
|
|
14
14
|
Analysis will use the bundled TypeScript version 5.8.3
|
|
15
15
|
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/qdrant/dist/_tsup-dts-rollup.d.cts[39m
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 9052ms
|
|
17
17
|
[34mCLI[39m Cleaning output folder
|
|
18
18
|
[34mESM[39m Build start
|
|
19
19
|
[34mCJS[39m Build start
|
|
20
|
-
[32mCJS[39m [1mdist/index.cjs [22m[
|
|
21
|
-
[32mCJS[39m ⚡️ Build success in
|
|
22
|
-
[32mESM[39m [1mdist/index.js [22m[32m16.
|
|
23
|
-
[32mESM[39m ⚡️ Build success in
|
|
20
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m17.03 KB[39m
|
|
21
|
+
[32mCJS[39m ⚡️ Build success in 961ms
|
|
22
|
+
[32mESM[39m [1mdist/index.js [22m[32m16.97 KB[39m
|
|
23
|
+
[32mESM[39m ⚡️ Build success in 962ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @mastra/qdrant
|
|
2
2
|
|
|
3
|
+
## 0.2.13-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9cd1a46: [MASTRA-3338] update naming scheme for embedding index based on vector store rules and added duplicate index checks
|
|
8
|
+
- Updated dependencies [e450778]
|
|
9
|
+
- Updated dependencies [8902157]
|
|
10
|
+
- Updated dependencies [ca0dc88]
|
|
11
|
+
- Updated dependencies [9cd1a46]
|
|
12
|
+
- Updated dependencies [70dbf51]
|
|
13
|
+
- @mastra/core@0.9.3-alpha.1
|
|
14
|
+
|
|
3
15
|
## 0.2.13-alpha.0
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -279,14 +279,23 @@ var QdrantVector = class extends vector.MastraVector {
|
|
|
279
279
|
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
280
280
|
throw new Error("Dimension must be a positive integer");
|
|
281
281
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
282
|
+
if (!DISTANCE_MAPPING[metric]) {
|
|
283
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
await this.client.createCollection(indexName, {
|
|
287
|
+
vectors: {
|
|
288
|
+
size: dimension,
|
|
289
|
+
distance: DISTANCE_MAPPING[metric]
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
} catch (error) {
|
|
293
|
+
const message = error?.message || error?.toString();
|
|
294
|
+
if (error?.status === 409 || typeof message === "string" && message.toLowerCase().includes("exists")) {
|
|
295
|
+
await this.validateExistingIndex(indexName, dimension, metric);
|
|
296
|
+
return;
|
|
288
297
|
}
|
|
289
|
-
}
|
|
298
|
+
}
|
|
290
299
|
}
|
|
291
300
|
transformFilter(filter) {
|
|
292
301
|
const translator = new QdrantFilterTranslator();
|
package/dist/index.js
CHANGED
|
@@ -277,14 +277,23 @@ var QdrantVector = class extends MastraVector {
|
|
|
277
277
|
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
278
278
|
throw new Error("Dimension must be a positive integer");
|
|
279
279
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
280
|
+
if (!DISTANCE_MAPPING[metric]) {
|
|
281
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
await this.client.createCollection(indexName, {
|
|
285
|
+
vectors: {
|
|
286
|
+
size: dimension,
|
|
287
|
+
distance: DISTANCE_MAPPING[metric]
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
} catch (error) {
|
|
291
|
+
const message = error?.message || error?.toString();
|
|
292
|
+
if (error?.status === 409 || typeof message === "string" && message.toLowerCase().includes("exists")) {
|
|
293
|
+
await this.validateExistingIndex(indexName, dimension, metric);
|
|
294
|
+
return;
|
|
286
295
|
}
|
|
287
|
-
}
|
|
296
|
+
}
|
|
288
297
|
}
|
|
289
298
|
transformFilter(filter) {
|
|
290
299
|
const translator = new QdrantFilterTranslator();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/qdrant",
|
|
3
|
-
"version": "0.2.13-alpha.
|
|
3
|
+
"version": "0.2.13-alpha.1",
|
|
4
4
|
"description": "Qdrant vector store provider for Mastra",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@qdrant/js-client-rest": "^1.13.0",
|
|
24
|
-
"@mastra/core": "^0.9.3-alpha.
|
|
24
|
+
"@mastra/core": "^0.9.3-alpha.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@microsoft/api-extractor": "^7.52.5",
|
package/src/vector/index.test.ts
CHANGED
|
@@ -184,8 +184,8 @@ describe('QdrantVector', () => {
|
|
|
184
184
|
// expect(results[0]?.vector).toEqual(newVector);
|
|
185
185
|
});
|
|
186
186
|
|
|
187
|
-
it('should throw exception when no updates are given', () => {
|
|
188
|
-
expect(qdrant.updateIndexById(testCollectionName, 'id', {})).rejects.toThrow('No updates provided');
|
|
187
|
+
it('should throw exception when no updates are given', async () => {
|
|
188
|
+
await expect(qdrant.updateIndexById(testCollectionName, 'id', {})).rejects.toThrow('No updates provided');
|
|
189
189
|
});
|
|
190
190
|
|
|
191
191
|
it('should throw error for non-existent index', async () => {
|
|
@@ -755,6 +755,15 @@ describe('QdrantVector', () => {
|
|
|
755
755
|
});
|
|
756
756
|
});
|
|
757
757
|
describe('Error Handling', () => {
|
|
758
|
+
const testIndexName = 'test_index_error';
|
|
759
|
+
beforeAll(async () => {
|
|
760
|
+
await qdrant.createIndex({ indexName: testIndexName, dimension: 3 });
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
afterAll(async () => {
|
|
764
|
+
await qdrant.deleteIndex(testIndexName);
|
|
765
|
+
});
|
|
766
|
+
|
|
758
767
|
it('should handle non-existent index query gracefully', async () => {
|
|
759
768
|
const nonExistentIndex = 'non-existent-index';
|
|
760
769
|
await expect(qdrant.query({ indexName: nonExistentIndex, queryVector: [1, 0, 0] })).rejects.toThrow();
|
|
@@ -764,6 +773,65 @@ describe('QdrantVector', () => {
|
|
|
764
773
|
const wrongDimVector = [[1, 0]]; // 2D vector for 3D index
|
|
765
774
|
await expect(qdrant.upsert({ indexName: testCollectionName, vectors: wrongDimVector })).rejects.toThrow();
|
|
766
775
|
}, 50000);
|
|
776
|
+
|
|
777
|
+
it('should handle mismatched metadata and vectors length', async () => {
|
|
778
|
+
const vectors = [[1, 2, 3]];
|
|
779
|
+
const metadata = [{}, {}];
|
|
780
|
+
await expect(qdrant.upsert({ indexName: testCollectionName, vectors, metadata })).rejects.toThrow();
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
it('should handle duplicate index creation gracefully', async () => {
|
|
784
|
+
const duplicateIndexName = `duplicate_test`;
|
|
785
|
+
const dimension = 768;
|
|
786
|
+
const infoSpy = vi.spyOn(qdrant['logger'], 'info');
|
|
787
|
+
const warnSpy = vi.spyOn(qdrant['logger'], 'warn');
|
|
788
|
+
try {
|
|
789
|
+
// Create index first time
|
|
790
|
+
await qdrant.createIndex({
|
|
791
|
+
indexName: duplicateIndexName,
|
|
792
|
+
dimension,
|
|
793
|
+
metric: 'cosine',
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
// Try to create with same dimensions - should not throw
|
|
797
|
+
await expect(
|
|
798
|
+
qdrant.createIndex({
|
|
799
|
+
indexName: duplicateIndexName,
|
|
800
|
+
dimension,
|
|
801
|
+
metric: 'cosine',
|
|
802
|
+
}),
|
|
803
|
+
).resolves.not.toThrow();
|
|
804
|
+
|
|
805
|
+
expect(infoSpy).toHaveBeenCalledWith(expect.stringContaining('already exists with'));
|
|
806
|
+
|
|
807
|
+
// Try to create with same dimensions and different metric - should not throw
|
|
808
|
+
await expect(
|
|
809
|
+
qdrant.createIndex({
|
|
810
|
+
indexName: duplicateIndexName,
|
|
811
|
+
dimension,
|
|
812
|
+
metric: 'euclidean',
|
|
813
|
+
}),
|
|
814
|
+
).resolves.not.toThrow();
|
|
815
|
+
|
|
816
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Attempted to create index with metric'));
|
|
817
|
+
|
|
818
|
+
// Try to create with different dimensions - should throw
|
|
819
|
+
await expect(
|
|
820
|
+
qdrant.createIndex({
|
|
821
|
+
indexName: duplicateIndexName,
|
|
822
|
+
dimension: dimension + 1,
|
|
823
|
+
metric: 'cosine',
|
|
824
|
+
}),
|
|
825
|
+
).rejects.toThrow(
|
|
826
|
+
`Index "${duplicateIndexName}" already exists with ${dimension} dimensions, but ${dimension + 1} dimensions were requested`,
|
|
827
|
+
);
|
|
828
|
+
} finally {
|
|
829
|
+
infoSpy.mockRestore();
|
|
830
|
+
warnSpy.mockRestore();
|
|
831
|
+
// Cleanup
|
|
832
|
+
await qdrant.deleteIndex(duplicateIndexName);
|
|
833
|
+
}
|
|
834
|
+
});
|
|
767
835
|
});
|
|
768
836
|
|
|
769
837
|
describe('Empty/Undefined Filters', () => {
|
package/src/vector/index.ts
CHANGED
|
@@ -75,14 +75,25 @@ export class QdrantVector extends MastraVector {
|
|
|
75
75
|
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
76
76
|
throw new Error('Dimension must be a positive integer');
|
|
77
77
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
if (!DISTANCE_MAPPING[metric]) {
|
|
79
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
await this.client.createCollection(indexName, {
|
|
83
|
+
vectors: {
|
|
84
|
+
size: dimension,
|
|
85
|
+
distance: DISTANCE_MAPPING[metric],
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
} catch (error: any) {
|
|
89
|
+
const message = error?.message || error?.toString();
|
|
90
|
+
// Qdrant typically returns 409 for existing collection
|
|
91
|
+
if (error?.status === 409 || (typeof message === 'string' && message.toLowerCase().includes('exists'))) {
|
|
92
|
+
// Fetch collection info and check dimension
|
|
93
|
+
await this.validateExistingIndex(indexName, dimension, metric);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
transformFilter(filter?: VectorFilter) {
|