@mastra/weaviate 0.0.0-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/dist/index.cjs ADDED
@@ -0,0 +1,831 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let _mastra_core_error = require("@mastra/core/error");
25
+ let _mastra_core_storage = require("@mastra/core/storage");
26
+ let _mastra_core_vector = require("@mastra/core/vector");
27
+ let weaviate_client = require("weaviate-client");
28
+ weaviate_client = __toESM(weaviate_client, 1);
29
+ let _mastra_core_vector_filter = require("@mastra/core/vector/filter");
30
+ //#region src/vector/encoding.ts
31
+ /**
32
+ * Weaviate reserves certain property names (e.g. `id`, `vector`). Metadata keys
33
+ * that collide are stored under a stable prefix and restored on read. This
34
+ * module is the single source of truth shared by the adapter and the filter
35
+ * translator — they must encode keys identically or filters will silently miss.
36
+ */
37
+ /** Internal property used to round-trip the caller's original id. */
38
+ const MASTRA_ID_PROPERTY = "mastraId";
39
+ const META_KEY_PREFIX = "mastraMeta_";
40
+ const RESERVED_META_KEYS = /* @__PURE__ */ new Set([
41
+ "id",
42
+ "vector",
43
+ "_additional",
44
+ MASTRA_ID_PROPERTY
45
+ ]);
46
+ function encodeMetaKey(key) {
47
+ return RESERVED_META_KEYS.has(key) || key.startsWith("mastraMeta_") ? `${META_KEY_PREFIX}${key}` : key;
48
+ }
49
+ function decodeMetaKey(key) {
50
+ return key.startsWith("mastraMeta_") ? key.slice(11) : key;
51
+ }
52
+ function encodeMetaProperties(metadata) {
53
+ if (!metadata) return {};
54
+ const out = {};
55
+ for (const [key, value] of Object.entries(metadata)) out[encodeMetaKey(key)] = value;
56
+ return out;
57
+ }
58
+ //#endregion
59
+ //#region src/vector/filter.ts
60
+ /**
61
+ * Translates MongoDB-style filters into Weaviate `FilterValue` objects.
62
+ *
63
+ * Weaviate filters are built from the collection's `filter` API (which produces
64
+ * protobuf-backed targets), so `translate` requires the collection filter API to
65
+ * be supplied alongside the filter.
66
+ */
67
+ var WeaviateFilterTranslator = class extends _mastra_core_vector_filter.BaseFilterTranslator {
68
+ getSupportedOperators() {
69
+ return {
70
+ logical: [
71
+ "$and",
72
+ "$or",
73
+ "$not"
74
+ ],
75
+ basic: ["$eq", "$ne"],
76
+ numeric: [
77
+ "$gt",
78
+ "$gte",
79
+ "$lt",
80
+ "$lte"
81
+ ],
82
+ array: [
83
+ "$in",
84
+ "$nin",
85
+ "$all"
86
+ ],
87
+ element: ["$exists"],
88
+ regex: [],
89
+ custom: []
90
+ };
91
+ }
92
+ isOperator(key) {
93
+ return super.isOperator(key) || key === "$not";
94
+ }
95
+ translate(filter, api) {
96
+ if (this.isEmpty(filter)) return void 0;
97
+ if (!api) throw new Error("WeaviateFilterTranslator.translate requires a collection filter API");
98
+ this.validateFilter(filter);
99
+ return this.translateNode(filter, api);
100
+ }
101
+ combine(parts) {
102
+ const filtered = parts.filter((p) => p !== void 0);
103
+ if (filtered.length === 0) return void 0;
104
+ if (filtered.length === 1) return filtered[0];
105
+ return weaviate_client.Filters.and(...filtered);
106
+ }
107
+ translateNode(node, api) {
108
+ const parts = Object.entries(node).map(([key, value]) => {
109
+ if (key === "$and") return this.combineLogical("and", value, api);
110
+ if (key === "$or") return this.combineLogical("or", value, api);
111
+ if (key === "$not") return this.negateNode(value, api);
112
+ return this.translateField(key, value, api);
113
+ });
114
+ return this.combine(parts);
115
+ }
116
+ /** Combines parts with OR, dropping undefined entries. */
117
+ combineOr(parts) {
118
+ const filtered = parts.filter((p) => p !== void 0);
119
+ if (filtered.length === 0) return void 0;
120
+ if (filtered.length === 1) return filtered[0];
121
+ return weaviate_client.Filters.or(...filtered);
122
+ }
123
+ /**
124
+ * Returns the negation of a node. A node's entries are AND-combined, so the
125
+ * negation is the OR of each entry's negation (De Morgan).
126
+ */
127
+ negateNode(node, api) {
128
+ const parts = Object.entries(node).map(([key, value]) => {
129
+ if (key === "$and") return this.combineOr(value.map((v) => this.negateNode(v, api)));
130
+ if (key === "$or") return this.combine(value.map((v) => this.negateNode(v, api)));
131
+ if (key === "$not") return this.translateNode(value, api);
132
+ return this.negateField(key, value, api);
133
+ });
134
+ return this.combineOr(parts);
135
+ }
136
+ /** Returns the negation of a single field condition. */
137
+ negateField(field, value, api) {
138
+ const prop = api.byProperty(encodeMetaKey(field));
139
+ if (value === null) return prop.isNull(false);
140
+ if (this.isPrimitive(value)) return prop.notEqual(this.normalizeComparisonValue(value));
141
+ if (Array.isArray(value)) return this.combine(this.normalizeArrayValues(value).map((v) => prop.notEqual(v)));
142
+ const parts = Object.entries(value).map(([op, opValue]) => this.negateSingleOp(field, op, opValue, api));
143
+ return this.combineOr(parts);
144
+ }
145
+ negateSingleOp(field, op, value, api) {
146
+ const prop = api.byProperty(encodeMetaKey(field));
147
+ switch (op) {
148
+ case "$eq": return value === null ? prop.isNull(false) : prop.notEqual(this.normalizeComparisonValue(value));
149
+ case "$ne": return value === null ? prop.isNull(true) : prop.equal(this.normalizeComparisonValue(value));
150
+ case "$gt": return prop.lessOrEqual(this.normalizeComparisonValue(value));
151
+ case "$gte": return prop.lessThan(this.normalizeComparisonValue(value));
152
+ case "$lt": return prop.greaterOrEqual(this.normalizeComparisonValue(value));
153
+ case "$lte": return prop.greaterThan(this.normalizeComparisonValue(value));
154
+ case "$in": return this.combine(this.normalizeArrayValues(value).map((v) => prop.notEqual(v)));
155
+ case "$nin": return prop.containsAny(this.normalizeArrayValues(value));
156
+ case "$exists": return prop.isNull(!!value);
157
+ case "$not": return this.translateField(field, value, api);
158
+ default: throw unsupportedOperatorError(op, field);
159
+ }
160
+ }
161
+ combineLogical(op, values, api) {
162
+ const translated = values.map((v) => this.translateNode(v, api)).filter((p) => p !== void 0);
163
+ if (translated.length === 0) return void 0;
164
+ if (translated.length === 1) return translated[0];
165
+ return op === "and" ? weaviate_client.Filters.and(...translated) : weaviate_client.Filters.or(...translated);
166
+ }
167
+ translateField(field, value, api) {
168
+ const prop = api.byProperty(encodeMetaKey(field));
169
+ if (value === null) return prop.isNull(true);
170
+ if (this.isPrimitive(value)) return prop.equal(this.normalizeComparisonValue(value));
171
+ if (Array.isArray(value)) return prop.containsAny(this.normalizeArrayValues(value));
172
+ const parts = Object.entries(value).map(([op, opValue]) => this.translateOperator(field, op, opValue, api));
173
+ return this.combine(parts);
174
+ }
175
+ translateOperator(field, op, value, api) {
176
+ const prop = api.byProperty(encodeMetaKey(field));
177
+ switch (op) {
178
+ case "$eq": return value === null ? prop.isNull(true) : prop.equal(this.normalizeComparisonValue(value));
179
+ case "$ne": return value === null ? prop.isNull(false) : prop.notEqual(this.normalizeComparisonValue(value));
180
+ case "$gt": return prop.greaterThan(this.normalizeComparisonValue(value));
181
+ case "$gte": return prop.greaterOrEqual(this.normalizeComparisonValue(value));
182
+ case "$lt": return prop.lessThan(this.normalizeComparisonValue(value));
183
+ case "$lte": return prop.lessOrEqual(this.normalizeComparisonValue(value));
184
+ case "$in": return prop.containsAny(this.normalizeArrayValues(value));
185
+ case "$nin": return this.combine(this.normalizeArrayValues(value).map((v) => prop.notEqual(v)));
186
+ case "$all": return prop.containsAll(this.normalizeArrayValues(value));
187
+ case "$exists": return prop.isNull(!value);
188
+ case "$not": return this.negateField(field, value, api);
189
+ default: throw unsupportedOperatorError(op, field);
190
+ }
191
+ }
192
+ };
193
+ /** Builds a user-facing error for an operator Weaviate cannot translate. */
194
+ function unsupportedOperatorError(op, field) {
195
+ return new _mastra_core_error.MastraError({
196
+ id: "STORAGE_WEAVIATE_FILTER_UNSUPPORTED_OPERATOR",
197
+ text: `Unsupported filter operator "${op}" on field "${field}"`,
198
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
199
+ category: _mastra_core_error.ErrorCategory.USER,
200
+ details: {
201
+ operator: op,
202
+ field
203
+ }
204
+ });
205
+ }
206
+ //#endregion
207
+ //#region src/vector/index.ts
208
+ /**
209
+ * Weaviate distance metrics mapped from Mastra metric names.
210
+ * @see https://weaviate.io/developers/weaviate/config-refs/distances
211
+ */
212
+ const DISTANCE_MAPPING = {
213
+ cosine: "cosine",
214
+ euclidean: "l2-squared",
215
+ dotproduct: "dot"
216
+ };
217
+ const REVERSE_DISTANCE_MAPPING = {
218
+ cosine: "cosine",
219
+ "l2-squared": "euclidean",
220
+ dot: "dotproduct"
221
+ };
222
+ /**
223
+ * A Mastra vector store backed by Weaviate.
224
+ *
225
+ * Vectors are stored in `vectorizer: none` collections (Mastra supplies the
226
+ * embeddings). Because Weaviate requires UUID object ids and capitalised
227
+ * collection names, this adapter maps arbitrary Mastra ids to deterministic
228
+ * UUIDv5 values (preserving the original id in a reserved property) and
229
+ * preserves the original index name in the collection description.
230
+ */
231
+ var WeaviateVector = class extends _mastra_core_vector.MastraVector {
232
+ clientPromise = null;
233
+ connectOptions;
234
+ /** Cache of property names known to exist in a collection's schema. */
235
+ knownProperties = /* @__PURE__ */ new Map();
236
+ /** Serializes schema mutations per collection to avoid concurrent addProperty races. */
237
+ schemaLocks = /* @__PURE__ */ new Map();
238
+ constructor(params) {
239
+ super({ id: params.id });
240
+ this.connectOptions = params;
241
+ }
242
+ getClient() {
243
+ if (!this.clientPromise) {
244
+ const { httpHost, httpPort, httpSecure, grpcHost, grpcPort, grpcSecure, apiKey, headers } = this.connectOptions;
245
+ this.clientPromise = weaviate_client.default.connectToCustom({
246
+ httpHost: httpHost ?? "localhost",
247
+ httpPort: httpPort ?? 8080,
248
+ httpSecure: httpSecure ?? false,
249
+ grpcHost: grpcHost ?? httpHost ?? "localhost",
250
+ grpcPort: grpcPort ?? 50051,
251
+ grpcSecure: grpcSecure ?? false,
252
+ ...apiKey ? { authCredentials: new weaviate_client.default.ApiKey(apiKey) } : {},
253
+ ...headers ? { headers } : {}
254
+ });
255
+ }
256
+ return this.clientPromise;
257
+ }
258
+ /** Closes the underlying Weaviate connection. */
259
+ async disconnect() {
260
+ if (this.clientPromise) {
261
+ await (await this.clientPromise).close();
262
+ this.clientPromise = null;
263
+ }
264
+ }
265
+ /** Weaviate collection names must start with an uppercase letter. */
266
+ toCollectionName(indexName) {
267
+ return indexName.charAt(0).toUpperCase() + indexName.slice(1);
268
+ }
269
+ async getCollection(indexName) {
270
+ return (await this.getClient()).collections.get(this.toCollectionName(indexName));
271
+ }
272
+ parseMeta(description) {
273
+ if (!description) return null;
274
+ try {
275
+ const parsed = JSON.parse(description);
276
+ if (parsed && typeof parsed === "object" && typeof parsed.name === "string") return parsed;
277
+ } catch {}
278
+ return null;
279
+ }
280
+ inferDataType(value) {
281
+ if (typeof value === "string") return "text";
282
+ if (typeof value === "number") return "number";
283
+ if (typeof value === "boolean") return "boolean";
284
+ if (Array.isArray(value)) {
285
+ const first = value.find((v) => v !== null && v !== void 0);
286
+ if (typeof first === "string") return "text[]";
287
+ if (typeof first === "number") return "number[]";
288
+ if (typeof first === "boolean") return "boolean[]";
289
+ return null;
290
+ }
291
+ return null;
292
+ }
293
+ /**
294
+ * Ensures every metadata key across the batch exists as a collection property.
295
+ * Weaviate's auto-schema would create text properties with `word` tokenization
296
+ * (breaking exact-match filtering), so properties are created explicitly with
297
+ * `field` tokenization for text values.
298
+ */
299
+ async ensureProperties(collection, collectionName, metadata) {
300
+ if (!metadata?.length) return;
301
+ const next = (this.schemaLocks.get(collectionName) ?? Promise.resolve()).catch(() => void 0).then(() => this.ensurePropertiesLocked(collection, collectionName, metadata));
302
+ this.schemaLocks.set(collectionName, next);
303
+ await next;
304
+ }
305
+ async ensurePropertiesLocked(collection, collectionName, metadata) {
306
+ let known = this.knownProperties.get(collectionName);
307
+ if (!known) {
308
+ const config = await collection.config.get();
309
+ known = new Set(config.properties.map((p) => p.name));
310
+ this.knownProperties.set(collectionName, known);
311
+ }
312
+ const seen = /* @__PURE__ */ new Map();
313
+ for (const row of metadata) {
314
+ if (!row) continue;
315
+ for (const [rawKey, value] of Object.entries(row)) {
316
+ const key = encodeMetaKey(rawKey);
317
+ if (known.has(key) || seen.has(key) || value === null || value === void 0) continue;
318
+ const dataType = this.inferDataType(value);
319
+ if (dataType) seen.set(key, dataType);
320
+ }
321
+ }
322
+ for (const [name, dataType] of seen) {
323
+ try {
324
+ await collection.config.addProperty({
325
+ name,
326
+ dataType,
327
+ ...dataType === "text" || dataType === "text[]" ? { tokenization: "field" } : {}
328
+ });
329
+ } catch (error) {
330
+ if (!/already/i.test(error?.message ?? "")) throw error;
331
+ }
332
+ known.add(name);
333
+ }
334
+ }
335
+ async createIndex({ indexName, dimension, metric = "cosine" }) {
336
+ try {
337
+ if (!Number.isInteger(dimension) || dimension <= 0) throw new _mastra_core_error.MastraError({
338
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "CREATE_INDEX", "INVALID_ARGS"),
339
+ text: "Dimension must be a positive integer",
340
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
341
+ category: _mastra_core_error.ErrorCategory.USER,
342
+ details: {
343
+ indexName,
344
+ dimension
345
+ }
346
+ });
347
+ const distance = DISTANCE_MAPPING[metric];
348
+ if (!distance) throw new _mastra_core_error.MastraError({
349
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "CREATE_INDEX", "INVALID_ARGS"),
350
+ text: `Invalid metric: ${metric}. Must be one of: cosine, euclidean, dotproduct`,
351
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
352
+ category: _mastra_core_error.ErrorCategory.USER,
353
+ details: {
354
+ indexName,
355
+ metric
356
+ }
357
+ });
358
+ const client = await this.getClient();
359
+ const collectionName = this.toCollectionName(indexName);
360
+ if (await client.collections.exists(collectionName)) {
361
+ const existingConfig = await client.collections.get(collectionName).config.get();
362
+ const existingMeta = this.parseMeta(existingConfig.description);
363
+ if (existingMeta && existingMeta.name !== indexName) throw new _mastra_core_error.MastraError({
364
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "CREATE_INDEX", "NAME_COLLISION"),
365
+ text: `Index name "${indexName}" collides with existing index "${existingMeta.name}" (Weaviate collection "${collectionName}"). Weaviate capitalises the first letter of collection names, so these names cannot coexist.`,
366
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
367
+ category: _mastra_core_error.ErrorCategory.USER,
368
+ details: {
369
+ indexName,
370
+ existingName: existingMeta.name,
371
+ collectionName
372
+ }
373
+ });
374
+ await this.validateExistingIndex(indexName, dimension, metric);
375
+ return;
376
+ }
377
+ const meta = {
378
+ name: indexName,
379
+ dimension,
380
+ metric
381
+ };
382
+ await client.collections.create({
383
+ name: collectionName,
384
+ description: JSON.stringify(meta),
385
+ properties: [{
386
+ name: MASTRA_ID_PROPERTY,
387
+ dataType: "text",
388
+ tokenization: "field"
389
+ }],
390
+ invertedIndex: weaviate_client.default.configure.invertedIndex({ indexNullState: true }),
391
+ vectorizers: weaviate_client.default.configure.vectors.selfProvided({ vectorIndexConfig: weaviate_client.default.configure.vectorIndex.hnsw({ distanceMetric: distance }) })
392
+ });
393
+ this.knownProperties.set(collectionName, /* @__PURE__ */ new Set([MASTRA_ID_PROPERTY]));
394
+ } catch (error) {
395
+ if (error instanceof _mastra_core_error.MastraError) throw error;
396
+ throw new _mastra_core_error.MastraError({
397
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "CREATE_INDEX", "FAILED"),
398
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
399
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
400
+ details: { indexName }
401
+ }, error);
402
+ }
403
+ }
404
+ /** Fetches a collection's stored metadata, throwing if the index does not exist. */
405
+ async requireMeta(indexName, operation) {
406
+ const client = await this.getClient();
407
+ const collectionName = this.toCollectionName(indexName);
408
+ if (!await client.collections.exists(collectionName)) throw new _mastra_core_error.MastraError({
409
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", operation, "INDEX_NOT_FOUND"),
410
+ text: `Index ${indexName} does not exist`,
411
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
412
+ category: _mastra_core_error.ErrorCategory.USER,
413
+ details: { indexName }
414
+ });
415
+ const config = await client.collections.get(collectionName).config.get();
416
+ return this.parseMeta(config.description);
417
+ }
418
+ async upsert({ indexName, vectors, metadata, ids }) {
419
+ try {
420
+ (0, _mastra_core_vector.validateUpsertInput)("WEAVIATE", vectors, metadata, ids);
421
+ (0, _mastra_core_vector.validateVectorValues)("WEAVIATE", vectors);
422
+ const meta = await this.requireMeta(indexName, "UPSERT");
423
+ if (meta?.dimension) {
424
+ const mismatch = vectors.find((v) => v.length !== meta.dimension);
425
+ if (mismatch) throw new _mastra_core_error.MastraError({
426
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "UPSERT", "DIMENSION_MISMATCH"),
427
+ text: `Vector dimension ${mismatch.length} does not match index dimension ${meta.dimension}`,
428
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
429
+ category: _mastra_core_error.ErrorCategory.USER,
430
+ details: {
431
+ indexName,
432
+ expected: meta.dimension,
433
+ actual: mismatch.length
434
+ }
435
+ });
436
+ }
437
+ const collection = await this.getCollection(indexName);
438
+ await this.ensureProperties(collection, this.toCollectionName(indexName), metadata);
439
+ const originalIds = ids ?? vectors.map(() => crypto.randomUUID());
440
+ const objects = vectors.map((vector, i) => {
441
+ const originalId = originalIds[i];
442
+ return {
443
+ id: (0, weaviate_client.generateUuid5)(originalId),
444
+ vectors: vector,
445
+ properties: {
446
+ ...encodeMetaProperties(metadata?.[i]),
447
+ [MASTRA_ID_PROPERTY]: originalId
448
+ }
449
+ };
450
+ });
451
+ const result = await collection.data.insertMany(objects);
452
+ if (result.hasErrors) {
453
+ const firstError = Object.values(result.errors)[0];
454
+ throw new Error(firstError?.message ?? "Weaviate insertMany reported errors");
455
+ }
456
+ return originalIds;
457
+ } catch (error) {
458
+ if (error instanceof _mastra_core_error.MastraError) throw error;
459
+ throw new _mastra_core_error.MastraError({
460
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "UPSERT", "FAILED"),
461
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
462
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
463
+ details: { indexName }
464
+ }, error);
465
+ }
466
+ }
467
+ transformFilter(collection, filter) {
468
+ return new WeaviateFilterTranslator().translate(filter, collection.filter);
469
+ }
470
+ toQueryResult(obj, includeVector) {
471
+ const raw = obj.properties ?? {};
472
+ const originalId = raw[MASTRA_ID_PROPERTY];
473
+ const properties = {};
474
+ for (const [key, value] of Object.entries(raw)) {
475
+ if (key === "mastraId" || value === void 0) continue;
476
+ properties[decodeMetaKey(key)] = value;
477
+ }
478
+ const distance = obj.metadata?.distance;
479
+ const score = typeof distance === "number" ? 1 - distance : obj.metadata?.certainty ?? 0;
480
+ const result = {
481
+ id: typeof originalId === "string" ? originalId : obj.uuid,
482
+ score,
483
+ metadata: properties
484
+ };
485
+ if (includeVector) {
486
+ const vectors = obj.vectors ?? {};
487
+ result.vector = vectors.default ?? Object.values(vectors)[0];
488
+ }
489
+ return result;
490
+ }
491
+ async query({ indexName, queryVector, topK = 10, filter, includeVector = false }) {
492
+ try {
493
+ (0, _mastra_core_vector.validateTopK)("WEAVIATE", topK);
494
+ const meta = await this.requireMeta(indexName, "QUERY");
495
+ if (queryVector && meta?.dimension && queryVector.length !== meta.dimension) throw new _mastra_core_error.MastraError({
496
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "QUERY", "DIMENSION_MISMATCH"),
497
+ text: `Query vector dimension ${queryVector.length} does not match index dimension ${meta.dimension}`,
498
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
499
+ category: _mastra_core_error.ErrorCategory.USER,
500
+ details: {
501
+ indexName,
502
+ expected: meta.dimension,
503
+ actual: queryVector.length
504
+ }
505
+ });
506
+ const collection = await this.getCollection(indexName);
507
+ const filters = this.transformFilter(collection, filter);
508
+ const returnMetadata = ["distance"];
509
+ if (queryVector) return (await collection.query.nearVector(queryVector, {
510
+ limit: topK,
511
+ includeVector,
512
+ returnMetadata,
513
+ ...filters ? { filters } : {}
514
+ })).objects.map((obj) => this.toQueryResult(obj, includeVector));
515
+ return (await collection.query.fetchObjects({
516
+ limit: topK,
517
+ includeVector,
518
+ ...filters ? { filters } : {}
519
+ })).objects.map((obj) => this.toQueryResult(obj, includeVector));
520
+ } catch (error) {
521
+ if (error instanceof _mastra_core_error.MastraError) throw error;
522
+ throw new _mastra_core_error.MastraError({
523
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "QUERY", "FAILED"),
524
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
525
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
526
+ details: { indexName }
527
+ }, error);
528
+ }
529
+ }
530
+ async listIndexes() {
531
+ try {
532
+ return (await (await this.getClient()).collections.listAll()).map((config) => {
533
+ return this.parseMeta(config.description)?.name ?? config.name;
534
+ });
535
+ } catch (error) {
536
+ throw new _mastra_core_error.MastraError({
537
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "LIST_INDEXES", "FAILED"),
538
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
539
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY
540
+ }, error);
541
+ }
542
+ }
543
+ async describeIndex({ indexName }) {
544
+ try {
545
+ const client = await this.getClient();
546
+ const collectionName = this.toCollectionName(indexName);
547
+ if (!await client.collections.exists(collectionName)) throw new _mastra_core_error.MastraError({
548
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DESCRIBE_INDEX", "INDEX_NOT_FOUND"),
549
+ text: `Index ${indexName} does not exist`,
550
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
551
+ category: _mastra_core_error.ErrorCategory.USER,
552
+ details: { indexName }
553
+ });
554
+ const collection = client.collections.get(collectionName);
555
+ const config = await collection.config.get();
556
+ const meta = this.parseMeta(config.description);
557
+ const count = await collection.length();
558
+ let dimension = meta?.dimension ?? 0;
559
+ if (!dimension) {
560
+ const vectors = (await collection.query.fetchObjects({
561
+ limit: 1,
562
+ includeVector: true
563
+ })).objects[0]?.vectors ?? {};
564
+ const vec = vectors.default ?? Object.values(vectors)[0];
565
+ if (Array.isArray(vec)) dimension = vec.length;
566
+ }
567
+ let metric = meta?.metric;
568
+ if (!metric) {
569
+ const distance = (config.vectorizers?.default ?? Object.values(config.vectorizers ?? {})[0])?.indexConfig?.distance;
570
+ metric = distance ? REVERSE_DISTANCE_MAPPING[distance] : void 0;
571
+ }
572
+ return {
573
+ dimension,
574
+ count,
575
+ metric
576
+ };
577
+ } catch (error) {
578
+ if (error instanceof _mastra_core_error.MastraError) throw error;
579
+ throw new _mastra_core_error.MastraError({
580
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DESCRIBE_INDEX", "FAILED"),
581
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
582
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
583
+ details: { indexName }
584
+ }, error);
585
+ }
586
+ }
587
+ async deleteIndex({ indexName }) {
588
+ try {
589
+ await (await this.getClient()).collections.delete(this.toCollectionName(indexName));
590
+ } catch (error) {
591
+ throw new _mastra_core_error.MastraError({
592
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DELETE_INDEX", "FAILED"),
593
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
594
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
595
+ details: { indexName }
596
+ }, error);
597
+ }
598
+ }
599
+ async updateVector({ indexName, id, filter, update }) {
600
+ try {
601
+ if (id !== void 0 && filter !== void 0) throw new _mastra_core_error.MastraError({
602
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "UPDATE_VECTOR", "INVALID_ARGS"),
603
+ text: "id and filter are mutually exclusive",
604
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
605
+ category: _mastra_core_error.ErrorCategory.USER,
606
+ details: { indexName }
607
+ });
608
+ if (!update || !update.vector && !update.metadata) throw new _mastra_core_error.MastraError({
609
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "UPDATE_VECTOR", "INVALID_ARGS"),
610
+ text: "Update data is required: no updates provided",
611
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
612
+ category: _mastra_core_error.ErrorCategory.USER,
613
+ details: { indexName }
614
+ });
615
+ if (id === void 0 && filter === void 0) throw new _mastra_core_error.MastraError({
616
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "UPDATE_VECTOR", "INVALID_ARGS"),
617
+ text: "Either id or filter must be provided",
618
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
619
+ category: _mastra_core_error.ErrorCategory.USER,
620
+ details: { indexName }
621
+ });
622
+ if (id === void 0 && (typeof filter !== "object" || filter === null || Object.keys(filter).length === 0)) throw new _mastra_core_error.MastraError({
623
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "UPDATE_VECTOR", "INVALID_ARGS"),
624
+ text: "A non-empty filter is required: empty filter not allowed",
625
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
626
+ category: _mastra_core_error.ErrorCategory.USER,
627
+ details: { indexName }
628
+ });
629
+ const collection = await this.getCollection(indexName);
630
+ if (update.metadata) await this.ensureProperties(collection, this.toCollectionName(indexName), [update.metadata]);
631
+ const encodedProperties = update.metadata ? encodeMetaProperties(update.metadata) : void 0;
632
+ const applyUpdate = async (uuid) => {
633
+ await collection.data.update({
634
+ id: uuid,
635
+ ...encodedProperties ? { properties: encodedProperties } : {},
636
+ ...update.vector ? { vectors: update.vector } : {}
637
+ });
638
+ };
639
+ if (id !== void 0) {
640
+ await applyUpdate((0, weaviate_client.generateUuid5)(id));
641
+ return;
642
+ }
643
+ const filters = this.transformFilter(collection, filter);
644
+ const PAGE_SIZE = 1e3;
645
+ const MAX_FILTERED_UPDATE = 1e4;
646
+ const uuids = [];
647
+ for (let offset = 0;; offset += PAGE_SIZE) {
648
+ if (offset >= MAX_FILTERED_UPDATE) throw new _mastra_core_error.MastraError({
649
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "UPDATE_VECTOR", "INVALID_ARGS"),
650
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
651
+ category: _mastra_core_error.ErrorCategory.USER,
652
+ text: `Filtered updateVector matched more than ${MAX_FILTERED_UPDATE} vectors, which exceeds Weaviate's query result cap. Narrow the filter or update by id.`,
653
+ details: {
654
+ indexName,
655
+ limit: MAX_FILTERED_UPDATE
656
+ }
657
+ });
658
+ const page = await collection.query.fetchObjects({
659
+ limit: PAGE_SIZE,
660
+ offset,
661
+ ...filters ? { filters } : {}
662
+ });
663
+ for (const obj of page.objects) uuids.push(obj.uuid);
664
+ if (page.objects.length < PAGE_SIZE) break;
665
+ }
666
+ for (const uuid of uuids) await applyUpdate(uuid);
667
+ } catch (error) {
668
+ if (error instanceof _mastra_core_error.MastraError) throw error;
669
+ throw new _mastra_core_error.MastraError({
670
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "UPDATE_VECTOR", "FAILED"),
671
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
672
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
673
+ details: {
674
+ indexName,
675
+ ...id ? { id } : {}
676
+ }
677
+ }, error);
678
+ }
679
+ }
680
+ async deleteVector({ indexName, id }) {
681
+ try {
682
+ await (await this.getCollection(indexName)).data.deleteById((0, weaviate_client.generateUuid5)(id));
683
+ } catch (error) {
684
+ throw new _mastra_core_error.MastraError({
685
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DELETE_VECTOR", "FAILED"),
686
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
687
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
688
+ details: {
689
+ indexName,
690
+ id
691
+ }
692
+ }, error);
693
+ }
694
+ }
695
+ async deleteVectors({ indexName, filter, ids }) {
696
+ if (ids && filter) throw new _mastra_core_error.MastraError({
697
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
698
+ text: "Cannot specify both ids and filter - they are mutually exclusive",
699
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
700
+ category: _mastra_core_error.ErrorCategory.USER,
701
+ details: { indexName }
702
+ });
703
+ if (!ids && !filter) throw new _mastra_core_error.MastraError({
704
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DELETE_VECTORS", "NO_TARGET"),
705
+ text: "Either filter or ids must be provided",
706
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
707
+ category: _mastra_core_error.ErrorCategory.USER,
708
+ details: { indexName }
709
+ });
710
+ if (ids && ids.length === 0) throw new _mastra_core_error.MastraError({
711
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DELETE_VECTORS", "EMPTY_IDS"),
712
+ text: "Cannot delete with empty ids array",
713
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
714
+ category: _mastra_core_error.ErrorCategory.USER,
715
+ details: { indexName }
716
+ });
717
+ if (filter && typeof filter === "object" && Object.keys(filter).length === 0) throw new _mastra_core_error.MastraError({
718
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DELETE_VECTORS", "EMPTY_FILTER"),
719
+ text: "Cannot delete with empty filter object",
720
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
721
+ category: _mastra_core_error.ErrorCategory.USER,
722
+ details: { indexName }
723
+ });
724
+ try {
725
+ const collection = await this.getCollection(indexName);
726
+ if (ids) for (const id of ids) await collection.data.deleteById((0, weaviate_client.generateUuid5)(id));
727
+ else if (filter) {
728
+ const filters = this.transformFilter(collection, filter);
729
+ if (filters) await collection.data.deleteMany(filters);
730
+ }
731
+ } catch (error) {
732
+ if (error instanceof _mastra_core_error.MastraError) throw error;
733
+ throw new _mastra_core_error.MastraError({
734
+ id: (0, _mastra_core_storage.createVectorErrorId)("WEAVIATE", "DELETE_VECTORS", "FAILED"),
735
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
736
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
737
+ details: {
738
+ indexName,
739
+ ...filter && { filter: JSON.stringify(filter) },
740
+ ...ids && { idsCount: ids.length }
741
+ }
742
+ }, error);
743
+ }
744
+ }
745
+ };
746
+ //#endregion
747
+ //#region src/vector/prompt.ts
748
+ /**
749
+ * Vector store specific prompt that details supported operators and examples.
750
+ * This prompt helps users construct valid filters for Weaviate Vector.
751
+ */
752
+ const WEAVIATE_PROMPT = `When querying Weaviate, you can ONLY use the operators listed below. Any other operators will be rejected.
753
+ Important: Don't explain how to construct the filter - use the specified operators and fields to search the content and return relevant results.
754
+ If a user tries to give an explicit operator that is not supported, reject the filter entirely and let them know that the operator is not supported.
755
+
756
+ Basic Comparison Operators:
757
+ - $eq: Exact match (default when using field: value)
758
+ Example: { "category": "electronics" }
759
+ - $ne: Not equal
760
+ Example: { "category": { "$ne": "electronics" } }
761
+ - $gt: Greater than
762
+ Example: { "price": { "$gt": 100 } }
763
+ - $gte: Greater than or equal
764
+ Example: { "price": { "$gte": 100 } }
765
+ - $lt: Less than
766
+ Example: { "price": { "$lt": 100 } }
767
+ - $lte: Less than or equal
768
+ Example: { "price": { "$lte": 100 } }
769
+
770
+ Array Operators:
771
+ - $in: Match any value in array
772
+ Example: { "category": { "$in": ["electronics", "books"] } }
773
+ - $nin: Does not match any value in array
774
+ Example: { "category": { "$nin": ["electronics", "books"] } }
775
+ - $all: Match arrays containing all values
776
+ Example: { "tags": { "$all": ["sale", "new"] } }
777
+
778
+ Logical Operators:
779
+ - $and: Logical AND (can be implicit or explicit)
780
+ Implicit Example: { "price": { "$gt": 100 }, "category": "electronics" }
781
+ Explicit Example: { "$and": [{ "price": { "$gt": 100 } }, { "category": "electronics" }] }
782
+ - $or: Logical OR
783
+ Example: { "$or": [{ "price": { "$lt": 50 } }, { "category": "books" }] }
784
+ - $not: Logical NOT
785
+ Example: { "$not": { "category": "electronics" } }
786
+
787
+ Element Operators:
788
+ - $exists: Check if field exists (is not null)
789
+ Example: { "rating": { "$exists": true } }
790
+
791
+ Restrictions:
792
+ - Regex patterns are not supported
793
+ - Only $and, $or, and $not logical operators are supported at the top level
794
+ - Empty arrays in $in/$nin will return no results
795
+ - Multiple conditions on the same field are supported with both implicit and explicit $and
796
+ - At least one key-value pair is required in filter object
797
+ - Empty objects and undefined values are treated as no filter
798
+ - Invalid types in comparison operators will throw errors
799
+ - All non-logical operators must be used within a field condition
800
+ Valid: { "field": { "$gt": 100 } }
801
+ Valid: { "$and": [...] }
802
+ Invalid: { "$gt": 100 }
803
+ - Logical operators must contain field conditions, not direct operators
804
+ Valid: { "$and": [{ "field": { "$gt": 100 } }] }
805
+ Invalid: { "$and": [{ "$gt": 100 }] }
806
+ - Logical operators ($and, $or, $not):
807
+ - Can only be used at top level or nested within other logical operators
808
+ - Can not be used on a field level, or be nested inside a field
809
+ - Can not be used inside an operator
810
+ - Valid: { "$and": [{ "field": { "$gt": 100 } }] }
811
+ - Valid: { "$or": [{ "$and": [{ "field": { "$gt": 100 } }] }] }
812
+ - Invalid: { "field": { "$and": [{ "$gt": 100 }] } }
813
+
814
+ Example Complex Query:
815
+ {
816
+ "$and": [
817
+ { "category": { "$in": ["electronics", "computers"] } },
818
+ { "price": { "$gte": 100, "$lte": 1000 } },
819
+ { "rating": { "$exists": true, "$gt": 4 } },
820
+ { "$or": [
821
+ { "stock": { "$gt": 0 } },
822
+ { "preorder": { "$eq": true } }
823
+ ]},
824
+ { "$not": { "status": "discontinued" } }
825
+ ]
826
+ }`;
827
+ //#endregion
828
+ exports.WEAVIATE_PROMPT = WEAVIATE_PROMPT;
829
+ exports.WeaviateVector = WeaviateVector;
830
+
831
+ //# sourceMappingURL=index.cjs.map