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