@mastra/upstash 1.0.0-beta.1 → 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/README.md +12 -0
- package/dist/index.cjs +347 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +348 -133
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +4 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts +18 -9
- package/dist/vector/index.d.ts.map +1 -1
- package/dist/vector/types.d.ts +15 -3
- package/dist/vector/types.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -54,6 +54,9 @@ function getMessageKey(threadId, messageId) {
|
|
|
54
54
|
const key = getKey(storage.TABLE_MESSAGES, { threadId, id: messageId });
|
|
55
55
|
return key;
|
|
56
56
|
}
|
|
57
|
+
function getMessageIndexKey(messageId) {
|
|
58
|
+
return `msg-idx:${messageId}`;
|
|
59
|
+
}
|
|
57
60
|
var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
58
61
|
client;
|
|
59
62
|
operations;
|
|
@@ -320,6 +323,7 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
320
323
|
}
|
|
321
324
|
}
|
|
322
325
|
pipeline.set(key, message);
|
|
326
|
+
pipeline.set(getMessageIndexKey(message.id), message.threadId);
|
|
323
327
|
pipeline.zadd(getThreadMessagesKey(message.threadId), {
|
|
324
328
|
score,
|
|
325
329
|
member: message.id
|
|
@@ -350,43 +354,60 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
350
354
|
);
|
|
351
355
|
}
|
|
352
356
|
}
|
|
353
|
-
|
|
354
|
-
|
|
357
|
+
/**
|
|
358
|
+
* Lookup threadId for a message - tries index first (O(1)), falls back to scan (backwards compatible)
|
|
359
|
+
*/
|
|
360
|
+
async _getThreadIdForMessage(messageId) {
|
|
361
|
+
const indexedThreadId = await this.client.get(getMessageIndexKey(messageId));
|
|
362
|
+
if (indexedThreadId) {
|
|
363
|
+
return indexedThreadId;
|
|
364
|
+
}
|
|
365
|
+
const existingKeyPattern = getMessageKey("*", messageId);
|
|
366
|
+
const keys = await this.operations.scanKeys(existingKeyPattern);
|
|
367
|
+
if (keys.length === 0) return null;
|
|
368
|
+
const messageData = await this.client.get(keys[0]);
|
|
369
|
+
if (!messageData) return null;
|
|
370
|
+
if (messageData.threadId) {
|
|
371
|
+
await this.client.set(getMessageIndexKey(messageId), messageData.threadId);
|
|
372
|
+
}
|
|
373
|
+
return messageData.threadId || null;
|
|
374
|
+
}
|
|
375
|
+
async _getIncludedMessages(include) {
|
|
376
|
+
if (!include?.length) return [];
|
|
355
377
|
const messageIds = /* @__PURE__ */ new Set();
|
|
356
378
|
const messageIdToThreadIds = {};
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
379
|
+
for (const item of include) {
|
|
380
|
+
const itemThreadId = await this._getThreadIdForMessage(item.id);
|
|
381
|
+
if (!itemThreadId) continue;
|
|
382
|
+
messageIds.add(item.id);
|
|
383
|
+
messageIdToThreadIds[item.id] = itemThreadId;
|
|
384
|
+
const itemThreadMessagesKey = getThreadMessagesKey(itemThreadId);
|
|
385
|
+
const rank = await this.client.zrank(itemThreadMessagesKey, item.id);
|
|
386
|
+
if (rank === null) continue;
|
|
387
|
+
if (item.withPreviousMessages) {
|
|
388
|
+
const start = Math.max(0, rank - item.withPreviousMessages);
|
|
389
|
+
const prevIds = rank === 0 ? [] : await this.client.zrange(itemThreadMessagesKey, start, rank - 1);
|
|
390
|
+
prevIds.forEach((id) => {
|
|
391
|
+
messageIds.add(id);
|
|
392
|
+
messageIdToThreadIds[id] = itemThreadId;
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
if (item.withNextMessages) {
|
|
396
|
+
const nextIds = await this.client.zrange(itemThreadMessagesKey, rank + 1, rank + item.withNextMessages);
|
|
397
|
+
nextIds.forEach((id) => {
|
|
398
|
+
messageIds.add(id);
|
|
399
|
+
messageIdToThreadIds[id] = itemThreadId;
|
|
400
|
+
});
|
|
380
401
|
}
|
|
381
|
-
const pipeline = this.client.pipeline();
|
|
382
|
-
Array.from(messageIds).forEach((id) => {
|
|
383
|
-
const tId = messageIdToThreadIds[id] || threadId;
|
|
384
|
-
pipeline.get(getMessageKey(tId, id));
|
|
385
|
-
});
|
|
386
|
-
const results = await pipeline.exec();
|
|
387
|
-
return results.filter((result) => result !== null);
|
|
388
402
|
}
|
|
389
|
-
return [];
|
|
403
|
+
if (messageIds.size === 0) return [];
|
|
404
|
+
const pipeline = this.client.pipeline();
|
|
405
|
+
Array.from(messageIds).forEach((id) => {
|
|
406
|
+
const tId = messageIdToThreadIds[id];
|
|
407
|
+
pipeline.get(getMessageKey(tId, id));
|
|
408
|
+
});
|
|
409
|
+
const results = await pipeline.exec();
|
|
410
|
+
return results.filter((result) => result !== null);
|
|
390
411
|
}
|
|
391
412
|
parseStoredMessage(storedMessage) {
|
|
392
413
|
const defaultMessageContent = { format: 2, parts: [{ type: "text", text: "" }] };
|
|
@@ -400,17 +421,49 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
400
421
|
async listMessagesById({ messageIds }) {
|
|
401
422
|
if (messageIds.length === 0) return { messages: [] };
|
|
402
423
|
try {
|
|
403
|
-
const
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
424
|
+
const rawMessages = [];
|
|
425
|
+
const indexPipeline = this.client.pipeline();
|
|
426
|
+
messageIds.forEach((id) => indexPipeline.get(getMessageIndexKey(id)));
|
|
427
|
+
const indexResults = await indexPipeline.exec();
|
|
428
|
+
const indexedIds = [];
|
|
429
|
+
const unindexedIds = [];
|
|
430
|
+
messageIds.forEach((id, i) => {
|
|
431
|
+
const threadId = indexResults[i];
|
|
432
|
+
if (threadId) {
|
|
433
|
+
indexedIds.push({ messageId: id, threadId });
|
|
434
|
+
} else {
|
|
435
|
+
unindexedIds.push(id);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
if (indexedIds.length > 0) {
|
|
439
|
+
const messagePipeline = this.client.pipeline();
|
|
440
|
+
indexedIds.forEach(({ messageId, threadId }) => messagePipeline.get(getMessageKey(threadId, messageId)));
|
|
441
|
+
const messageResults = await messagePipeline.exec();
|
|
442
|
+
rawMessages.push(...messageResults.filter((msg) => msg !== null));
|
|
443
|
+
}
|
|
444
|
+
if (unindexedIds.length > 0) {
|
|
445
|
+
const threadKeys = await this.client.keys("thread:*");
|
|
446
|
+
const result = await Promise.all(
|
|
447
|
+
threadKeys.map((threadKey) => {
|
|
448
|
+
const threadId = threadKey.split(":")[1];
|
|
449
|
+
if (!threadId) throw new Error(`Failed to parse thread ID from thread key "${threadKey}"`);
|
|
450
|
+
return this.client.mget(
|
|
451
|
+
unindexedIds.map((id) => getMessageKey(threadId, id))
|
|
452
|
+
);
|
|
453
|
+
})
|
|
454
|
+
);
|
|
455
|
+
const foundMessages = result.flat(1).filter((msg) => !!msg);
|
|
456
|
+
rawMessages.push(...foundMessages);
|
|
457
|
+
if (foundMessages.length > 0) {
|
|
458
|
+
const backfillPipeline = this.client.pipeline();
|
|
459
|
+
foundMessages.forEach((msg) => {
|
|
460
|
+
if (msg.threadId) {
|
|
461
|
+
backfillPipeline.set(getMessageIndexKey(msg.id), msg.threadId);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
await backfillPipeline.exec();
|
|
465
|
+
}
|
|
466
|
+
}
|
|
414
467
|
const list = new agent.MessageList().add(rawMessages.map(this.parseStoredMessage), "memory");
|
|
415
468
|
return { messages: list.get.all.db() };
|
|
416
469
|
} catch (error$1) {
|
|
@@ -429,18 +482,18 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
429
482
|
}
|
|
430
483
|
async listMessages(args) {
|
|
431
484
|
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
432
|
-
|
|
485
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
486
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
433
487
|
throw new error.MastraError(
|
|
434
488
|
{
|
|
435
489
|
id: "STORAGE_UPSTASH_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
436
490
|
domain: error.ErrorDomain.STORAGE,
|
|
437
491
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
438
|
-
details: { threadId }
|
|
492
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
439
493
|
},
|
|
440
|
-
new Error("threadId must be a non-empty string")
|
|
494
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
441
495
|
);
|
|
442
496
|
}
|
|
443
|
-
const threadMessagesKey = getThreadMessagesKey(threadId);
|
|
444
497
|
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
445
498
|
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
446
499
|
try {
|
|
@@ -457,11 +510,18 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
457
510
|
}
|
|
458
511
|
let includedMessages = [];
|
|
459
512
|
if (include && include.length > 0) {
|
|
460
|
-
const included = await this._getIncludedMessages(
|
|
513
|
+
const included = await this._getIncludedMessages(include);
|
|
461
514
|
includedMessages = included.map(this.parseStoredMessage);
|
|
462
515
|
}
|
|
463
|
-
const
|
|
464
|
-
|
|
516
|
+
const allMessageIdsWithThreads = [];
|
|
517
|
+
for (const tid of threadIds) {
|
|
518
|
+
const threadMessagesKey = getThreadMessagesKey(tid);
|
|
519
|
+
const messageIds2 = await this.client.zrange(threadMessagesKey, 0, -1);
|
|
520
|
+
for (const mid of messageIds2) {
|
|
521
|
+
allMessageIdsWithThreads.push({ threadId: tid, messageId: mid });
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (allMessageIdsWithThreads.length === 0) {
|
|
465
525
|
return {
|
|
466
526
|
messages: [],
|
|
467
527
|
total: 0,
|
|
@@ -471,7 +531,7 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
471
531
|
};
|
|
472
532
|
}
|
|
473
533
|
const pipeline = this.client.pipeline();
|
|
474
|
-
|
|
534
|
+
allMessageIdsWithThreads.forEach(({ threadId: tid, messageId }) => pipeline.get(getMessageKey(tid, messageId)));
|
|
475
535
|
const results = await pipeline.exec();
|
|
476
536
|
let messagesData = results.filter((msg) => msg !== null).map(this.parseStoredMessage);
|
|
477
537
|
if (resourceId) {
|
|
@@ -500,13 +560,11 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
500
560
|
}
|
|
501
561
|
return 0;
|
|
502
562
|
};
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
});
|
|
509
|
-
}
|
|
563
|
+
messagesData.sort((a, b) => {
|
|
564
|
+
const aValue = getFieldValue(a);
|
|
565
|
+
const bValue = getFieldValue(b);
|
|
566
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
567
|
+
});
|
|
510
568
|
const total = messagesData.length;
|
|
511
569
|
const start = offset;
|
|
512
570
|
const end = perPageInput === false ? total : start + perPage;
|
|
@@ -527,23 +585,11 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
527
585
|
}
|
|
528
586
|
const list = new agent.MessageList().add(allMessages, "memory");
|
|
529
587
|
let finalMessages = list.get.all.db();
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
});
|
|
536
|
-
} else {
|
|
537
|
-
const messageIdToPosition = /* @__PURE__ */ new Map();
|
|
538
|
-
allMessageIds.forEach((id, index) => {
|
|
539
|
-
messageIdToPosition.set(id, index);
|
|
540
|
-
});
|
|
541
|
-
finalMessages = finalMessages.sort((a, b) => {
|
|
542
|
-
const aPos = messageIdToPosition.get(a.id) ?? Number.MAX_SAFE_INTEGER;
|
|
543
|
-
const bPos = messageIdToPosition.get(b.id) ?? Number.MAX_SAFE_INTEGER;
|
|
544
|
-
return aPos - bPos;
|
|
545
|
-
});
|
|
546
|
-
}
|
|
588
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
589
|
+
const aValue = getFieldValue(a);
|
|
590
|
+
const bValue = getFieldValue(b);
|
|
591
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
592
|
+
});
|
|
547
593
|
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
548
594
|
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
549
595
|
const hasMore = perPageInput !== false && !allThreadMessagesReturned && end < total;
|
|
@@ -561,7 +607,7 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
561
607
|
domain: error.ErrorDomain.STORAGE,
|
|
562
608
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
563
609
|
details: {
|
|
564
|
-
threadId,
|
|
610
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
565
611
|
resourceId: resourceId ?? ""
|
|
566
612
|
}
|
|
567
613
|
},
|
|
@@ -766,13 +812,33 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
766
812
|
try {
|
|
767
813
|
const threadIds = /* @__PURE__ */ new Set();
|
|
768
814
|
const messageKeys = [];
|
|
769
|
-
|
|
815
|
+
const foundMessageIds = [];
|
|
816
|
+
const indexPipeline = this.client.pipeline();
|
|
817
|
+
messageIds.forEach((id) => indexPipeline.get(getMessageIndexKey(id)));
|
|
818
|
+
const indexResults = await indexPipeline.exec();
|
|
819
|
+
const indexedMessages = [];
|
|
820
|
+
const unindexedMessageIds = [];
|
|
821
|
+
messageIds.forEach((id, i) => {
|
|
822
|
+
const threadId = indexResults[i];
|
|
823
|
+
if (threadId) {
|
|
824
|
+
indexedMessages.push({ messageId: id, threadId });
|
|
825
|
+
} else {
|
|
826
|
+
unindexedMessageIds.push(id);
|
|
827
|
+
}
|
|
828
|
+
});
|
|
829
|
+
for (const { messageId, threadId } of indexedMessages) {
|
|
830
|
+
messageKeys.push(getMessageKey(threadId, messageId));
|
|
831
|
+
foundMessageIds.push(messageId);
|
|
832
|
+
threadIds.add(threadId);
|
|
833
|
+
}
|
|
834
|
+
for (const messageId of unindexedMessageIds) {
|
|
770
835
|
const pattern = getMessageKey("*", messageId);
|
|
771
836
|
const keys = await this.operations.scanKeys(pattern);
|
|
772
837
|
for (const key of keys) {
|
|
773
838
|
const message = await this.client.get(key);
|
|
774
839
|
if (message && message.id === messageId) {
|
|
775
840
|
messageKeys.push(key);
|
|
841
|
+
foundMessageIds.push(messageId);
|
|
776
842
|
if (message.threadId) {
|
|
777
843
|
threadIds.add(message.threadId);
|
|
778
844
|
}
|
|
@@ -787,6 +853,9 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
787
853
|
for (const key of messageKeys) {
|
|
788
854
|
pipeline.del(key);
|
|
789
855
|
}
|
|
856
|
+
for (const messageId of foundMessageIds) {
|
|
857
|
+
pipeline.del(getMessageIndexKey(messageId));
|
|
858
|
+
}
|
|
790
859
|
if (threadIds.size > 0) {
|
|
791
860
|
for (const threadId of threadIds) {
|
|
792
861
|
const threadKey = getKey(storage.TABLE_THREADS, { id: threadId });
|
|
@@ -962,32 +1031,7 @@ var StoreOperationsUpstash = class extends storage.StoreOperations {
|
|
|
962
1031
|
}
|
|
963
1032
|
};
|
|
964
1033
|
function transformScoreRow(row) {
|
|
965
|
-
|
|
966
|
-
if (typeof v === "string") {
|
|
967
|
-
try {
|
|
968
|
-
return JSON.parse(v);
|
|
969
|
-
} catch {
|
|
970
|
-
return v;
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
return v;
|
|
974
|
-
};
|
|
975
|
-
return {
|
|
976
|
-
...row,
|
|
977
|
-
scorer: parseField(row.scorer),
|
|
978
|
-
preprocessStepResult: parseField(row.preprocessStepResult),
|
|
979
|
-
generateScorePrompt: row.generateScorePrompt,
|
|
980
|
-
generateReasonPrompt: row.generateReasonPrompt,
|
|
981
|
-
analyzeStepResult: parseField(row.analyzeStepResult),
|
|
982
|
-
metadata: parseField(row.metadata),
|
|
983
|
-
input: parseField(row.input),
|
|
984
|
-
output: parseField(row.output),
|
|
985
|
-
additionalContext: parseField(row.additionalContext),
|
|
986
|
-
requestContext: parseField(row.requestContext),
|
|
987
|
-
entity: parseField(row.entity),
|
|
988
|
-
createdAt: row.createdAt,
|
|
989
|
-
updatedAt: row.updatedAt
|
|
990
|
-
};
|
|
1034
|
+
return storage.transformScoreRow(row);
|
|
991
1035
|
}
|
|
992
1036
|
var ScoresUpstash = class extends storage.ScoresStorage {
|
|
993
1037
|
client;
|
|
@@ -1011,7 +1055,9 @@ var ScoresUpstash = class extends storage.ScoresStorage {
|
|
|
1011
1055
|
id: "STORAGE_UPSTASH_STORAGE_GET_SCORE_BY_ID_FAILED",
|
|
1012
1056
|
domain: error.ErrorDomain.STORAGE,
|
|
1013
1057
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1014
|
-
details: {
|
|
1058
|
+
details: {
|
|
1059
|
+
...id && { id }
|
|
1060
|
+
}
|
|
1015
1061
|
},
|
|
1016
1062
|
error$1
|
|
1017
1063
|
);
|
|
@@ -2001,6 +2047,11 @@ var UpstashVector = class extends vector.MastraVector {
|
|
|
2001
2047
|
try {
|
|
2002
2048
|
await this.client.deleteNamespace(namespace);
|
|
2003
2049
|
} catch (error$1) {
|
|
2050
|
+
const errorMessage = error$1?.message || "";
|
|
2051
|
+
if (errorMessage.includes("does not exist") || errorMessage.includes("not found")) {
|
|
2052
|
+
this.logger.info(`Namespace ${namespace} does not exist, treating as already deleted`);
|
|
2053
|
+
return;
|
|
2054
|
+
}
|
|
2004
2055
|
throw new error.MastraError(
|
|
2005
2056
|
{
|
|
2006
2057
|
id: "STORAGE_UPSTASH_VECTOR_DELETE_INDEX_FAILED",
|
|
@@ -2013,47 +2064,124 @@ var UpstashVector = class extends vector.MastraVector {
|
|
|
2013
2064
|
}
|
|
2014
2065
|
}
|
|
2015
2066
|
/**
|
|
2016
|
-
* Updates a vector by its ID
|
|
2017
|
-
* @param
|
|
2018
|
-
* @param
|
|
2019
|
-
* @param
|
|
2020
|
-
* @param
|
|
2021
|
-
* @param update
|
|
2067
|
+
* Updates a vector by its ID or multiple vectors matching a filter.
|
|
2068
|
+
* @param params - Parameters containing the id or filter for targeting the vector(s) to update
|
|
2069
|
+
* @param params.indexName - The name of the namespace containing the vector.
|
|
2070
|
+
* @param params.id - The ID of the vector to update (mutually exclusive with filter).
|
|
2071
|
+
* @param params.filter - Filter to match multiple vectors to update (mutually exclusive with id).
|
|
2072
|
+
* @param params.update - An object containing the vector and/or metadata to update.
|
|
2022
2073
|
* @returns A promise that resolves when the update is complete.
|
|
2023
2074
|
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
2024
2075
|
*/
|
|
2025
|
-
async updateVector(
|
|
2026
|
-
|
|
2076
|
+
async updateVector(params) {
|
|
2077
|
+
const { indexName: namespace, update } = params;
|
|
2078
|
+
const upstashUpdate = update;
|
|
2079
|
+
const sparseVector = upstashUpdate.sparseVector;
|
|
2080
|
+
if ("id" in params && params.id && "filter" in params && params.filter) {
|
|
2081
|
+
throw new error.MastraError({
|
|
2082
|
+
id: "STORAGE_UPSTASH_VECTOR_UPDATE_MUTUALLY_EXCLUSIVE",
|
|
2083
|
+
text: "Cannot specify both id and filter - they are mutually exclusive",
|
|
2084
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2085
|
+
category: error.ErrorCategory.USER,
|
|
2086
|
+
details: { namespace }
|
|
2087
|
+
});
|
|
2088
|
+
}
|
|
2089
|
+
if (!("id" in params && params.id) && !("filter" in params && params.filter)) {
|
|
2027
2090
|
throw new error.MastraError({
|
|
2028
|
-
id: "
|
|
2091
|
+
id: "STORAGE_UPSTASH_VECTOR_UPDATE_NO_TARGET",
|
|
2092
|
+
text: "Either id or filter must be provided",
|
|
2029
2093
|
domain: error.ErrorDomain.STORAGE,
|
|
2030
|
-
category: error.ErrorCategory.
|
|
2031
|
-
details: { namespace
|
|
2032
|
-
text: "No update data provided"
|
|
2094
|
+
category: error.ErrorCategory.USER,
|
|
2095
|
+
details: { namespace }
|
|
2033
2096
|
});
|
|
2034
2097
|
}
|
|
2035
|
-
if (!update.vector && !update.
|
|
2098
|
+
if (!update.vector && !update.metadata && !sparseVector) {
|
|
2036
2099
|
throw new error.MastraError({
|
|
2037
|
-
id: "
|
|
2100
|
+
id: "STORAGE_UPSTASH_VECTOR_UPDATE_NO_PAYLOAD",
|
|
2101
|
+
text: "No update data provided",
|
|
2038
2102
|
domain: error.ErrorDomain.STORAGE,
|
|
2039
|
-
category: error.ErrorCategory.
|
|
2040
|
-
details: { namespace
|
|
2041
|
-
|
|
2103
|
+
category: error.ErrorCategory.USER,
|
|
2104
|
+
details: { namespace }
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
|
|
2108
|
+
throw new error.MastraError({
|
|
2109
|
+
id: "STORAGE_UPSTASH_VECTOR_UPDATE_EMPTY_FILTER",
|
|
2110
|
+
text: "Filter cannot be an empty filter object",
|
|
2111
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2112
|
+
category: error.ErrorCategory.USER,
|
|
2113
|
+
details: { namespace }
|
|
2042
2114
|
});
|
|
2043
2115
|
}
|
|
2044
2116
|
try {
|
|
2045
|
-
const
|
|
2046
|
-
if (
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2117
|
+
const ns = this.client.namespace(namespace);
|
|
2118
|
+
if ("id" in params && params.id) {
|
|
2119
|
+
const points = { id: params.id };
|
|
2120
|
+
if (!update.vector || !update.metadata) {
|
|
2121
|
+
try {
|
|
2122
|
+
const existing = await ns.fetch([params.id], {
|
|
2123
|
+
includeVectors: true,
|
|
2124
|
+
includeMetadata: true
|
|
2125
|
+
});
|
|
2126
|
+
if (existing && existing.length > 0 && existing[0]) {
|
|
2127
|
+
if (!update.vector && existing[0]?.vector) {
|
|
2128
|
+
points.vector = existing[0].vector;
|
|
2129
|
+
}
|
|
2130
|
+
if (!update.metadata && existing[0]?.metadata) {
|
|
2131
|
+
points.metadata = existing[0].metadata;
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
} catch (fetchError) {
|
|
2135
|
+
this.logger.warn(`Failed to fetch existing vector ${params.id} for partial update: ${fetchError}`);
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
if (update.vector) points.vector = update.vector;
|
|
2139
|
+
if (update.metadata) points.metadata = update.metadata;
|
|
2140
|
+
if (sparseVector) points.sparseVector = sparseVector;
|
|
2141
|
+
await ns.upsert(points);
|
|
2142
|
+
} else if ("filter" in params && params.filter) {
|
|
2143
|
+
const filterString = this.transformFilter(params.filter);
|
|
2144
|
+
if (filterString) {
|
|
2145
|
+
const stats = await this.describeIndex({ indexName: namespace });
|
|
2146
|
+
const dummyVector = new Array(stats.dimension).fill(1 / Math.sqrt(stats.dimension));
|
|
2147
|
+
const needsVectors = !update.vector;
|
|
2148
|
+
const results = await ns.query({
|
|
2149
|
+
vector: dummyVector,
|
|
2150
|
+
topK: 1e3,
|
|
2151
|
+
// Upstash's max query limit
|
|
2152
|
+
filter: filterString,
|
|
2153
|
+
includeVectors: needsVectors,
|
|
2154
|
+
includeMetadata: needsVectors
|
|
2155
|
+
});
|
|
2156
|
+
for (const result of results) {
|
|
2157
|
+
const points = { id: `${result.id}` };
|
|
2158
|
+
if (update.vector) {
|
|
2159
|
+
points.vector = update.vector;
|
|
2160
|
+
} else if (result.vector) {
|
|
2161
|
+
points.vector = result.vector;
|
|
2162
|
+
}
|
|
2163
|
+
if (update.metadata) {
|
|
2164
|
+
points.metadata = update.metadata;
|
|
2165
|
+
} else if (result.metadata) {
|
|
2166
|
+
points.metadata = result.metadata;
|
|
2167
|
+
}
|
|
2168
|
+
if (sparseVector) points.sparseVector = sparseVector;
|
|
2169
|
+
await ns.upsert(points);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2050
2173
|
} catch (error$1) {
|
|
2174
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
2051
2175
|
throw new error.MastraError(
|
|
2052
2176
|
{
|
|
2053
2177
|
id: "STORAGE_UPSTASH_VECTOR_UPDATE_VECTOR_FAILED",
|
|
2054
2178
|
domain: error.ErrorDomain.STORAGE,
|
|
2055
2179
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2056
|
-
details: {
|
|
2180
|
+
details: {
|
|
2181
|
+
namespace,
|
|
2182
|
+
..."id" in params && params.id && { id: params.id },
|
|
2183
|
+
..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) }
|
|
2184
|
+
}
|
|
2057
2185
|
},
|
|
2058
2186
|
error$1
|
|
2059
2187
|
);
|
|
@@ -2068,22 +2196,109 @@ var UpstashVector = class extends vector.MastraVector {
|
|
|
2068
2196
|
*/
|
|
2069
2197
|
async deleteVector({ indexName: namespace, id }) {
|
|
2070
2198
|
try {
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
});
|
|
2199
|
+
const ns = this.client.namespace(namespace);
|
|
2200
|
+
await ns.delete(id);
|
|
2074
2201
|
} catch (error$1) {
|
|
2075
2202
|
const mastraError = new error.MastraError(
|
|
2076
2203
|
{
|
|
2077
2204
|
id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTOR_FAILED",
|
|
2078
2205
|
domain: error.ErrorDomain.STORAGE,
|
|
2079
2206
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2080
|
-
details: {
|
|
2207
|
+
details: {
|
|
2208
|
+
namespace,
|
|
2209
|
+
...id && { id }
|
|
2210
|
+
}
|
|
2081
2211
|
},
|
|
2082
2212
|
error$1
|
|
2083
2213
|
);
|
|
2084
2214
|
this.logger?.error(mastraError.toString());
|
|
2085
2215
|
}
|
|
2086
2216
|
}
|
|
2217
|
+
/**
|
|
2218
|
+
* Deletes multiple vectors by IDs or filter.
|
|
2219
|
+
* @param indexName - The name of the namespace containing the vectors.
|
|
2220
|
+
* @param ids - Array of vector IDs to delete (mutually exclusive with filter).
|
|
2221
|
+
* @param filter - Filter to match vectors to delete (mutually exclusive with ids).
|
|
2222
|
+
* @returns A promise that resolves when the deletion is complete.
|
|
2223
|
+
* @throws Will throw an error if both ids and filter are provided, or if neither is provided.
|
|
2224
|
+
*/
|
|
2225
|
+
async deleteVectors({ indexName: namespace, filter, ids }) {
|
|
2226
|
+
if (ids && filter) {
|
|
2227
|
+
throw new error.MastraError({
|
|
2228
|
+
id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_MUTUALLY_EXCLUSIVE",
|
|
2229
|
+
text: "Cannot specify both ids and filter - they are mutually exclusive",
|
|
2230
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2231
|
+
category: error.ErrorCategory.USER,
|
|
2232
|
+
details: { namespace }
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2235
|
+
if (!ids && !filter) {
|
|
2236
|
+
throw new error.MastraError({
|
|
2237
|
+
id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_NO_TARGET",
|
|
2238
|
+
text: "Either filter or ids must be provided",
|
|
2239
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2240
|
+
category: error.ErrorCategory.USER,
|
|
2241
|
+
details: { namespace }
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
if (ids && ids.length === 0) {
|
|
2245
|
+
throw new error.MastraError({
|
|
2246
|
+
id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_EMPTY_IDS",
|
|
2247
|
+
text: "Cannot delete with empty ids array",
|
|
2248
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2249
|
+
category: error.ErrorCategory.USER,
|
|
2250
|
+
details: { namespace }
|
|
2251
|
+
});
|
|
2252
|
+
}
|
|
2253
|
+
if (filter && Object.keys(filter).length === 0) {
|
|
2254
|
+
throw new error.MastraError({
|
|
2255
|
+
id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_EMPTY_FILTER",
|
|
2256
|
+
text: "Cannot delete with empty filter object",
|
|
2257
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2258
|
+
category: error.ErrorCategory.USER,
|
|
2259
|
+
details: { namespace }
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
try {
|
|
2263
|
+
const ns = this.client.namespace(namespace);
|
|
2264
|
+
if (ids) {
|
|
2265
|
+
await ns.delete(ids);
|
|
2266
|
+
} else if (filter) {
|
|
2267
|
+
const filterString = this.transformFilter(filter);
|
|
2268
|
+
if (filterString) {
|
|
2269
|
+
const stats = await this.describeIndex({ indexName: namespace });
|
|
2270
|
+
const dummyVector = new Array(stats.dimension).fill(1 / Math.sqrt(stats.dimension));
|
|
2271
|
+
const results = await ns.query({
|
|
2272
|
+
vector: dummyVector,
|
|
2273
|
+
topK: 1e3,
|
|
2274
|
+
// Upstash's max query limit
|
|
2275
|
+
filter: filterString,
|
|
2276
|
+
includeVectors: false,
|
|
2277
|
+
includeMetadata: false
|
|
2278
|
+
});
|
|
2279
|
+
const idsToDelete = results.map((r) => `${r.id}`);
|
|
2280
|
+
if (idsToDelete.length > 0) {
|
|
2281
|
+
await ns.delete(idsToDelete);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
} catch (error$1) {
|
|
2286
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
2287
|
+
throw new error.MastraError(
|
|
2288
|
+
{
|
|
2289
|
+
id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_FAILED",
|
|
2290
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2291
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2292
|
+
details: {
|
|
2293
|
+
namespace,
|
|
2294
|
+
...filter && { filter: JSON.stringify(filter) },
|
|
2295
|
+
...ids && { idsCount: ids.length }
|
|
2296
|
+
}
|
|
2297
|
+
},
|
|
2298
|
+
error$1
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2087
2302
|
};
|
|
2088
2303
|
|
|
2089
2304
|
// src/vector/prompt.ts
|