@mastra/upstash 1.0.0-beta.1 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -498,13 +498,11 @@ var StoreMemoryUpstash = class extends MemoryStorage {
498
498
  }
499
499
  return 0;
500
500
  };
501
- if (orderBy) {
502
- messagesData.sort((a, b) => {
503
- const aValue = getFieldValue(a);
504
- const bValue = getFieldValue(b);
505
- return direction === "ASC" ? aValue - bValue : bValue - aValue;
506
- });
507
- }
501
+ messagesData.sort((a, b) => {
502
+ const aValue = getFieldValue(a);
503
+ const bValue = getFieldValue(b);
504
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
505
+ });
508
506
  const total = messagesData.length;
509
507
  const start = offset;
510
508
  const end = perPageInput === false ? total : start + perPage;
@@ -525,23 +523,11 @@ var StoreMemoryUpstash = class extends MemoryStorage {
525
523
  }
526
524
  const list = new MessageList().add(allMessages, "memory");
527
525
  let finalMessages = list.get.all.db();
528
- if (orderBy) {
529
- finalMessages = finalMessages.sort((a, b) => {
530
- const aValue = getFieldValue(a);
531
- const bValue = getFieldValue(b);
532
- return direction === "ASC" ? aValue - bValue : bValue - aValue;
533
- });
534
- } else {
535
- const messageIdToPosition = /* @__PURE__ */ new Map();
536
- allMessageIds.forEach((id, index) => {
537
- messageIdToPosition.set(id, index);
538
- });
539
- finalMessages = finalMessages.sort((a, b) => {
540
- const aPos = messageIdToPosition.get(a.id) ?? Number.MAX_SAFE_INTEGER;
541
- const bPos = messageIdToPosition.get(b.id) ?? Number.MAX_SAFE_INTEGER;
542
- return aPos - bPos;
543
- });
544
- }
526
+ finalMessages = finalMessages.sort((a, b) => {
527
+ const aValue = getFieldValue(a);
528
+ const bValue = getFieldValue(b);
529
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
530
+ });
545
531
  const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
546
532
  const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
547
533
  const hasMore = perPageInput !== false && !allThreadMessagesReturned && end < total;
@@ -1009,7 +995,9 @@ var ScoresUpstash = class extends ScoresStorage {
1009
995
  id: "STORAGE_UPSTASH_STORAGE_GET_SCORE_BY_ID_FAILED",
1010
996
  domain: ErrorDomain.STORAGE,
1011
997
  category: ErrorCategory.THIRD_PARTY,
1012
- details: { id }
998
+ details: {
999
+ ...id && { id }
1000
+ }
1013
1001
  },
1014
1002
  error
1015
1003
  );
