@mastra/qdrant 0.10.3 → 0.10.4-alpha.0
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 +13 -0
- package/dist/index.cjs +164 -56
- package/dist/index.js +159 -51
- package/package.json +2 -2
- package/src/vector/index.ts +167 -57
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @mastra/qdrant@0.10.
|
|
2
|
+
> @mastra/qdrant@0.10.4-alpha.0 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.5.0
|
|
8
8
|
[34mTSC[39m Build start
|
|
9
|
-
[32mTSC[39m ⚡️ Build success in
|
|
9
|
+
[32mTSC[39m ⚡️ Build success in 7453ms
|
|
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 9897ms
|
|
17
17
|
[34mCLI[39m Cleaning output folder
|
|
18
18
|
[34mESM[39m Build start
|
|
19
19
|
[34mCJS[39m Build start
|
|
20
|
-
[
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
[
|
|
20
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m21.22 KB[39m
|
|
21
|
+
[32mCJS[39m ⚡️ Build success in 959ms
|
|
22
|
+
[32mESM[39m [1mdist/index.js [22m[32m20.99 KB[39m
|
|
23
|
+
[32mESM[39m ⚡️ Build success in 962ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @mastra/qdrant
|
|
2
2
|
|
|
3
|
+
## 0.10.4-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0e17048: Throw mastra errors in storage packages
|
|
8
|
+
- Updated dependencies [d1baedb]
|
|
9
|
+
- Updated dependencies [4d21bf2]
|
|
10
|
+
- Updated dependencies [2097952]
|
|
11
|
+
- Updated dependencies [4fb0cc2]
|
|
12
|
+
- Updated dependencies [d2a7a31]
|
|
13
|
+
- Updated dependencies [0e17048]
|
|
14
|
+
- @mastra/core@0.10.7-alpha.1
|
|
15
|
+
|
|
3
16
|
## 0.10.3
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var error = require('@mastra/core/error');
|
|
3
4
|
var vector = require('@mastra/core/vector');
|
|
4
5
|
var jsClientRest = require('@qdrant/js-client-rest');
|
|
5
6
|
var filter = require('@mastra/core/vector/filter');
|
|
@@ -267,22 +268,46 @@ var QdrantVector = class extends vector.MastraVector {
|
|
|
267
268
|
vector,
|
|
268
269
|
payload: metadata?.[i] || {}
|
|
269
270
|
}));
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
271
|
+
try {
|
|
272
|
+
for (let i = 0; i < records.length; i += BATCH_SIZE) {
|
|
273
|
+
const batch = records.slice(i, i + BATCH_SIZE);
|
|
274
|
+
await this.client.upsert(indexName, {
|
|
275
|
+
// @ts-expect-error
|
|
276
|
+
points: batch,
|
|
277
|
+
wait: true
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return pointIds;
|
|
281
|
+
} catch (error$1) {
|
|
282
|
+
throw new error.MastraError(
|
|
283
|
+
{
|
|
284
|
+
id: "STORAGE_QDRANT_VECTOR_UPSERT_FAILED",
|
|
285
|
+
domain: error.ErrorDomain.STORAGE,
|
|
286
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
287
|
+
details: { indexName, vectorCount: vectors.length }
|
|
288
|
+
},
|
|
289
|
+
error$1
|
|
290
|
+
);
|
|
277
291
|
}
|
|
278
|
-
return pointIds;
|
|
279
292
|
}
|
|
280
293
|
async createIndex({ indexName, dimension, metric = "cosine" }) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
294
|
+
try {
|
|
295
|
+
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
296
|
+
throw new Error("Dimension must be a positive integer");
|
|
297
|
+
}
|
|
298
|
+
if (!DISTANCE_MAPPING[metric]) {
|
|
299
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
300
|
+
}
|
|
301
|
+
} catch (validationError) {
|
|
302
|
+
throw new error.MastraError(
|
|
303
|
+
{
|
|
304
|
+
id: "STORAGE_QDRANT_VECTOR_CREATE_INDEX_INVALID_ARGS",
|
|
305
|
+
domain: error.ErrorDomain.STORAGE,
|
|
306
|
+
category: error.ErrorCategory.USER,
|
|
307
|
+
details: { indexName, dimension, metric }
|
|
308
|
+
},
|
|
309
|
+
validationError
|
|
310
|
+
);
|
|
286
311
|
}
|
|
287
312
|
try {
|
|
288
313
|
await this.client.createCollection(indexName, {
|
|
@@ -291,12 +316,21 @@ var QdrantVector = class extends vector.MastraVector {
|
|
|
291
316
|
distance: DISTANCE_MAPPING[metric]
|
|
292
317
|
}
|
|
293
318
|
});
|
|
294
|
-
} catch (error) {
|
|
295
|
-
const message = error?.message || error?.toString();
|
|
296
|
-
if (error?.status === 409 || typeof message === "string" && message.toLowerCase().includes("exists")) {
|
|
319
|
+
} catch (error$1) {
|
|
320
|
+
const message = error$1?.message || error$1?.toString();
|
|
321
|
+
if (error$1?.status === 409 || typeof message === "string" && message.toLowerCase().includes("exists")) {
|
|
297
322
|
await this.validateExistingIndex(indexName, dimension, metric);
|
|
298
323
|
return;
|
|
299
324
|
}
|
|
325
|
+
throw new error.MastraError(
|
|
326
|
+
{
|
|
327
|
+
id: "STORAGE_QDRANT_VECTOR_CREATE_INDEX_FAILED",
|
|
328
|
+
domain: error.ErrorDomain.STORAGE,
|
|
329
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
330
|
+
details: { indexName, dimension, metric }
|
|
331
|
+
},
|
|
332
|
+
error$1
|
|
333
|
+
);
|
|
300
334
|
}
|
|
301
335
|
}
|
|
302
336
|
transformFilter(filter) {
|
|
@@ -311,33 +345,56 @@ var QdrantVector = class extends vector.MastraVector {
|
|
|
311
345
|
includeVector = false
|
|
312
346
|
}) {
|
|
313
347
|
const translatedFilter = this.transformFilter(filter) ?? {};
|
|
314
|
-
|
|
315
|
-
query
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
348
|
+
try {
|
|
349
|
+
const results = (await this.client.query(indexName, {
|
|
350
|
+
query: queryVector,
|
|
351
|
+
limit: topK,
|
|
352
|
+
filter: translatedFilter,
|
|
353
|
+
with_payload: true,
|
|
354
|
+
with_vector: includeVector
|
|
355
|
+
})).points;
|
|
356
|
+
return results.map((match) => {
|
|
357
|
+
let vector = [];
|
|
358
|
+
if (includeVector) {
|
|
359
|
+
if (Array.isArray(match.vector)) {
|
|
360
|
+
vector = match.vector;
|
|
361
|
+
} else if (typeof match.vector === "object" && match.vector !== null) {
|
|
362
|
+
vector = Object.values(match.vector).filter((v) => typeof v === "number");
|
|
363
|
+
}
|
|
328
364
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
};
|
|
336
|
-
})
|
|
365
|
+
return {
|
|
366
|
+
id: match.id,
|
|
367
|
+
score: match.score || 0,
|
|
368
|
+
metadata: match.payload,
|
|
369
|
+
...includeVector && { vector }
|
|
370
|
+
};
|
|
371
|
+
});
|
|
372
|
+
} catch (error$1) {
|
|
373
|
+
throw new error.MastraError(
|
|
374
|
+
{
|
|
375
|
+
id: "STORAGE_QDRANT_VECTOR_QUERY_FAILED",
|
|
376
|
+
domain: error.ErrorDomain.STORAGE,
|
|
377
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
378
|
+
details: { indexName, topK }
|
|
379
|
+
},
|
|
380
|
+
error$1
|
|
381
|
+
);
|
|
382
|
+
}
|
|
337
383
|
}
|
|
338
384
|
async listIndexes() {
|
|
339
|
-
|
|
340
|
-
|
|
385
|
+
try {
|
|
386
|
+
const response = await this.client.getCollections();
|
|
387
|
+
return response.collections.map((collection) => collection.name) || [];
|
|
388
|
+
} catch (error$1) {
|
|
389
|
+
throw new error.MastraError(
|
|
390
|
+
{
|
|
391
|
+
id: "STORAGE_QDRANT_VECTOR_LIST_INDEXES_FAILED",
|
|
392
|
+
domain: error.ErrorDomain.STORAGE,
|
|
393
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
394
|
+
},
|
|
395
|
+
error$1
|
|
396
|
+
);
|
|
397
|
+
}
|
|
341
398
|
}
|
|
342
399
|
/**
|
|
343
400
|
* Retrieves statistics about a vector index.
|
|
@@ -346,17 +403,41 @@ var QdrantVector = class extends vector.MastraVector {
|
|
|
346
403
|
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
347
404
|
*/
|
|
348
405
|
async describeIndex({ indexName }) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
406
|
+
try {
|
|
407
|
+
const { config, points_count } = await this.client.getCollection(indexName);
|
|
408
|
+
const distance = config.params.vectors?.distance;
|
|
409
|
+
return {
|
|
410
|
+
dimension: config.params.vectors?.size,
|
|
411
|
+
count: points_count || 0,
|
|
412
|
+
// @ts-expect-error
|
|
413
|
+
metric: Object.keys(DISTANCE_MAPPING).find((key) => DISTANCE_MAPPING[key] === distance)
|
|
414
|
+
};
|
|
415
|
+
} catch (error$1) {
|
|
416
|
+
throw new error.MastraError(
|
|
417
|
+
{
|
|
418
|
+
id: "STORAGE_QDRANT_VECTOR_DESCRIBE_INDEX_FAILED",
|
|
419
|
+
domain: error.ErrorDomain.STORAGE,
|
|
420
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
421
|
+
details: { indexName }
|
|
422
|
+
},
|
|
423
|
+
error$1
|
|
424
|
+
);
|
|
425
|
+
}
|
|
357
426
|
}
|
|
358
427
|
async deleteIndex({ indexName }) {
|
|
359
|
-
|
|
428
|
+
try {
|
|
429
|
+
await this.client.deleteCollection(indexName);
|
|
430
|
+
} catch (error$1) {
|
|
431
|
+
throw new error.MastraError(
|
|
432
|
+
{
|
|
433
|
+
id: "STORAGE_QDRANT_VECTOR_DELETE_INDEX_FAILED",
|
|
434
|
+
domain: error.ErrorDomain.STORAGE,
|
|
435
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
436
|
+
details: { indexName }
|
|
437
|
+
},
|
|
438
|
+
error$1
|
|
439
|
+
);
|
|
440
|
+
}
|
|
360
441
|
}
|
|
361
442
|
/**
|
|
362
443
|
* Updates a vector by its ID with the provided vector and/or metadata.
|
|
@@ -369,8 +450,20 @@ var QdrantVector = class extends vector.MastraVector {
|
|
|
369
450
|
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
370
451
|
*/
|
|
371
452
|
async updateVector({ indexName, id, update }) {
|
|
372
|
-
|
|
373
|
-
|
|
453
|
+
try {
|
|
454
|
+
if (!update.vector && !update.metadata) {
|
|
455
|
+
throw new Error("No updates provided");
|
|
456
|
+
}
|
|
457
|
+
} catch (validationError) {
|
|
458
|
+
throw new error.MastraError(
|
|
459
|
+
{
|
|
460
|
+
id: "STORAGE_QDRANT_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
|
|
461
|
+
domain: error.ErrorDomain.STORAGE,
|
|
462
|
+
category: error.ErrorCategory.USER,
|
|
463
|
+
details: { indexName, id }
|
|
464
|
+
},
|
|
465
|
+
validationError
|
|
466
|
+
);
|
|
374
467
|
}
|
|
375
468
|
const pointId = this.parsePointId(id);
|
|
376
469
|
try {
|
|
@@ -400,9 +493,16 @@ var QdrantVector = class extends vector.MastraVector {
|
|
|
400
493
|
});
|
|
401
494
|
return;
|
|
402
495
|
}
|
|
403
|
-
} catch (error) {
|
|
404
|
-
|
|
405
|
-
|
|
496
|
+
} catch (error$1) {
|
|
497
|
+
throw new error.MastraError(
|
|
498
|
+
{
|
|
499
|
+
id: "STORAGE_QDRANT_VECTOR_UPDATE_VECTOR_FAILED",
|
|
500
|
+
domain: error.ErrorDomain.STORAGE,
|
|
501
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
502
|
+
details: { indexName, id }
|
|
503
|
+
},
|
|
504
|
+
error$1
|
|
505
|
+
);
|
|
406
506
|
}
|
|
407
507
|
}
|
|
408
508
|
/**
|
|
@@ -418,8 +518,16 @@ var QdrantVector = class extends vector.MastraVector {
|
|
|
418
518
|
await this.client.delete(indexName, {
|
|
419
519
|
points: [pointId]
|
|
420
520
|
});
|
|
421
|
-
} catch (error) {
|
|
422
|
-
throw new
|
|
521
|
+
} catch (error$1) {
|
|
522
|
+
throw new error.MastraError(
|
|
523
|
+
{
|
|
524
|
+
id: "STORAGE_QDRANT_VECTOR_DELETE_VECTOR_FAILED",
|
|
525
|
+
domain: error.ErrorDomain.STORAGE,
|
|
526
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
527
|
+
details: { indexName, id }
|
|
528
|
+
},
|
|
529
|
+
error$1
|
|
530
|
+
);
|
|
423
531
|
}
|
|
424
532
|
}
|
|
425
533
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
1
2
|
import { MastraVector } from '@mastra/core/vector';
|
|
2
3
|
import { QdrantClient } from '@qdrant/js-client-rest';
|
|
3
4
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
@@ -265,22 +266,46 @@ var QdrantVector = class extends MastraVector {
|
|
|
265
266
|
vector,
|
|
266
267
|
payload: metadata?.[i] || {}
|
|
267
268
|
}));
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
269
|
+
try {
|
|
270
|
+
for (let i = 0; i < records.length; i += BATCH_SIZE) {
|
|
271
|
+
const batch = records.slice(i, i + BATCH_SIZE);
|
|
272
|
+
await this.client.upsert(indexName, {
|
|
273
|
+
// @ts-expect-error
|
|
274
|
+
points: batch,
|
|
275
|
+
wait: true
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return pointIds;
|
|
279
|
+
} catch (error) {
|
|
280
|
+
throw new MastraError(
|
|
281
|
+
{
|
|
282
|
+
id: "STORAGE_QDRANT_VECTOR_UPSERT_FAILED",
|
|
283
|
+
domain: ErrorDomain.STORAGE,
|
|
284
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
285
|
+
details: { indexName, vectorCount: vectors.length }
|
|
286
|
+
},
|
|
287
|
+
error
|
|
288
|
+
);
|
|
275
289
|
}
|
|
276
|
-
return pointIds;
|
|
277
290
|
}
|
|
278
291
|
async createIndex({ indexName, dimension, metric = "cosine" }) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
292
|
+
try {
|
|
293
|
+
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
294
|
+
throw new Error("Dimension must be a positive integer");
|
|
295
|
+
}
|
|
296
|
+
if (!DISTANCE_MAPPING[metric]) {
|
|
297
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
298
|
+
}
|
|
299
|
+
} catch (validationError) {
|
|
300
|
+
throw new MastraError(
|
|
301
|
+
{
|
|
302
|
+
id: "STORAGE_QDRANT_VECTOR_CREATE_INDEX_INVALID_ARGS",
|
|
303
|
+
domain: ErrorDomain.STORAGE,
|
|
304
|
+
category: ErrorCategory.USER,
|
|
305
|
+
details: { indexName, dimension, metric }
|
|
306
|
+
},
|
|
307
|
+
validationError
|
|
308
|
+
);
|
|
284
309
|
}
|
|
285
310
|
try {
|
|
286
311
|
await this.client.createCollection(indexName, {
|
|
@@ -295,6 +320,15 @@ var QdrantVector = class extends MastraVector {
|
|
|
295
320
|
await this.validateExistingIndex(indexName, dimension, metric);
|
|
296
321
|
return;
|
|
297
322
|
}
|
|
323
|
+
throw new MastraError(
|
|
324
|
+
{
|
|
325
|
+
id: "STORAGE_QDRANT_VECTOR_CREATE_INDEX_FAILED",
|
|
326
|
+
domain: ErrorDomain.STORAGE,
|
|
327
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
328
|
+
details: { indexName, dimension, metric }
|
|
329
|
+
},
|
|
330
|
+
error
|
|
331
|
+
);
|
|
298
332
|
}
|
|
299
333
|
}
|
|
300
334
|
transformFilter(filter) {
|
|
@@ -309,33 +343,56 @@ var QdrantVector = class extends MastraVector {
|
|
|
309
343
|
includeVector = false
|
|
310
344
|
}) {
|
|
311
345
|
const translatedFilter = this.transformFilter(filter) ?? {};
|
|
312
|
-
|
|
313
|
-
query
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
346
|
+
try {
|
|
347
|
+
const results = (await this.client.query(indexName, {
|
|
348
|
+
query: queryVector,
|
|
349
|
+
limit: topK,
|
|
350
|
+
filter: translatedFilter,
|
|
351
|
+
with_payload: true,
|
|
352
|
+
with_vector: includeVector
|
|
353
|
+
})).points;
|
|
354
|
+
return results.map((match) => {
|
|
355
|
+
let vector = [];
|
|
356
|
+
if (includeVector) {
|
|
357
|
+
if (Array.isArray(match.vector)) {
|
|
358
|
+
vector = match.vector;
|
|
359
|
+
} else if (typeof match.vector === "object" && match.vector !== null) {
|
|
360
|
+
vector = Object.values(match.vector).filter((v) => typeof v === "number");
|
|
361
|
+
}
|
|
326
362
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
};
|
|
334
|
-
})
|
|
363
|
+
return {
|
|
364
|
+
id: match.id,
|
|
365
|
+
score: match.score || 0,
|
|
366
|
+
metadata: match.payload,
|
|
367
|
+
...includeVector && { vector }
|
|
368
|
+
};
|
|
369
|
+
});
|
|
370
|
+
} catch (error) {
|
|
371
|
+
throw new MastraError(
|
|
372
|
+
{
|
|
373
|
+
id: "STORAGE_QDRANT_VECTOR_QUERY_FAILED",
|
|
374
|
+
domain: ErrorDomain.STORAGE,
|
|
375
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
376
|
+
details: { indexName, topK }
|
|
377
|
+
},
|
|
378
|
+
error
|
|
379
|
+
);
|
|
380
|
+
}
|
|
335
381
|
}
|
|
336
382
|
async listIndexes() {
|
|
337
|
-
|
|
338
|
-
|
|
383
|
+
try {
|
|
384
|
+
const response = await this.client.getCollections();
|
|
385
|
+
return response.collections.map((collection) => collection.name) || [];
|
|
386
|
+
} catch (error) {
|
|
387
|
+
throw new MastraError(
|
|
388
|
+
{
|
|
389
|
+
id: "STORAGE_QDRANT_VECTOR_LIST_INDEXES_FAILED",
|
|
390
|
+
domain: ErrorDomain.STORAGE,
|
|
391
|
+
category: ErrorCategory.THIRD_PARTY
|
|
392
|
+
},
|
|
393
|
+
error
|
|
394
|
+
);
|
|
395
|
+
}
|
|
339
396
|
}
|
|
340
397
|
/**
|
|
341
398
|
* Retrieves statistics about a vector index.
|
|
@@ -344,17 +401,41 @@ var QdrantVector = class extends MastraVector {
|
|
|
344
401
|
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
345
402
|
*/
|
|
346
403
|
async describeIndex({ indexName }) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
404
|
+
try {
|
|
405
|
+
const { config, points_count } = await this.client.getCollection(indexName);
|
|
406
|
+
const distance = config.params.vectors?.distance;
|
|
407
|
+
return {
|
|
408
|
+
dimension: config.params.vectors?.size,
|
|
409
|
+
count: points_count || 0,
|
|
410
|
+
// @ts-expect-error
|
|
411
|
+
metric: Object.keys(DISTANCE_MAPPING).find((key) => DISTANCE_MAPPING[key] === distance)
|
|
412
|
+
};
|
|
413
|
+
} catch (error) {
|
|
414
|
+
throw new MastraError(
|
|
415
|
+
{
|
|
416
|
+
id: "STORAGE_QDRANT_VECTOR_DESCRIBE_INDEX_FAILED",
|
|
417
|
+
domain: ErrorDomain.STORAGE,
|
|
418
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
419
|
+
details: { indexName }
|
|
420
|
+
},
|
|
421
|
+
error
|
|
422
|
+
);
|
|
423
|
+
}
|
|
355
424
|
}
|
|
356
425
|
async deleteIndex({ indexName }) {
|
|
357
|
-
|
|
426
|
+
try {
|
|
427
|
+
await this.client.deleteCollection(indexName);
|
|
428
|
+
} catch (error) {
|
|
429
|
+
throw new MastraError(
|
|
430
|
+
{
|
|
431
|
+
id: "STORAGE_QDRANT_VECTOR_DELETE_INDEX_FAILED",
|
|
432
|
+
domain: ErrorDomain.STORAGE,
|
|
433
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
434
|
+
details: { indexName }
|
|
435
|
+
},
|
|
436
|
+
error
|
|
437
|
+
);
|
|
438
|
+
}
|
|
358
439
|
}
|
|
359
440
|
/**
|
|
360
441
|
* Updates a vector by its ID with the provided vector and/or metadata.
|
|
@@ -367,8 +448,20 @@ var QdrantVector = class extends MastraVector {
|
|
|
367
448
|
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
368
449
|
*/
|
|
369
450
|
async updateVector({ indexName, id, update }) {
|
|
370
|
-
|
|
371
|
-
|
|
451
|
+
try {
|
|
452
|
+
if (!update.vector && !update.metadata) {
|
|
453
|
+
throw new Error("No updates provided");
|
|
454
|
+
}
|
|
455
|
+
} catch (validationError) {
|
|
456
|
+
throw new MastraError(
|
|
457
|
+
{
|
|
458
|
+
id: "STORAGE_QDRANT_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
|
|
459
|
+
domain: ErrorDomain.STORAGE,
|
|
460
|
+
category: ErrorCategory.USER,
|
|
461
|
+
details: { indexName, id }
|
|
462
|
+
},
|
|
463
|
+
validationError
|
|
464
|
+
);
|
|
372
465
|
}
|
|
373
466
|
const pointId = this.parsePointId(id);
|
|
374
467
|
try {
|
|
@@ -399,8 +492,15 @@ var QdrantVector = class extends MastraVector {
|
|
|
399
492
|
return;
|
|
400
493
|
}
|
|
401
494
|
} catch (error) {
|
|
402
|
-
|
|
403
|
-
|
|
495
|
+
throw new MastraError(
|
|
496
|
+
{
|
|
497
|
+
id: "STORAGE_QDRANT_VECTOR_UPDATE_VECTOR_FAILED",
|
|
498
|
+
domain: ErrorDomain.STORAGE,
|
|
499
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
500
|
+
details: { indexName, id }
|
|
501
|
+
},
|
|
502
|
+
error
|
|
503
|
+
);
|
|
404
504
|
}
|
|
405
505
|
}
|
|
406
506
|
/**
|
|
@@ -417,7 +517,15 @@ var QdrantVector = class extends MastraVector {
|
|
|
417
517
|
points: [pointId]
|
|
418
518
|
});
|
|
419
519
|
} catch (error) {
|
|
420
|
-
throw new
|
|
520
|
+
throw new MastraError(
|
|
521
|
+
{
|
|
522
|
+
id: "STORAGE_QDRANT_VECTOR_DELETE_VECTOR_FAILED",
|
|
523
|
+
domain: ErrorDomain.STORAGE,
|
|
524
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
525
|
+
details: { indexName, id }
|
|
526
|
+
},
|
|
527
|
+
error
|
|
528
|
+
);
|
|
421
529
|
}
|
|
422
530
|
}
|
|
423
531
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/qdrant",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4-alpha.0",
|
|
4
4
|
"description": "Qdrant vector store provider for Mastra",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"typescript": "^5.8.3",
|
|
31
31
|
"vitest": "^3.2.3",
|
|
32
32
|
"@internal/lint": "0.0.13",
|
|
33
|
-
"@mastra/core": "0.10.
|
|
33
|
+
"@mastra/core": "0.10.7-alpha.1"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@mastra/core": ">=0.10.4-0 <0.11.0"
|
package/src/vector/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MastraError, ErrorDomain, ErrorCategory } from '@mastra/core/error';
|
|
1
2
|
import { MastraVector } from '@mastra/core/vector';
|
|
2
3
|
import type {
|
|
3
4
|
QueryResult,
|
|
@@ -58,25 +59,50 @@ export class QdrantVector extends MastraVector {
|
|
|
58
59
|
payload: metadata?.[i] || {},
|
|
59
60
|
}));
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
try {
|
|
63
|
+
for (let i = 0; i < records.length; i += BATCH_SIZE) {
|
|
64
|
+
const batch = records.slice(i, i + BATCH_SIZE);
|
|
65
|
+
await this.client.upsert(indexName, {
|
|
66
|
+
// @ts-expect-error
|
|
67
|
+
points: batch,
|
|
68
|
+
wait: true,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
return pointIds;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new MastraError(
|
|
75
|
+
{
|
|
76
|
+
id: 'STORAGE_QDRANT_VECTOR_UPSERT_FAILED',
|
|
77
|
+
domain: ErrorDomain.STORAGE,
|
|
78
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
79
|
+
details: { indexName, vectorCount: vectors.length },
|
|
80
|
+
},
|
|
81
|
+
error,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
async createIndex({ indexName, dimension, metric = 'cosine' }: CreateIndexParams): Promise<void> {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
87
|
+
try {
|
|
88
|
+
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
89
|
+
throw new Error('Dimension must be a positive integer');
|
|
90
|
+
}
|
|
91
|
+
if (!DISTANCE_MAPPING[metric]) {
|
|
92
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
93
|
+
}
|
|
94
|
+
} catch (validationError) {
|
|
95
|
+
throw new MastraError(
|
|
96
|
+
{
|
|
97
|
+
id: 'STORAGE_QDRANT_VECTOR_CREATE_INDEX_INVALID_ARGS',
|
|
98
|
+
domain: ErrorDomain.STORAGE,
|
|
99
|
+
category: ErrorCategory.USER,
|
|
100
|
+
details: { indexName, dimension, metric },
|
|
101
|
+
},
|
|
102
|
+
validationError,
|
|
103
|
+
);
|
|
79
104
|
}
|
|
105
|
+
|
|
80
106
|
try {
|
|
81
107
|
await this.client.createCollection(indexName, {
|
|
82
108
|
vectors: {
|
|
@@ -92,6 +118,16 @@ export class QdrantVector extends MastraVector {
|
|
|
92
118
|
await this.validateExistingIndex(indexName, dimension, metric);
|
|
93
119
|
return;
|
|
94
120
|
}
|
|
121
|
+
|
|
122
|
+
throw new MastraError(
|
|
123
|
+
{
|
|
124
|
+
id: 'STORAGE_QDRANT_VECTOR_CREATE_INDEX_FAILED',
|
|
125
|
+
domain: ErrorDomain.STORAGE,
|
|
126
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
127
|
+
details: { indexName, dimension, metric },
|
|
128
|
+
},
|
|
129
|
+
error,
|
|
130
|
+
);
|
|
95
131
|
}
|
|
96
132
|
}
|
|
97
133
|
|
|
@@ -109,40 +145,63 @@ export class QdrantVector extends MastraVector {
|
|
|
109
145
|
}: QueryVectorParams): Promise<QueryResult[]> {
|
|
110
146
|
const translatedFilter = this.transformFilter(filter) ?? {};
|
|
111
147
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
query
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
148
|
+
try {
|
|
149
|
+
const results = (
|
|
150
|
+
await this.client.query(indexName, {
|
|
151
|
+
query: queryVector,
|
|
152
|
+
limit: topK,
|
|
153
|
+
filter: translatedFilter,
|
|
154
|
+
with_payload: true,
|
|
155
|
+
with_vector: includeVector,
|
|
156
|
+
})
|
|
157
|
+
).points;
|
|
121
158
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
159
|
+
return results.map(match => {
|
|
160
|
+
let vector: number[] = [];
|
|
161
|
+
if (includeVector) {
|
|
162
|
+
if (Array.isArray(match.vector)) {
|
|
163
|
+
// If it's already an array of numbers
|
|
164
|
+
vector = match.vector as number[];
|
|
165
|
+
} else if (typeof match.vector === 'object' && match.vector !== null) {
|
|
166
|
+
// If it's an object with vector data
|
|
167
|
+
vector = Object.values(match.vector).filter(v => typeof v === 'number');
|
|
168
|
+
}
|
|
131
169
|
}
|
|
132
|
-
}
|
|
133
170
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
171
|
+
return {
|
|
172
|
+
id: match.id as string,
|
|
173
|
+
score: match.score || 0,
|
|
174
|
+
metadata: match.payload as Record<string, any>,
|
|
175
|
+
...(includeVector && { vector }),
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
} catch (error) {
|
|
179
|
+
throw new MastraError(
|
|
180
|
+
{
|
|
181
|
+
id: 'STORAGE_QDRANT_VECTOR_QUERY_FAILED',
|
|
182
|
+
domain: ErrorDomain.STORAGE,
|
|
183
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
184
|
+
details: { indexName, topK },
|
|
185
|
+
},
|
|
186
|
+
error,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
141
189
|
}
|
|
142
190
|
|
|
143
191
|
async listIndexes(): Promise<string[]> {
|
|
144
|
-
|
|
145
|
-
|
|
192
|
+
try {
|
|
193
|
+
const response = await this.client.getCollections();
|
|
194
|
+
return response.collections.map(collection => collection.name) || [];
|
|
195
|
+
} catch (error) {
|
|
196
|
+
throw new MastraError(
|
|
197
|
+
{
|
|
198
|
+
id: 'STORAGE_QDRANT_VECTOR_LIST_INDEXES_FAILED',
|
|
199
|
+
domain: ErrorDomain.STORAGE,
|
|
200
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
201
|
+
},
|
|
202
|
+
error,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
146
205
|
}
|
|
147
206
|
|
|
148
207
|
/**
|
|
@@ -152,19 +211,43 @@ export class QdrantVector extends MastraVector {
|
|
|
152
211
|
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
153
212
|
*/
|
|
154
213
|
async describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats> {
|
|
155
|
-
|
|
214
|
+
try {
|
|
215
|
+
const { config, points_count } = await this.client.getCollection(indexName);
|
|
156
216
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
217
|
+
const distance = config.params.vectors?.distance as Schemas['Distance'];
|
|
218
|
+
return {
|
|
219
|
+
dimension: config.params.vectors?.size as number,
|
|
220
|
+
count: points_count || 0,
|
|
221
|
+
// @ts-expect-error
|
|
222
|
+
metric: Object.keys(DISTANCE_MAPPING).find(key => DISTANCE_MAPPING[key] === distance),
|
|
223
|
+
};
|
|
224
|
+
} catch (error) {
|
|
225
|
+
throw new MastraError(
|
|
226
|
+
{
|
|
227
|
+
id: 'STORAGE_QDRANT_VECTOR_DESCRIBE_INDEX_FAILED',
|
|
228
|
+
domain: ErrorDomain.STORAGE,
|
|
229
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
230
|
+
details: { indexName },
|
|
231
|
+
},
|
|
232
|
+
error,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
164
235
|
}
|
|
165
236
|
|
|
166
237
|
async deleteIndex({ indexName }: DeleteIndexParams): Promise<void> {
|
|
167
|
-
|
|
238
|
+
try {
|
|
239
|
+
await this.client.deleteCollection(indexName);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
throw new MastraError(
|
|
242
|
+
{
|
|
243
|
+
id: 'STORAGE_QDRANT_VECTOR_DELETE_INDEX_FAILED',
|
|
244
|
+
domain: ErrorDomain.STORAGE,
|
|
245
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
246
|
+
details: { indexName },
|
|
247
|
+
},
|
|
248
|
+
error,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
168
251
|
}
|
|
169
252
|
|
|
170
253
|
/**
|
|
@@ -178,8 +261,20 @@ export class QdrantVector extends MastraVector {
|
|
|
178
261
|
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
179
262
|
*/
|
|
180
263
|
async updateVector({ indexName, id, update }: UpdateVectorParams): Promise<void> {
|
|
181
|
-
|
|
182
|
-
|
|
264
|
+
try {
|
|
265
|
+
if (!update.vector && !update.metadata) {
|
|
266
|
+
throw new Error('No updates provided');
|
|
267
|
+
}
|
|
268
|
+
} catch (validationError) {
|
|
269
|
+
throw new MastraError(
|
|
270
|
+
{
|
|
271
|
+
id: 'STORAGE_QDRANT_VECTOR_UPDATE_VECTOR_INVALID_ARGS',
|
|
272
|
+
domain: ErrorDomain.STORAGE,
|
|
273
|
+
category: ErrorCategory.USER,
|
|
274
|
+
details: { indexName, id },
|
|
275
|
+
},
|
|
276
|
+
validationError,
|
|
277
|
+
);
|
|
183
278
|
}
|
|
184
279
|
|
|
185
280
|
const pointId = this.parsePointId(id);
|
|
@@ -219,8 +314,15 @@ export class QdrantVector extends MastraVector {
|
|
|
219
314
|
return;
|
|
220
315
|
}
|
|
221
316
|
} catch (error) {
|
|
222
|
-
|
|
223
|
-
|
|
317
|
+
throw new MastraError(
|
|
318
|
+
{
|
|
319
|
+
id: 'STORAGE_QDRANT_VECTOR_UPDATE_VECTOR_FAILED',
|
|
320
|
+
domain: ErrorDomain.STORAGE,
|
|
321
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
322
|
+
details: { indexName, id },
|
|
323
|
+
},
|
|
324
|
+
error,
|
|
325
|
+
);
|
|
224
326
|
}
|
|
225
327
|
}
|
|
226
328
|
|
|
@@ -240,8 +342,16 @@ export class QdrantVector extends MastraVector {
|
|
|
240
342
|
await this.client.delete(indexName, {
|
|
241
343
|
points: [pointId],
|
|
242
344
|
});
|
|
243
|
-
} catch (error
|
|
244
|
-
throw new
|
|
345
|
+
} catch (error) {
|
|
346
|
+
throw new MastraError(
|
|
347
|
+
{
|
|
348
|
+
id: 'STORAGE_QDRANT_VECTOR_DELETE_VECTOR_FAILED',
|
|
349
|
+
domain: ErrorDomain.STORAGE,
|
|
350
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
351
|
+
details: { indexName, id },
|
|
352
|
+
},
|
|
353
|
+
error,
|
|
354
|
+
);
|
|
245
355
|
}
|
|
246
356
|
}
|
|
247
357
|
|