@mastra/qdrant 1.0.0-beta.3 → 1.0.0-beta.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # @mastra/qdrant
2
2
 
3
+ ## 1.0.0-beta.4
4
+
5
+ ### Minor Changes
6
+
7
+ - Added support for creating payload (metadata) indexes in Qdrant ([#11839](https://github.com/mastra-ai/mastra/pull/11839))
8
+
9
+ Qdrant Cloud and deployments with `strict_mode_config = true` require explicit payload indexes for metadata filtering. This release adds two new methods to `QdrantVector`:
10
+
11
+ **New exports:**
12
+ - `PayloadSchemaType` - Union type for Qdrant payload schema types ('keyword', 'integer', 'float', 'geo', 'text', 'bool', 'datetime', 'uuid')
13
+ - `CreatePayloadIndexParams` - Parameters interface for creating payload indexes
14
+ - `DeletePayloadIndexParams` - Parameters interface for deleting payload indexes
15
+
16
+ **New methods:**
17
+ - `createPayloadIndex()` - Creates a payload index on a collection field for efficient filtering
18
+ - `deletePayloadIndex()` - Removes a payload index from a collection field
19
+
20
+ **Example usage:**
21
+
22
+ ```typescript
23
+ import { QdrantVector } from '@mastra/qdrant';
24
+
25
+ const qdrant = new QdrantVector({ url: `http://localhost:6333`, id: 'my-store' });
26
+
27
+ // Create a keyword index for filtering by source
28
+ await qdrant.createPayloadIndex({
29
+ indexName: 'my-collection',
30
+ fieldName: 'source',
31
+ fieldSchema: 'keyword',
32
+ });
33
+
34
+ // Now filtering works in strict mode environments
35
+ const results = await qdrant.query({
36
+ indexName: 'my-collection',
37
+ queryVector: embeddings,
38
+ filter: { source: 'document-a' },
39
+ });
40
+ ```
41
+
42
+ Closes #8923
43
+
44
+ ### Patch Changes
45
+
46
+ - Updated dependencies [[`ebae12a`](https://github.com/mastra-ai/mastra/commit/ebae12a2dd0212e75478981053b148a2c246962d), [`c61a0a5`](https://github.com/mastra-ai/mastra/commit/c61a0a5de4904c88fd8b3718bc26d1be1c2ec6e7), [`69136e7`](https://github.com/mastra-ai/mastra/commit/69136e748e32f57297728a4e0f9a75988462f1a7), [`449aed2`](https://github.com/mastra-ai/mastra/commit/449aed2ba9d507b75bf93d427646ea94f734dfd1), [`eb648a2`](https://github.com/mastra-ai/mastra/commit/eb648a2cc1728f7678768dd70cd77619b448dab9), [`0131105`](https://github.com/mastra-ai/mastra/commit/0131105532e83bdcbb73352fc7d0879eebf140dc), [`9d5059e`](https://github.com/mastra-ai/mastra/commit/9d5059eae810829935fb08e81a9bb7ecd5b144a7), [`ef756c6`](https://github.com/mastra-ai/mastra/commit/ef756c65f82d16531c43f49a27290a416611e526), [`b00ccd3`](https://github.com/mastra-ai/mastra/commit/b00ccd325ebd5d9e37e34dd0a105caae67eb568f), [`3bdfa75`](https://github.com/mastra-ai/mastra/commit/3bdfa7507a91db66f176ba8221aa28dd546e464a), [`e770de9`](https://github.com/mastra-ai/mastra/commit/e770de941a287a49b1964d44db5a5763d19890a6), [`52e2716`](https://github.com/mastra-ai/mastra/commit/52e2716b42df6eff443de72360ae83e86ec23993), [`27b4040`](https://github.com/mastra-ai/mastra/commit/27b4040bfa1a95d92546f420a02a626b1419a1d6), [`610a70b`](https://github.com/mastra-ai/mastra/commit/610a70bdad282079f0c630e0d7bb284578f20151), [`8dc7f55`](https://github.com/mastra-ai/mastra/commit/8dc7f55900395771da851dc7d78d53ae84fe34ec), [`8379099`](https://github.com/mastra-ai/mastra/commit/8379099fc467af6bef54dd7f80c9bd75bf8bbddf), [`8c0ec25`](https://github.com/mastra-ai/mastra/commit/8c0ec25646c8a7df253ed1e5ff4863a0d3f1316c), [`ff4d9a6`](https://github.com/mastra-ai/mastra/commit/ff4d9a6704fc87b31a380a76ed22736fdedbba5a), [`69821ef`](https://github.com/mastra-ai/mastra/commit/69821ef806482e2c44e2197ac0b050c3fe3a5285), [`1ed5716`](https://github.com/mastra-ai/mastra/commit/1ed5716830867b3774c4a1b43cc0d82935f32b96), [`4186bdd`](https://github.com/mastra-ai/mastra/commit/4186bdd00731305726fa06adba0b076a1d50b49f), [`7aaf973`](https://github.com/mastra-ai/mastra/commit/7aaf973f83fbbe9521f1f9e7a4fd99b8de464617)]:
47
+ - @mastra/core@1.0.0-beta.22
48
+
3
49
  ## 1.0.0-beta.3
4
50
 
5
51
  ### Patch Changes
@@ -29,4 +29,4 @@ docs/
29
29
  ## Version
30
30
 
31
31
  Package: @mastra/qdrant
32
- Version: 1.0.0-beta.3
32
+ Version: 1.0.0-beta.4
@@ -5,7 +5,7 @@ description: Documentation for @mastra/qdrant. Includes links to type definition
5
5
 
6
6
  # @mastra/qdrant Documentation
7
7
 
8
- > **Version**: 1.0.0-beta.3
8
+ > **Version**: 1.0.0-beta.4
9
9
  > **Package**: @mastra/qdrant
10
10
 
11
11
  ## Quick Navigation
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.0-beta.3",
2
+ "version": "1.0.0-beta.4",
3
3
  "package": "@mastra/qdrant",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -12,6 +12,7 @@ After generating embeddings, you need to store them in a database that supports
12
12
  import { MongoDBVector } from "@mastra/mongodb";
13
13
 
14
14
  const store = new MongoDBVector({
15
+ id: 'mongodb-vector',
15
16
  uri: process.env.MONGODB_URI,
16
17
  dbName: process.env.MONGODB_DATABASE,
17
18
  });
@@ -144,6 +145,7 @@ await store.upsert({
144
145
  import { AstraVector } from "@mastra/astra";
145
146
 
146
147
  const store = new AstraVector({
148
+ id: 'astra-vector',
147
149
  token: process.env.ASTRA_DB_TOKEN,
148
150
  endpoint: process.env.ASTRA_DB_ENDPOINT,
149
151
  keyspace: process.env.ASTRA_DB_KEYSPACE,
@@ -170,7 +172,7 @@ import { LibSQLVector } from "@mastra/core/vector/libsql";
170
172
 
171
173
  const store = new LibSQLVector({
172
174
  id: 'libsql-vector',
173
- connectionUrl: process.env.DATABASE_URL,
175
+ url: process.env.DATABASE_URL,
174
176
  authToken: process.env.DATABASE_AUTH_TOKEN, // Optional: for Turso cloud databases
175
177
  });
176
178
 
@@ -217,6 +219,7 @@ await store.upsert({
217
219
  import { CloudflareVector } from "@mastra/vectorize";
218
220
 
219
221
  const store = new CloudflareVector({
222
+ id: 'cloudflare-vector',
220
223
  accountId: process.env.CF_ACCOUNT_ID,
221
224
  apiToken: process.env.CF_API_TOKEN,
222
225
  });
@@ -238,7 +241,7 @@ await store.upsert({
238
241
  ```ts title="vector-store.ts"
239
242
  import { OpenSearchVector } from "@mastra/opensearch";
240
243
 
241
- const store = new OpenSearchVector({ url: process.env.OPENSEARCH_URL });
244
+ const store = new OpenSearchVector({ id: "opensearch", node: process.env.OPENSEARCH_URL });
242
245
 
243
246
  await store.createIndex({
244
247
  indexName: "my-collection",
@@ -259,7 +262,7 @@ await store.upsert({
259
262
  ```ts title="vector-store.ts"
260
263
  import { ElasticSearchVector } from "@mastra/elasticsearch";
261
264
 
262
- const store = new ElasticSearchVector({ url: process.env.ELASTICSEARCH_URL });
265
+ const store = new ElasticSearchVector({ id: 'elasticsearch-vector', url: process.env.ELASTICSEARCH_URL });
263
266
 
264
267
  await store.createIndex({
265
268
  indexName: "my-collection",
@@ -280,6 +283,7 @@ await store.upsert({
280
283
  import { CouchbaseVector } from "@mastra/couchbase";
281
284
 
282
285
  const store = new CouchbaseVector({
286
+ id: 'couchbase-vector',
283
287
  connectionString: process.env.COUCHBASE_CONNECTION_STRING,
284
288
  username: process.env.COUCHBASE_USERNAME,
285
289
  password: process.env.COUCHBASE_PASSWORD,
@@ -331,6 +335,7 @@ For detailed setup instructions and best practices, see the [official LanceDB do
331
335
  import { S3Vectors } from "@mastra/s3vectors";
332
336
 
333
337
  const store = new S3Vectors({
338
+ id: 's3-vectors',
334
339
  vectorBucketName: "my-vector-bucket",
335
340
  clientConfig: {
336
341
  region: "us-east-1",
@@ -373,7 +378,7 @@ The dimension size must match the output dimension of your chosen embedding mode
373
378
  - Cohere embed-multilingual-v3: 1024 dimensions
374
379
  - Google text-embedding-004: 768 dimensions (or custom)
375
380
 
376
- important
381
+ > **Note:**
377
382
  Index dimensions cannot be changed after creation. To use a different model, delete and recreate the index with the new dimension size.
378
383
 
379
384
  ### Naming Rules for Databases
@@ -537,7 +542,7 @@ The upsert operation:
537
542
 
538
543
  Vector stores support rich metadata (any JSON-serializable fields) for filtering and organization. Since metadata is stored with no fixed schema, use consistent field naming to avoid unexpected query results.
539
544
 
540
- important
545
+ > **Note:**
541
546
  Metadata is crucial for vector storage - without it, you'd only have numerical embeddings with no way to return the original text or filter results. Always store at least the source text as metadata.
542
547
 
543
548
  ```ts
@@ -171,7 +171,7 @@ The Vector Query Tool supports database-specific configurations that enable you
171
171
  > **Note:**
172
172
  These configurations are for **query-time options** like namespaces, performance tuning, and filtering—not for database connection setup.
173
173
 
174
- Connection credentials (URLs, auth tokens) are configured when you instantiate the vector store class (e.g., `new LibSQLVector({ connectionUrl: '...' })`).
174
+ Connection credentials (URLs, auth tokens) are configured when you instantiate the vector store class (e.g., `new LibSQLVector({ url: '...' })`).
175
175
 
176
176
  ```ts
177
177
  import { createVectorQueryTool } from "@mastra/rag";
@@ -258,11 +258,10 @@ requestContext.set("databaseConfig", {
258
258
  },
259
259
  });
260
260
 
261
- await pineconeQueryTool.execute({
262
- context: { queryText: "search query" },
263
- mastra,
264
- requestContext,
265
- });
261
+ await pineconeQueryTool.execute(
262
+ { queryText: "search query" },
263
+ { mastra, requestContext }
264
+ );
266
265
  ```
267
266
 
268
267
  For detailed configuration options and advanced usage, see the [Vector Query Tool Reference](https://mastra.ai/reference/v1/tools/vector-query-tool).
@@ -54,6 +54,29 @@ Deletes a vector from the specified index by its ID.
54
54
 
55
55
  Delete multiple vectors by IDs or by metadata filter. Either `ids` or `filter` must be provided, but not both.
56
56
 
57
+ ### createPayloadIndex()
58
+
59
+ Creates a payload (metadata) index on a collection field to enable efficient filtering. This is **required** for Qdrant Cloud and any Qdrant instance with `strict_mode_config = true`.
60
+
61
+ ```typescript
62
+ // Create a keyword index for filtering by source
63
+ await store.createPayloadIndex({
64
+ indexName: "my_index",
65
+ fieldName: "source",
66
+ fieldSchema: "keyword",
67
+ });
68
+
69
+ const results = await store.query({
70
+ indexName: "my_index",
71
+ queryVector: queryVector,
72
+ filter: { source: "document-a" },
73
+ });
74
+ ```
75
+
76
+ ### deletePayloadIndex()
77
+
78
+ Removes a payload index from a collection field.
79
+
57
80
  ## Response Types
58
81
 
59
82
  Query results are returned in this format:
package/dist/index.cjs CHANGED
@@ -725,6 +725,161 @@ var QdrantVector = class extends vector.MastraVector {
725
725
  );
726
726
  }
727
727
  }
728
+ /**
729
+ * Creates a payload index on a Qdrant collection to enable efficient filtering on metadata fields.
730
+ *
731
+ * This is required for Qdrant Cloud and any Qdrant instance with `strict_mode_config = true`,
732
+ * where metadata (payload) fields must be explicitly indexed before they can be used for filtering.
733
+ *
734
+ * @param params - The parameters for creating the payload index.
735
+ * @param params.indexName - The name of the collection (index) to create the payload index on.
736
+ * @param params.fieldName - The name of the payload field to index.
737
+ * @param params.fieldSchema - The schema type for the field (e.g., 'keyword', 'integer', 'text').
738
+ * @param params.wait - Whether to wait for the operation to complete. Defaults to true.
739
+ * @returns A promise that resolves when the index is created (idempotent if index already exists).
740
+ * @throws Will throw a MastraError if arguments are invalid or if the operation fails.
741
+ *
742
+ * @example
743
+ * ```ts
744
+ * // Create a keyword index for filtering by source
745
+ * await qdrant.createPayloadIndex({
746
+ * indexName: 'my-collection',
747
+ * fieldName: 'source',
748
+ * fieldSchema: 'keyword',
749
+ * });
750
+ *
751
+ * // Create an integer index for numeric filtering
752
+ * await qdrant.createPayloadIndex({
753
+ * indexName: 'my-collection',
754
+ * fieldName: 'price',
755
+ * fieldSchema: 'integer',
756
+ * });
757
+ * ```
758
+ *
759
+ * @see https://qdrant.tech/documentation/concepts/indexing/#payload-index
760
+ */
761
+ async createPayloadIndex({
762
+ indexName,
763
+ fieldName,
764
+ fieldSchema,
765
+ wait = true
766
+ }) {
767
+ const validSchemas = [
768
+ "keyword",
769
+ "integer",
770
+ "float",
771
+ "geo",
772
+ "text",
773
+ "bool",
774
+ "datetime",
775
+ "uuid"
776
+ ];
777
+ if (!indexName || typeof indexName !== "string" || indexName.trim() === "") {
778
+ throw new error.MastraError({
779
+ id: storage.createVectorErrorId("QDRANT", "CREATE_PAYLOAD_INDEX", "INVALID_ARGS"),
780
+ text: "indexName must be a non-empty string",
781
+ domain: error.ErrorDomain.STORAGE,
782
+ category: error.ErrorCategory.USER,
783
+ details: { indexName, fieldName, fieldSchema }
784
+ });
785
+ }
786
+ if (!fieldName || typeof fieldName !== "string" || fieldName.trim() === "") {
787
+ throw new error.MastraError({
788
+ id: storage.createVectorErrorId("QDRANT", "CREATE_PAYLOAD_INDEX", "INVALID_ARGS"),
789
+ text: "fieldName must be a non-empty string",
790
+ domain: error.ErrorDomain.STORAGE,
791
+ category: error.ErrorCategory.USER,
792
+ details: { indexName, fieldName, fieldSchema }
793
+ });
794
+ }
795
+ if (!validSchemas.includes(fieldSchema)) {
796
+ throw new error.MastraError({
797
+ id: storage.createVectorErrorId("QDRANT", "CREATE_PAYLOAD_INDEX", "INVALID_ARGS"),
798
+ text: `fieldSchema must be one of: ${validSchemas.join(", ")}`,
799
+ domain: error.ErrorDomain.STORAGE,
800
+ category: error.ErrorCategory.USER,
801
+ details: { indexName, fieldName, fieldSchema }
802
+ });
803
+ }
804
+ try {
805
+ await this.client.createPayloadIndex(indexName, {
806
+ field_name: fieldName,
807
+ field_schema: fieldSchema,
808
+ wait
809
+ });
810
+ } catch (error$1) {
811
+ const message = error$1?.message || error$1?.toString() || "";
812
+ if (error$1?.status === 409 || message.toLowerCase().includes("exists")) {
813
+ this.logger.info(`Payload index for field "${fieldName}" already exists on collection "${indexName}"`);
814
+ return;
815
+ }
816
+ throw new error.MastraError(
817
+ {
818
+ id: storage.createVectorErrorId("QDRANT", "CREATE_PAYLOAD_INDEX", "FAILED"),
819
+ domain: error.ErrorDomain.STORAGE,
820
+ category: error.ErrorCategory.THIRD_PARTY,
821
+ details: { indexName, fieldName, fieldSchema }
822
+ },
823
+ error$1
824
+ );
825
+ }
826
+ }
827
+ /**
828
+ * Deletes a payload index from a Qdrant collection.
829
+ *
830
+ * @param params - The parameters for deleting the payload index.
831
+ * @param params.indexName - The name of the collection (index) to delete the payload index from.
832
+ * @param params.fieldName - The name of the payload field index to delete.
833
+ * @param params.wait - Whether to wait for the operation to complete. Defaults to true.
834
+ * @returns A promise that resolves when the index is deleted (idempotent if index doesn't exist).
835
+ * @throws Will throw a MastraError if the operation fails.
836
+ *
837
+ * @example
838
+ * ```ts
839
+ * await qdrant.deletePayloadIndex({
840
+ * indexName: 'my-collection',
841
+ * fieldName: 'source',
842
+ * });
843
+ * ```
844
+ */
845
+ async deletePayloadIndex({ indexName, fieldName, wait = true }) {
846
+ if (!indexName || typeof indexName !== "string" || indexName.trim() === "") {
847
+ throw new error.MastraError({
848
+ id: storage.createVectorErrorId("QDRANT", "DELETE_PAYLOAD_INDEX", "INVALID_ARGS"),
849
+ text: "indexName must be a non-empty string",
850
+ domain: error.ErrorDomain.STORAGE,
851
+ category: error.ErrorCategory.USER,
852
+ details: { indexName, fieldName }
853
+ });
854
+ }
855
+ if (!fieldName || typeof fieldName !== "string" || fieldName.trim() === "") {
856
+ throw new error.MastraError({
857
+ id: storage.createVectorErrorId("QDRANT", "DELETE_PAYLOAD_INDEX", "INVALID_ARGS"),
858
+ text: "fieldName must be a non-empty string",
859
+ domain: error.ErrorDomain.STORAGE,
860
+ category: error.ErrorCategory.USER,
861
+ details: { indexName, fieldName }
862
+ });
863
+ }
864
+ try {
865
+ await this.client.deletePayloadIndex(indexName, fieldName, { wait });
866
+ } catch (error$1) {
867
+ const message = error$1?.message || error$1?.toString() || "";
868
+ if (error$1?.status === 404 || message.toLowerCase().includes("not found") || message.toLowerCase().includes("not exist")) {
869
+ this.logger.info(`Payload index for field "${fieldName}" does not exist on collection "${indexName}"`);
870
+ return;
871
+ }
872
+ throw new error.MastraError(
873
+ {
874
+ id: storage.createVectorErrorId("QDRANT", "DELETE_PAYLOAD_INDEX", "FAILED"),
875
+ domain: error.ErrorDomain.STORAGE,
876
+ category: error.ErrorCategory.THIRD_PARTY,
877
+ details: { indexName, fieldName }
878
+ },
879
+ error$1
880
+ );
881
+ }
882
+ }
728
883
  };
729
884
 
730
885
  // src/vector/prompt.ts