@@ -1999,6 +1987,11 @@ var UpstashVector = class extends MastraVector {
1999
1987
  try {
2000
1988
  await this.client.deleteNamespace(namespace);
2001
1989
  } catch (error) {
1990
+ const errorMessage = error?.message || "";
1991
+ if (errorMessage.includes("does not exist") || errorMessage.includes("not found")) {
1992
+ this.logger.info(`Namespace ${namespace} does not exist, treating as already deleted`);
1993
+ return;
1994
+ }
2002
1995
  throw new MastraError(
2003
1996
  {
2004
1997
  id: "STORAGE_UPSTASH_VECTOR_DELETE_INDEX_FAILED",
@@ -2011,47 +2004,124 @@ var UpstashVector = class extends MastraVector {
2011
2004
  }
2012
2005
  }
2013
2006
  /**
2014
- * Updates a vector by its ID with the provided vector and/or metadata.
2015
- * @param indexName - The name of the namespace containing the vector.
2016
- * @param id - The ID of the vector to update.
2017
- * @param update - An object containing the vector and/or metadata to update.
2018
- * @param update.vector - An optional array of numbers representing the new vector.
2019
- * @param update.metadata - An optional record containing the new metadata.
2007
+ * Updates a vector by its ID or multiple vectors matching a filter.
2008
+ * @param params - Parameters containing the id or filter for targeting the vector(s) to update
2009
+ * @param params.indexName - The name of the namespace containing the vector.
2010
+ * @param params.id - The ID of the vector to update (mutually exclusive with filter).
2011
+ * @param params.filter - Filter to match multiple vectors to update (mutually exclusive with id).
2012
+ * @param params.update - An object containing the vector and/or metadata to update.
2020
2013
  * @returns A promise that resolves when the update is complete.
2021
2014
  * @throws Will throw an error if no updates are provided or if the update operation fails.
2022
2015
  */
2023
- async updateVector({ indexName: namespace, id, update }) {
2024
- if (!update.vector && !update.metadata && !update.sparseVector) {
2016
+ async updateVector(params) {
2017
+ const { indexName: namespace, update } = params;
2018
+ const upstashUpdate = update;
2019
+ const sparseVector = upstashUpdate.sparseVector;
2020
+ if ("id" in params && params.id && "filter" in params && params.filter) {
2025
2021
  throw new MastraError({
2026
- id: "STORAGE_UPSTASH_VECTOR_UPDATE_VECTOR_FAILED",
2022
+ id: "STORAGE_UPSTASH_VECTOR_UPDATE_MUTUALLY_EXCLUSIVE",
2023
+ text: "Cannot specify both id and filter - they are mutually exclusive",
2027
2024
  domain: ErrorDomain.STORAGE,
2028
- category: ErrorCategory.THIRD_PARTY,
2029
- details: { namespace, id },
2030
- text: "No update data provided"
2025
+ category: ErrorCategory.USER,
2026
+ details: { namespace }
2031
2027
  });
2032
2028
  }
2033
- if (!update.vector && !update.sparseVector && update.metadata) {
2029
+ if (!("id" in params && params.id) && !("filter" in params && params.filter)) {
2034
2030
  throw new MastraError({
2035
- id: "STORAGE_UPSTASH_VECTOR_UPDATE_VECTOR_FAILED",
2031
+ id: "STORAGE_UPSTASH_VECTOR_UPDATE_NO_TARGET",
2032
+ text: "Either id or filter must be provided",
2036
2033
  domain: ErrorDomain.STORAGE,
2037
- category: ErrorCategory.THIRD_PARTY,
2038
- details: { namespace, id },
2039
- text: "Both vector and metadata must be provided for an update"
2034
+ category: ErrorCategory.USER,
2035
+ details: { namespace }
2036
+ });
2037
+ }
2038
+ if (!update.vector && !update.metadata && !sparseVector) {
2039
+ throw new MastraError({
2040
+ id: "STORAGE_UPSTASH_VECTOR_UPDATE_NO_PAYLOAD",
2041
+ text: "No update data provided",
2042
+ domain: ErrorDomain.STORAGE,
2043
+ category: ErrorCategory.USER,
2044
+ details: { namespace }
2045
+ });
2046
+ }
2047
+ if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
2048
+ throw new MastraError({
2049
+ id: "STORAGE_UPSTASH_VECTOR_UPDATE_EMPTY_FILTER",
2050
+ text: "Filter cannot be an empty filter object",
2051
+ domain: ErrorDomain.STORAGE,
2052
+ category: ErrorCategory.USER,
2053
+ details: { namespace }
2040
2054
  });
2041
2055
  }
2042
2056
  try {
2043
- const points = { id };
2044
- if (update.vector) points.vector = update.vector;
2045
- if (update.metadata) points.metadata = update.metadata;
2046
- if (update.sparseVector) points.sparseVector = update.sparseVector;
2047
- await this.client.upsert(points, { namespace });
2057
+ const ns = this.client.namespace(namespace);
2058
+ if ("id" in params && params.id) {
2059
+ const points = { id: params.id };
2060
+ if (!update.vector || !update.metadata) {
2061
+ try {
2062
+ const existing = await ns.fetch([params.id], {
2063
+ includeVectors: true,
2064
+ includeMetadata: true
2065
+ });
2066
+ if (existing && existing.length > 0 && existing[0]) {
2067
+ if (!update.vector && existing[0]?.vector) {
2068
+ points.vector = existing[0].vector;
2069
+ }
2070
+ if (!update.metadata && existing[0]?.metadata) {
2071
+ points.metadata = existing[0].metadata;
2072
+ }
2073
+ }
2074
+ } catch (fetchError) {
2075
+ this.logger.warn(`Failed to fetch existing vector ${params.id} for partial update: ${fetchError}`);
2076
+ }
2077
+ }
2078
+ if (update.vector) points.vector = update.vector;
2079
+ if (update.metadata) points.metadata = update.metadata;
2080
+ if (sparseVector) points.sparseVector = sparseVector;
2081
+ await ns.upsert(points);
2082
+ } else if ("filter" in params && params.filter) {
2083
+ const filterString = this.transformFilter(params.filter);
2084
+ if (filterString) {
2085
+ const stats = await this.describeIndex({ indexName: namespace });
2086
+ const dummyVector = new Array(stats.dimension).fill(1 / Math.sqrt(stats.dimension));
2087
+ const needsVectors = !update.vector;
2088
+ const results = await ns.query({
2089
+ vector: dummyVector,
2090
+ topK: 1e3,
2091
+ // Upstash's max query limit
2092
+ filter: filterString,
2093
+ includeVectors: needsVectors,
2094
+ includeMetadata: needsVectors
2095
+ });
2096
+ for (const result of results) {
2097
+ const points = { id: `${result.id}` };
2098
+ if (update.vector) {
2099
+ points.vector = update.vector;
2100
+ } else if (result.vector) {
2101
+ points.vector = result.vector;
2102
+ }
2103
+ if (update.metadata) {
2104
+ points.metadata = update.metadata;
2105
+ } else if (result.metadata) {
2106
+ points.metadata = result.metadata;
2107
+ }
2108
+ if (sparseVector) points.sparseVector = sparseVector;
2109
+ await ns.upsert(points);
2110
+ }
2111
+ }
2112
+ }
2048
2113
  } catch (error) {
2114
+ if (error instanceof MastraError) throw error;
2049
2115
  throw new MastraError(
2050
2116
  {
2051
2117
  id: "STORAGE_UPSTASH_VECTOR_UPDATE_VECTOR_FAILED",
2052
2118
  domain: ErrorDomain.STORAGE,
2053
2119
  category: ErrorCategory.THIRD_PARTY,
2054
- details: { namespace, id }
2120
+ details: {
2121
+ namespace,
2122
+ ..."id" in params && params.id && { id: params.id },
2123
+ ..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) }
2124
+ }
2055
2125
  },
2056
2126
  error
2057
2127
  );
@@ -2066,22 +2136,109 @@ var UpstashVector = class extends MastraVector {
2066
2136
  */
2067
2137
  async deleteVector({ indexName: namespace, id }) {
2068
2138
  try {
2069
- await this.client.delete(id, {
2070
- namespace
2071
- });
2139
+ const ns = this.client.namespace(namespace);
2140
+ await ns.delete(id);
2072
2141
  } catch (error) {
2073
2142
  const mastraError = new MastraError(
2074
2143
  {
2075
2144
  id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTOR_FAILED",
2076
2145
  domain: ErrorDomain.STORAGE,
2077
2146
  category: ErrorCategory.THIRD_PARTY,
2078
- details: { namespace, id }
2147
+ details: {
2148
+ namespace,
2149
+ ...id && { id }
2150
+ }
2079
2151
  },
2080
2152
  error
2081
2153
  );
2082
2154
  this.logger?.error(mastraError.toString());
2083
2155
  }
2084
2156
  }
2157
+ /**
2158
+ * Deletes multiple vectors by IDs or filter.
2159
+ * @param indexName - The name of the namespace containing the vectors.
2160
+ * @param ids - Array of vector IDs to delete (mutually exclusive with filter).
2161
+ * @param filter - Filter to match vectors to delete (mutually exclusive with ids).
2162
+ * @returns A promise that resolves when the deletion is complete.
2163
+ * @throws Will throw an error if both ids and filter are provided, or if neither is provided.
2164
+ */
2165
+ async deleteVectors({ indexName: namespace, filter, ids }) {
2166
+ if (ids && filter) {
2167
+ throw new MastraError({
2168
+ id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_MUTUALLY_EXCLUSIVE",
2169
+ text: "Cannot specify both ids and filter - they are mutually exclusive",
2170
+ domain: ErrorDomain.STORAGE,
2171
+ category: ErrorCategory.USER,
2172
+ details: { namespace }
2173
+ });
2174
+ }
2175
+ if (!ids && !filter) {
2176
+ throw new MastraError({
2177
+ id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_NO_TARGET",
2178
+ text: "Either filter or ids must be provided",
2179
+ domain: ErrorDomain.STORAGE,
2180
+ category: ErrorCategory.USER,
2181
+ details: { namespace }
2182
+ });
2183
+ }
2184
+ if (ids && ids.length === 0) {
2185
+ throw new MastraError({
2186
+ id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_EMPTY_IDS",
2187
+ text: "Cannot delete with empty ids array",
2188
+ domain: ErrorDomain.STORAGE,
2189
+ category: ErrorCategory.USER,
2190
+ details: { namespace }
2191
+ });
2192
+ }
2193
+ if (filter && Object.keys(filter).length === 0) {
2194
+ throw new MastraError({
2195
+ id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_EMPTY_FILTER",
2196
+ text: "Cannot delete with empty filter object",
2197
+ domain: ErrorDomain.STORAGE,
2198
+ category: ErrorCategory.USER,
2199
+ details: { namespace }
2200
+ });
2201
+ }
2202
+ try {
2203
+ const ns = this.client.namespace(namespace);
2204
+ if (ids) {
2205
+ await ns.delete(ids);
2206
+ } else if (filter) {
2207
+ const filterString = this.transformFilter(filter);
2208
+ if (filterString) {
2209
+ const stats = await this.describeIndex({ indexName: namespace });
2210
+ const dummyVector = new Array(stats.dimension).fill(1 / Math.sqrt(stats.dimension));
2211
+ const results = await ns.query({
2212
+ vector: dummyVector,
2213
+ topK: 1e3,
2214
+ // Upstash's max query limit
2215
+ filter: filterString,
2216
+ includeVectors: false,
2217
+ includeMetadata: false
2218
+ });
2219
+ const idsToDelete = results.map((r) => `${r.id}`);
2220
+ if (idsToDelete.length > 0) {
2221
+ await ns.delete(idsToDelete);
2222
+ }
2223
+ }
2224
+ }
2225
+ } catch (error) {
2226
+ if (error instanceof MastraError) throw error;
2227
+ throw new MastraError(
2228
+ {
2229
+ id: "STORAGE_UPSTASH_VECTOR_DELETE_VECTORS_FAILED",
2230
+ domain: ErrorDomain.STORAGE,
2231
+ category: ErrorCategory.THIRD_PARTY,
2232
+ details: {
2233
+ namespace,
2234
+ ...filter && { filter: JSON.stringify(filter) },
2235
+ ...ids && { idsCount: ids.length }
2236
+ }
2237
+ },
2238
+ error
2239
+ );
2240
+ }
2241
+ }
2085
2242
  };
2086
2243
 
2087
2244
  // src/vector/prompt.ts