@mastra/turbopuffer 1.2.0 → 1.2.1-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/LICENSE.md +6 -4
- package/dist/docs/SKILL.md +2 -2
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-vectors-turbopuffer.md +3 -1
- package/dist/index.cjs +575 -681
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +572 -677
- package/dist/index.js.map +1 -1
- package/dist/vector/filter.d.ts.map +1 -1
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +12 -12
- package/CHANGELOG.md +0 -1559
package/dist/index.cjs
CHANGED
|
@@ -1,685 +1,579 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
*/
|
|
155
|
-
normalizeValue(value) {
|
|
156
|
-
if (value instanceof Date) {
|
|
157
|
-
return value.toISOString();
|
|
158
|
-
}
|
|
159
|
-
return value;
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Normalize array values
|
|
163
|
-
*/
|
|
164
|
-
normalizeArrayValues(values) {
|
|
165
|
-
return values.map((value) => this.normalizeValue(value));
|
|
166
|
-
}
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _mastra_core_error = require("@mastra/core/error");
|
|
3
|
+
let _mastra_core_storage = require("@mastra/core/storage");
|
|
4
|
+
let _mastra_core_vector = require("@mastra/core/vector");
|
|
5
|
+
let _turbopuffer_turbopuffer = require("@turbopuffer/turbopuffer");
|
|
6
|
+
let _mastra_core_vector_filter = require("@mastra/core/vector/filter");
|
|
7
|
+
//#region src/vector/filter.ts
|
|
8
|
+
/**
|
|
9
|
+
* Translator for converting Mastra filters to Turbopuffer format
|
|
10
|
+
*
|
|
11
|
+
* Mastra filters: { field: { $gt: 10 } }
|
|
12
|
+
* Turbopuffer filters: ["And", [["field", "Gt", 10]]]
|
|
13
|
+
*/
|
|
14
|
+
var TurbopufferFilterTranslator = class extends _mastra_core_vector_filter.BaseFilterTranslator {
|
|
15
|
+
getSupportedOperators() {
|
|
16
|
+
return {
|
|
17
|
+
..._mastra_core_vector_filter.BaseFilterTranslator.DEFAULT_OPERATORS,
|
|
18
|
+
logical: ["$and", "$or"],
|
|
19
|
+
array: [
|
|
20
|
+
"$in",
|
|
21
|
+
"$nin",
|
|
22
|
+
"$all"
|
|
23
|
+
],
|
|
24
|
+
element: ["$exists"],
|
|
25
|
+
regex: [],
|
|
26
|
+
custom: []
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Map Mastra operators to Turbopuffer operators
|
|
31
|
+
*/
|
|
32
|
+
operatorMap = {
|
|
33
|
+
$eq: "Eq",
|
|
34
|
+
$ne: "NotEq",
|
|
35
|
+
$gt: "Gt",
|
|
36
|
+
$gte: "Gte",
|
|
37
|
+
$lt: "Lt",
|
|
38
|
+
$lte: "Lte",
|
|
39
|
+
$in: "In",
|
|
40
|
+
$nin: "NotIn"
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Convert the Mastra filter to Turbopuffer format
|
|
44
|
+
*/
|
|
45
|
+
translate(filter) {
|
|
46
|
+
if (this.isEmpty(filter)) return;
|
|
47
|
+
this.validateFilter(filter);
|
|
48
|
+
const result = this.translateNode(filter);
|
|
49
|
+
if (!Array.isArray(result) || result.length !== 2 || result[0] !== "And" && result[0] !== "Or") return ["And", [result]];
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Recursively translate a filter node
|
|
54
|
+
*/
|
|
55
|
+
translateNode(node) {
|
|
56
|
+
if (node === null || node === void 0 || Object.keys(node).length === 0) return ["And", []];
|
|
57
|
+
if (this.isPrimitive(node)) throw new Error("Direct primitive values not valid in this context for Turbopuffer");
|
|
58
|
+
if (Array.isArray(node)) throw new Error("Direct array values not valid in this context for Turbopuffer");
|
|
59
|
+
const entries = Object.entries(node);
|
|
60
|
+
if (entries.length === 0) return ["And", []];
|
|
61
|
+
const [key, value] = entries[0];
|
|
62
|
+
if (key && this.isLogicalOperator(key)) return this.translateLogical(key, value);
|
|
63
|
+
if (entries.length > 1) return ["And", entries.map(([field, fieldValue]) => this.translateFieldCondition(field, fieldValue))];
|
|
64
|
+
return this.translateFieldCondition(key, value);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Translate a field condition
|
|
68
|
+
*/
|
|
69
|
+
translateFieldCondition(field, value) {
|
|
70
|
+
if (value instanceof Date) return [
|
|
71
|
+
field,
|
|
72
|
+
"Eq",
|
|
73
|
+
this.normalizeValue(value)
|
|
74
|
+
];
|
|
75
|
+
if (this.isPrimitive(value)) return [
|
|
76
|
+
field,
|
|
77
|
+
"Eq",
|
|
78
|
+
this.normalizeValue(value)
|
|
79
|
+
];
|
|
80
|
+
if (Array.isArray(value)) return [
|
|
81
|
+
field,
|
|
82
|
+
"In",
|
|
83
|
+
this.normalizeArrayValues(value)
|
|
84
|
+
];
|
|
85
|
+
if (typeof value === "object" && value !== null) {
|
|
86
|
+
const operators = Object.keys(value);
|
|
87
|
+
if (operators.length > 1) if (operators.every((op) => this.isOperator(op))) return ["And", operators.map((op) => this.translateOperator(field, op, value[op]))];
|
|
88
|
+
else return ["And", operators.map((op) => {
|
|
89
|
+
const nestedField = `${field}.${op}`;
|
|
90
|
+
return this.translateFieldCondition(nestedField, value[op]);
|
|
91
|
+
})];
|
|
92
|
+
const op = operators[0];
|
|
93
|
+
if (op && this.isOperator(op)) return this.translateOperator(field, op, value[op]);
|
|
94
|
+
if (op && !this.isOperator(op)) {
|
|
95
|
+
const nestedField = `${field}.${op}`;
|
|
96
|
+
return this.translateFieldCondition(nestedField, value[op]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
throw new Error(`Unsupported filter format for field: ${field}`);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Translate a logical operator
|
|
103
|
+
*/
|
|
104
|
+
translateLogical(operator, conditions) {
|
|
105
|
+
const logicalOp = operator === "$and" ? "And" : "Or";
|
|
106
|
+
if (!Array.isArray(conditions)) throw new Error(`Logical operator ${operator} requires an array of conditions`);
|
|
107
|
+
return [logicalOp, conditions.map((condition) => {
|
|
108
|
+
if (typeof condition !== "object" || condition === null) throw new Error(`Invalid condition for logical operator ${operator}`);
|
|
109
|
+
return this.translateNode(condition);
|
|
110
|
+
})];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Translate a specific operator
|
|
114
|
+
*/
|
|
115
|
+
translateOperator(field, operator, value) {
|
|
116
|
+
if (operator && this.operatorMap[operator]) return [
|
|
117
|
+
field,
|
|
118
|
+
this.operatorMap[operator],
|
|
119
|
+
this.normalizeValue(value)
|
|
120
|
+
];
|
|
121
|
+
switch (operator) {
|
|
122
|
+
case "$exists": return value ? [
|
|
123
|
+
field,
|
|
124
|
+
"NotEq",
|
|
125
|
+
null
|
|
126
|
+
] : [
|
|
127
|
+
field,
|
|
128
|
+
"Eq",
|
|
129
|
+
null
|
|
130
|
+
];
|
|
131
|
+
case "$all":
|
|
132
|
+
if (!Array.isArray(value) || value.length === 0) throw new Error("$all operator requires a non-empty array");
|
|
133
|
+
return ["And", value.map((item) => [
|
|
134
|
+
field,
|
|
135
|
+
"In",
|
|
136
|
+
[this.normalizeValue(item)]
|
|
137
|
+
])];
|
|
138
|
+
default: throw new Error(`Unsupported operator: ${operator || "undefined"}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Normalize a value for comparison operations
|
|
143
|
+
*/
|
|
144
|
+
normalizeValue(value) {
|
|
145
|
+
if (value instanceof Date) return value.toISOString();
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Normalize array values
|
|
150
|
+
*/
|
|
151
|
+
normalizeArrayValues(values) {
|
|
152
|
+
return values.map((value) => this.normalizeValue(value));
|
|
153
|
+
}
|
|
167
154
|
};
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
var TurbopufferVector = class extends
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
id: storage.createVectorErrorId("TURBOPUFFER", "DELETE_VECTOR", "FAILED"),
|
|
589
|
-
domain: error.ErrorDomain.STORAGE,
|
|
590
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
591
|
-
details: { indexName }
|
|
592
|
-
},
|
|
593
|
-
error$1
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
async deleteVectors({ indexName, filter, ids }) {
|
|
598
|
-
if (ids && filter) {
|
|
599
|
-
throw new error.MastraError({
|
|
600
|
-
id: storage.createVectorErrorId("TURBOPUFFER", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
|
|
601
|
-
domain: error.ErrorDomain.STORAGE,
|
|
602
|
-
category: error.ErrorCategory.USER,
|
|
603
|
-
text: "ids and filter are mutually exclusive",
|
|
604
|
-
details: { indexName }
|
|
605
|
-
});
|
|
606
|
-
}
|
|
607
|
-
if (!ids && !filter) {
|
|
608
|
-
throw new error.MastraError({
|
|
609
|
-
id: storage.createVectorErrorId("TURBOPUFFER", "DELETE_VECTORS", "NO_TARGET"),
|
|
610
|
-
domain: error.ErrorDomain.STORAGE,
|
|
611
|
-
category: error.ErrorCategory.USER,
|
|
612
|
-
text: "Either filter or ids must be provided",
|
|
613
|
-
details: { indexName }
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
if (ids && ids.length === 0) {
|
|
617
|
-
throw new error.MastraError({
|
|
618
|
-
id: storage.createVectorErrorId("TURBOPUFFER", "DELETE_VECTORS", "EMPTY_IDS"),
|
|
619
|
-
domain: error.ErrorDomain.STORAGE,
|
|
620
|
-
category: error.ErrorCategory.USER,
|
|
621
|
-
text: "ids array cannot be empty",
|
|
622
|
-
details: { indexName }
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
if (filter && Object.keys(filter).length === 0) {
|
|
626
|
-
throw new error.MastraError({
|
|
627
|
-
id: storage.createVectorErrorId("TURBOPUFFER", "DELETE_VECTORS", "EMPTY_FILTER"),
|
|
628
|
-
domain: error.ErrorDomain.STORAGE,
|
|
629
|
-
category: error.ErrorCategory.USER,
|
|
630
|
-
text: "Filter cannot be an empty object",
|
|
631
|
-
details: { indexName }
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
try {
|
|
635
|
-
const namespace = this.client.namespace(indexName);
|
|
636
|
-
let idsToDelete = [];
|
|
637
|
-
if (ids) {
|
|
638
|
-
idsToDelete = ids;
|
|
639
|
-
} else if (filter) {
|
|
640
|
-
const createIndex = this.createIndexCache.get(indexName);
|
|
641
|
-
if (!createIndex) {
|
|
642
|
-
throw new Error(`createIndex() not called for this index`);
|
|
643
|
-
}
|
|
644
|
-
const dummyVector = new Array(createIndex.dimension).fill(1 / Math.sqrt(createIndex.dimension));
|
|
645
|
-
const translatedFilter = this.filterTranslator.translate(filter);
|
|
646
|
-
const results = await namespace.query({
|
|
647
|
-
rank_by: ["vector", "ANN", dummyVector],
|
|
648
|
-
top_k: 1e4,
|
|
649
|
-
// Get all matching vectors
|
|
650
|
-
filters: translatedFilter,
|
|
651
|
-
include_attributes: []
|
|
652
|
-
});
|
|
653
|
-
idsToDelete = (results.rows ?? []).map((r) => String(r.id));
|
|
654
|
-
}
|
|
655
|
-
if (idsToDelete.length === 0) {
|
|
656
|
-
this.logger.info(`No vectors matched the criteria for deletion in ${indexName}`);
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
const batchSize = 1e3;
|
|
660
|
-
for (let i = 0; i < idsToDelete.length; i += batchSize) {
|
|
661
|
-
const batch = idsToDelete.slice(i, i + batchSize);
|
|
662
|
-
await namespace.write({ deletes: batch });
|
|
663
|
-
}
|
|
664
|
-
} catch (error$1) {
|
|
665
|
-
if (error$1 instanceof error.MastraError) throw error$1;
|
|
666
|
-
throw new error.MastraError(
|
|
667
|
-
{
|
|
668
|
-
id: storage.createVectorErrorId("TURBOPUFFER", "DELETE_VECTORS", "FAILED"),
|
|
669
|
-
domain: error.ErrorDomain.STORAGE,
|
|
670
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
671
|
-
details: {
|
|
672
|
-
indexName,
|
|
673
|
-
...filter && { filter: JSON.stringify(filter) },
|
|
674
|
-
...ids && { idsCount: ids.length }
|
|
675
|
-
}
|
|
676
|
-
},
|
|
677
|
-
error$1
|
|
678
|
-
);
|
|
679
|
-
}
|
|
680
|
-
}
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/vector/index.ts
|
|
157
|
+
var TurbopufferVector = class extends _mastra_core_vector.MastraVector {
|
|
158
|
+
client;
|
|
159
|
+
filterTranslator;
|
|
160
|
+
createIndexCache = /* @__PURE__ */ new Map();
|
|
161
|
+
opts;
|
|
162
|
+
constructor(opts) {
|
|
163
|
+
super({ id: opts.id });
|
|
164
|
+
this.filterTranslator = new TurbopufferFilterTranslator();
|
|
165
|
+
this.opts = opts;
|
|
166
|
+
this.client = new _turbopuffer_turbopuffer.Turbopuffer(opts);
|
|
167
|
+
}
|
|
168
|
+
async createIndex({ indexName, dimension, metric }) {
|
|
169
|
+
metric = metric ?? "cosine";
|
|
170
|
+
let distanceMetric = "cosine_distance";
|
|
171
|
+
try {
|
|
172
|
+
if (this.createIndexCache.has(indexName)) {
|
|
173
|
+
const expected = this.createIndexCache.get(indexName);
|
|
174
|
+
if (dimension !== expected.dimension || metric !== expected.metric) throw new Error(`createIndex() called more than once with inconsistent inputs. Index ${indexName} expected dimensions=${expected.dimension} and metric=${expected.metric} but got dimensions=${dimension} and metric=${metric}`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (dimension <= 0) throw new Error("Dimension must be a positive integer");
|
|
178
|
+
switch (metric) {
|
|
179
|
+
case "cosine":
|
|
180
|
+
distanceMetric = "cosine_distance";
|
|
181
|
+
break;
|
|
182
|
+
case "euclidean":
|
|
183
|
+
distanceMetric = "euclidean_squared";
|
|
184
|
+
break;
|
|
185
|
+
case "dotproduct": throw new Error("dotproduct is not supported in Turbopuffer");
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
throw new _mastra_core_error.MastraError({
|
|
189
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "CREATE_INDEX", "INVALID_ARGS"),
|
|
190
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
191
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
192
|
+
details: {
|
|
193
|
+
indexName,
|
|
194
|
+
dimension,
|
|
195
|
+
metric
|
|
196
|
+
}
|
|
197
|
+
}, error);
|
|
198
|
+
}
|
|
199
|
+
this.createIndexCache.set(indexName, {
|
|
200
|
+
indexName,
|
|
201
|
+
dimension,
|
|
202
|
+
metric,
|
|
203
|
+
tpufDistanceMetric: distanceMetric
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
async upsert({ indexName, vectors, metadata, ids }) {
|
|
207
|
+
let index;
|
|
208
|
+
let createIndex;
|
|
209
|
+
try {
|
|
210
|
+
if (vectors.length === 0) throw new Error("upsert() called with empty vectors");
|
|
211
|
+
index = this.client.namespace(indexName);
|
|
212
|
+
createIndex = this.createIndexCache.get(indexName);
|
|
213
|
+
if (!createIndex) throw new Error(`createIndex() not called for this index`);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
throw new _mastra_core_error.MastraError({
|
|
216
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "UPSERT", "INVALID_ARGS"),
|
|
217
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
218
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
219
|
+
details: { indexName }
|
|
220
|
+
}, error);
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
const distanceMetric = createIndex.tpufDistanceMetric;
|
|
224
|
+
const vectorIds = ids || vectors.map(() => crypto.randomUUID());
|
|
225
|
+
const records = vectors.map((vector, i) => ({
|
|
226
|
+
id: vectorIds[i],
|
|
227
|
+
vector,
|
|
228
|
+
...metadata?.[i] || {}
|
|
229
|
+
}));
|
|
230
|
+
const batchSize = 100;
|
|
231
|
+
for (let i = 0; i < records.length; i += batchSize) {
|
|
232
|
+
const writeOptions = {
|
|
233
|
+
upsert_rows: records.slice(i, i + batchSize),
|
|
234
|
+
distance_metric: distanceMetric
|
|
235
|
+
};
|
|
236
|
+
const schemaConfig = this.opts.schemaConfigForIndex?.(indexName);
|
|
237
|
+
if (schemaConfig) {
|
|
238
|
+
writeOptions.schema = schemaConfig.schema;
|
|
239
|
+
if (vectors[0]?.length !== schemaConfig.dimensions) throw new Error(`Turbopuffer index ${indexName} was configured with dimensions=${schemaConfig.dimensions} but attempting to upsert vectors[0].length=${vectors[0]?.length}`);
|
|
240
|
+
}
|
|
241
|
+
await index.write(writeOptions);
|
|
242
|
+
}
|
|
243
|
+
return vectorIds;
|
|
244
|
+
} catch (error) {
|
|
245
|
+
throw new _mastra_core_error.MastraError({
|
|
246
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "UPSERT", "FAILED"),
|
|
247
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
248
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
249
|
+
details: { indexName }
|
|
250
|
+
}, error);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async query({ indexName, queryVector, topK, filter, includeVector, consistency }) {
|
|
254
|
+
if (!queryVector) throw new _mastra_core_error.MastraError({
|
|
255
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "QUERY", "MISSING_VECTOR"),
|
|
256
|
+
text: "queryVector is required for Turbopuffer queries. Metadata-only queries are not supported by this vector store.",
|
|
257
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
258
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
259
|
+
details: { indexName }
|
|
260
|
+
});
|
|
261
|
+
let createIndex;
|
|
262
|
+
try {
|
|
263
|
+
const schemaConfig = this.opts.schemaConfigForIndex?.(indexName);
|
|
264
|
+
if (schemaConfig) {
|
|
265
|
+
if (queryVector.length !== schemaConfig.dimensions) throw new Error(`Turbopuffer index ${indexName} was configured with dimensions=${schemaConfig.dimensions} but attempting to query with queryVector.length=${queryVector.length}`);
|
|
266
|
+
}
|
|
267
|
+
createIndex = this.createIndexCache.get(indexName);
|
|
268
|
+
if (!createIndex) throw new Error(`createIndex() not called for this index`);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
throw new _mastra_core_error.MastraError({
|
|
271
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "QUERY", "INVALID_ARGS"),
|
|
272
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
273
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
274
|
+
details: { indexName }
|
|
275
|
+
}, error);
|
|
276
|
+
}
|
|
277
|
+
const distanceMetric = createIndex.tpufDistanceMetric;
|
|
278
|
+
try {
|
|
279
|
+
const index = this.client.namespace(indexName);
|
|
280
|
+
const translatedFilter = this.filterTranslator.translate(filter);
|
|
281
|
+
return ((await index.query({
|
|
282
|
+
distance_metric: distanceMetric,
|
|
283
|
+
rank_by: [
|
|
284
|
+
"vector",
|
|
285
|
+
"ANN",
|
|
286
|
+
queryVector
|
|
287
|
+
],
|
|
288
|
+
top_k: topK,
|
|
289
|
+
filters: translatedFilter,
|
|
290
|
+
vector_encoding: includeVector ? "float" : void 0,
|
|
291
|
+
include_attributes: true,
|
|
292
|
+
consistency: { level: consistency ?? this.opts.consistency ?? "strong" }
|
|
293
|
+
})).rows ?? []).map((item) => {
|
|
294
|
+
const { id, vector, $dist, ...metadata } = item;
|
|
295
|
+
return {
|
|
296
|
+
id: String(id),
|
|
297
|
+
score: typeof $dist === "number" ? $dist : 0,
|
|
298
|
+
metadata,
|
|
299
|
+
...includeVector && Array.isArray(vector) ? { vector } : {}
|
|
300
|
+
};
|
|
301
|
+
});
|
|
302
|
+
} catch (error) {
|
|
303
|
+
throw new _mastra_core_error.MastraError({
|
|
304
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "QUERY", "FAILED"),
|
|
305
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
306
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
307
|
+
details: { indexName }
|
|
308
|
+
}, error);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async listIndexes() {
|
|
312
|
+
try {
|
|
313
|
+
return (await this.client.namespaces({})).namespaces.map((namespace) => namespace.id);
|
|
314
|
+
} catch (error) {
|
|
315
|
+
throw new _mastra_core_error.MastraError({
|
|
316
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "LIST_INDEXES", "FAILED"),
|
|
317
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
318
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY
|
|
319
|
+
}, error);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Retrieves statistics about a vector index.
|
|
324
|
+
*
|
|
325
|
+
* @param {string} indexName - The name of the index to describe
|
|
326
|
+
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
327
|
+
*/
|
|
328
|
+
async describeIndex({ indexName }) {
|
|
329
|
+
try {
|
|
330
|
+
const metadata = await this.client.namespace(indexName).metadata();
|
|
331
|
+
const createIndex = this.createIndexCache.get(indexName);
|
|
332
|
+
if (!createIndex) throw new Error(`createIndex() not called for this index`);
|
|
333
|
+
return {
|
|
334
|
+
dimension: createIndex.dimension,
|
|
335
|
+
count: metadata.approx_row_count,
|
|
336
|
+
metric: createIndex.metric
|
|
337
|
+
};
|
|
338
|
+
} catch (error) {
|
|
339
|
+
throw new _mastra_core_error.MastraError({
|
|
340
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "DESCRIBE_INDEX", "FAILED"),
|
|
341
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
342
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
343
|
+
details: { indexName }
|
|
344
|
+
}, error);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
async deleteIndex({ indexName }) {
|
|
348
|
+
try {
|
|
349
|
+
await this.client.namespace(indexName).deleteAll();
|
|
350
|
+
this.createIndexCache.delete(indexName);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
throw new _mastra_core_error.MastraError({
|
|
353
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "DELETE_INDEX", "FAILED"),
|
|
354
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
355
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
356
|
+
details: { indexName }
|
|
357
|
+
}, error);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Updates a vector by its ID or filter with the provided vector and/or metadata.
|
|
362
|
+
* @param indexName - The name of the index containing the vector.
|
|
363
|
+
* @param id - The ID of the vector to update.
|
|
364
|
+
* @param filter - The filter to match vectors to update.
|
|
365
|
+
* @param update - An object containing the vector and/or metadata to update.
|
|
366
|
+
* @param update.vector - An optional array of numbers representing the new vector.
|
|
367
|
+
* @param update.metadata - An optional record containing the new metadata.
|
|
368
|
+
* @returns A promise that resolves when the update is complete.
|
|
369
|
+
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
370
|
+
*/
|
|
371
|
+
async updateVector({ indexName, id, filter, update }) {
|
|
372
|
+
if (id && filter) throw new _mastra_core_error.MastraError({
|
|
373
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "UPDATE_VECTOR", "MUTUALLY_EXCLUSIVE"),
|
|
374
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
375
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
376
|
+
text: "id and filter are mutually exclusive",
|
|
377
|
+
details: { indexName }
|
|
378
|
+
});
|
|
379
|
+
if (!id && !filter) throw new _mastra_core_error.MastraError({
|
|
380
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "UPDATE_VECTOR", "NO_TARGET"),
|
|
381
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
382
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
383
|
+
text: "Either id or filter must be provided",
|
|
384
|
+
details: { indexName }
|
|
385
|
+
});
|
|
386
|
+
if (!update.vector && !update.metadata) throw new _mastra_core_error.MastraError({
|
|
387
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "UPDATE_VECTOR", "NO_PAYLOAD"),
|
|
388
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
389
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
390
|
+
text: "No update data provided",
|
|
391
|
+
details: {
|
|
392
|
+
indexName,
|
|
393
|
+
...id && { id }
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
let namespace;
|
|
397
|
+
let createIndex;
|
|
398
|
+
let distanceMetric;
|
|
399
|
+
try {
|
|
400
|
+
namespace = this.client.namespace(indexName);
|
|
401
|
+
createIndex = this.createIndexCache.get(indexName);
|
|
402
|
+
if (!createIndex) throw new Error(`createIndex() not called for this index`);
|
|
403
|
+
distanceMetric = createIndex.tpufDistanceMetric;
|
|
404
|
+
} catch (error) {
|
|
405
|
+
throw new _mastra_core_error.MastraError({
|
|
406
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "UPDATE_VECTOR", "INVALID_ARGS"),
|
|
407
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
408
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
409
|
+
details: { indexName }
|
|
410
|
+
}, error);
|
|
411
|
+
}
|
|
412
|
+
try {
|
|
413
|
+
let idsToUpdate = [];
|
|
414
|
+
if (id) idsToUpdate = [id];
|
|
415
|
+
else if (filter) {
|
|
416
|
+
if (Object.keys(filter).length === 0) throw new _mastra_core_error.MastraError({
|
|
417
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "UPDATE_VECTOR", "EMPTY_FILTER"),
|
|
418
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
419
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
420
|
+
text: "Filter cannot be an empty object",
|
|
421
|
+
details: { indexName }
|
|
422
|
+
});
|
|
423
|
+
const dummyVector = new Array(createIndex.dimension).fill(1 / Math.sqrt(createIndex.dimension));
|
|
424
|
+
const translatedFilter = this.filterTranslator.translate(filter);
|
|
425
|
+
const rows = (await namespace.query({
|
|
426
|
+
rank_by: [
|
|
427
|
+
"vector",
|
|
428
|
+
"ANN",
|
|
429
|
+
dummyVector
|
|
430
|
+
],
|
|
431
|
+
top_k: 1e4,
|
|
432
|
+
filters: translatedFilter,
|
|
433
|
+
vector_encoding: update.vector ? void 0 : "float",
|
|
434
|
+
include_attributes: true
|
|
435
|
+
})).rows ?? [];
|
|
436
|
+
idsToUpdate = rows.map((r) => String(r.id));
|
|
437
|
+
if (!update.vector || !update.metadata) {
|
|
438
|
+
for (const result of rows) {
|
|
439
|
+
const { id: resultId, vector, $dist, ...metadata } = result;
|
|
440
|
+
const record = { id: resultId };
|
|
441
|
+
if (update.vector) record.vector = update.vector;
|
|
442
|
+
else if (Array.isArray(vector)) record.vector = vector;
|
|
443
|
+
if (update.metadata) Object.assign(record, update.metadata);
|
|
444
|
+
else Object.assign(record, metadata);
|
|
445
|
+
await namespace.write({
|
|
446
|
+
upsert_rows: [record],
|
|
447
|
+
distance_metric: distanceMetric
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (idsToUpdate.length === 0) {
|
|
454
|
+
this.logger.info(`No vectors matched the criteria for update in ${indexName}`);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
const records = idsToUpdate.map((vecId) => ({
|
|
458
|
+
id: vecId,
|
|
459
|
+
...update.vector ? { vector: update.vector } : {},
|
|
460
|
+
...update.metadata || {}
|
|
461
|
+
}));
|
|
462
|
+
const batchSize = 1e3;
|
|
463
|
+
for (let i = 0; i < records.length; i += batchSize) {
|
|
464
|
+
const batch = records.slice(i, i + batchSize);
|
|
465
|
+
await namespace.write({
|
|
466
|
+
upsert_rows: batch,
|
|
467
|
+
distance_metric: distanceMetric
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
} catch (error) {
|
|
471
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
472
|
+
throw new _mastra_core_error.MastraError({
|
|
473
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "UPDATE_VECTOR", "FAILED"),
|
|
474
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
475
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
476
|
+
details: {
|
|
477
|
+
indexName,
|
|
478
|
+
...id && { id },
|
|
479
|
+
...filter && { filter: JSON.stringify(filter) }
|
|
480
|
+
}
|
|
481
|
+
}, error);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Deletes a vector by its ID.
|
|
486
|
+
* @param indexName - The name of the index containing the vector.
|
|
487
|
+
* @param id - The ID of the vector to delete.
|
|
488
|
+
* @returns A promise that resolves when the deletion is complete.
|
|
489
|
+
* @throws Will throw an error if the deletion operation fails.
|
|
490
|
+
*/
|
|
491
|
+
async deleteVector({ indexName, id }) {
|
|
492
|
+
try {
|
|
493
|
+
await this.client.namespace(indexName).write({ deletes: [id] });
|
|
494
|
+
} catch (error) {
|
|
495
|
+
throw new _mastra_core_error.MastraError({
|
|
496
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "DELETE_VECTOR", "FAILED"),
|
|
497
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
498
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
499
|
+
details: { indexName }
|
|
500
|
+
}, error);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
async deleteVectors({ indexName, filter, ids }) {
|
|
504
|
+
if (ids && filter) throw new _mastra_core_error.MastraError({
|
|
505
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
|
|
506
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
507
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
508
|
+
text: "ids and filter are mutually exclusive",
|
|
509
|
+
details: { indexName }
|
|
510
|
+
});
|
|
511
|
+
if (!ids && !filter) throw new _mastra_core_error.MastraError({
|
|
512
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "DELETE_VECTORS", "NO_TARGET"),
|
|
513
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
514
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
515
|
+
text: "Either filter or ids must be provided",
|
|
516
|
+
details: { indexName }
|
|
517
|
+
});
|
|
518
|
+
if (ids && ids.length === 0) throw new _mastra_core_error.MastraError({
|
|
519
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "DELETE_VECTORS", "EMPTY_IDS"),
|
|
520
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
521
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
522
|
+
text: "ids array cannot be empty",
|
|
523
|
+
details: { indexName }
|
|
524
|
+
});
|
|
525
|
+
if (filter && Object.keys(filter).length === 0) throw new _mastra_core_error.MastraError({
|
|
526
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "DELETE_VECTORS", "EMPTY_FILTER"),
|
|
527
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
528
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
529
|
+
text: "Filter cannot be an empty object",
|
|
530
|
+
details: { indexName }
|
|
531
|
+
});
|
|
532
|
+
try {
|
|
533
|
+
const namespace = this.client.namespace(indexName);
|
|
534
|
+
let idsToDelete = [];
|
|
535
|
+
if (ids) idsToDelete = ids;
|
|
536
|
+
else if (filter) {
|
|
537
|
+
const createIndex = this.createIndexCache.get(indexName);
|
|
538
|
+
if (!createIndex) throw new Error(`createIndex() not called for this index`);
|
|
539
|
+
const dummyVector = new Array(createIndex.dimension).fill(1 / Math.sqrt(createIndex.dimension));
|
|
540
|
+
const translatedFilter = this.filterTranslator.translate(filter);
|
|
541
|
+
idsToDelete = ((await namespace.query({
|
|
542
|
+
rank_by: [
|
|
543
|
+
"vector",
|
|
544
|
+
"ANN",
|
|
545
|
+
dummyVector
|
|
546
|
+
],
|
|
547
|
+
top_k: 1e4,
|
|
548
|
+
filters: translatedFilter,
|
|
549
|
+
include_attributes: []
|
|
550
|
+
})).rows ?? []).map((r) => String(r.id));
|
|
551
|
+
}
|
|
552
|
+
if (idsToDelete.length === 0) {
|
|
553
|
+
this.logger.info(`No vectors matched the criteria for deletion in ${indexName}`);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const batchSize = 1e3;
|
|
557
|
+
for (let i = 0; i < idsToDelete.length; i += batchSize) {
|
|
558
|
+
const batch = idsToDelete.slice(i, i + batchSize);
|
|
559
|
+
await namespace.write({ deletes: batch });
|
|
560
|
+
}
|
|
561
|
+
} catch (error) {
|
|
562
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
563
|
+
throw new _mastra_core_error.MastraError({
|
|
564
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("TURBOPUFFER", "DELETE_VECTORS", "FAILED"),
|
|
565
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
566
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
567
|
+
details: {
|
|
568
|
+
indexName,
|
|
569
|
+
...filter && { filter: JSON.stringify(filter) },
|
|
570
|
+
...ids && { idsCount: ids.length }
|
|
571
|
+
}
|
|
572
|
+
}, error);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
681
575
|
};
|
|
682
|
-
|
|
576
|
+
//#endregion
|
|
683
577
|
exports.TurbopufferVector = TurbopufferVector;
|
|
684
|
-
|
|
578
|
+
|
|
685
579
|
//# sourceMappingURL=index.cjs.map
|