@prmichaelsen/remember-mcp 3.14.1 → 3.14.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.
@@ -2256,6 +2256,20 @@ var MemoryService = class {
2256
2256
  this.userId = userId;
2257
2257
  this.logger = logger2;
2258
2258
  }
2259
+ /**
2260
+ * Execute a search function, retrying without the deleted_at filter if
2261
+ * the collection lacks indexNullState (created before soft-delete support).
2262
+ */
2263
+ async retryWithoutDeletedFilter(fn) {
2264
+ try {
2265
+ return await fn(true);
2266
+ } catch (err2) {
2267
+ if (err2?.message?.includes("Nullstate must be indexed")) {
2268
+ return fn(false);
2269
+ }
2270
+ throw err2;
2271
+ }
2272
+ }
2259
2273
  // ── Create ──────────────────────────────────────────────────────────
2260
2274
  async create(input) {
2261
2275
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2301,7 +2315,6 @@ var MemoryService = class {
2301
2315
  const alpha = input.alpha ?? 0.7;
2302
2316
  const limit = input.limit ?? 10;
2303
2317
  const offset = input.offset ?? 0;
2304
- const deletedFilter = buildDeletedFilter(this.collection, input.deleted_filter || "exclude");
2305
2318
  const searchFilters = includeRelationships ? buildCombinedSearchFilters(this.collection, input.filters) : buildMemoryOnlyFilters(this.collection, input.filters);
2306
2319
  const ghostFilters = [];
2307
2320
  if (input.ghost_context) {
@@ -2310,11 +2323,21 @@ var MemoryService = class {
2310
2323
  if (!input.ghost_context?.include_ghost_content) {
2311
2324
  ghostFilters.push(this.collection.filter.byProperty("content_type").notEqual("ghost"));
2312
2325
  }
2313
- const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters, ...ghostFilters].filter((f) => f !== null));
2314
- const searchOptions = { alpha, limit: limit + offset };
2315
- if (combinedFilters)
2316
- searchOptions.filters = combinedFilters;
2317
- const results = await this.collection.query.hybrid(input.query, searchOptions);
2326
+ const isWildcard = input.query === "*";
2327
+ const executeSearch = async (useDeletedFilter) => {
2328
+ const deletedFilter = useDeletedFilter ? buildDeletedFilter(this.collection, input.deleted_filter || "exclude") : null;
2329
+ const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters, ...ghostFilters].filter((f) => f !== null));
2330
+ const searchOptions = { limit: limit + offset };
2331
+ if (combinedFilters)
2332
+ searchOptions.filters = combinedFilters;
2333
+ if (isWildcard) {
2334
+ return this.collection.query.fetchObjects(searchOptions);
2335
+ } else {
2336
+ searchOptions.alpha = alpha;
2337
+ return this.collection.query.hybrid(input.query, searchOptions);
2338
+ }
2339
+ };
2340
+ const results = await this.retryWithoutDeletedFilter(executeSearch);
2318
2341
  const paginated = results.objects.slice(offset);
2319
2342
  const memories = [];
2320
2343
  const relationships = [];
@@ -2341,7 +2364,6 @@ var MemoryService = class {
2341
2364
  throw new Error("Provide either memory_id or text, not both");
2342
2365
  const limit = input.limit ?? 10;
2343
2366
  const minSimilarity = input.min_similarity ?? 0.7;
2344
- const deletedFilter = buildDeletedFilter(this.collection, input.deleted_filter || "exclude");
2345
2367
  const ghostFilters = [];
2346
2368
  if (input.ghost_context) {
2347
2369
  ghostFilters.push(buildTrustFilter(this.collection, input.ghost_context.accessor_trust_level));
@@ -2349,29 +2371,35 @@ var MemoryService = class {
2349
2371
  if (!input.ghost_context?.include_ghost_content) {
2350
2372
  ghostFilters.push(this.collection.filter.byProperty("content_type").notEqual("ghost"));
2351
2373
  }
2352
- const combinedFilter = combineFiltersWithAnd([deletedFilter, ...ghostFilters].filter((f) => f !== null));
2353
- let results;
2374
+ let memoryObj = null;
2354
2375
  if (input.memory_id) {
2355
- const memory = await this.collection.query.fetchObjectById(input.memory_id, {
2376
+ memoryObj = await this.collection.query.fetchObjectById(input.memory_id, {
2356
2377
  returnProperties: ["user_id", "doc_type", "content"]
2357
2378
  });
2358
- if (!memory)
2379
+ if (!memoryObj)
2359
2380
  throw new Error(`Memory not found: ${input.memory_id}`);
2360
- if (memory.properties.user_id !== this.userId)
2381
+ if (memoryObj.properties.user_id !== this.userId)
2361
2382
  throw new Error("Unauthorized");
2362
- if (memory.properties.doc_type !== "memory")
2383
+ if (memoryObj.properties.doc_type !== "memory")
2363
2384
  throw new Error("Can only find similar for memory documents");
2364
- const opts = { limit: limit + 1, distance: 1 - minSimilarity, returnMetadata: ["distance"] };
2365
- if (combinedFilter)
2366
- opts.filters = combinedFilter;
2367
- results = await this.collection.query.nearObject(input.memory_id, opts);
2368
- results.objects = results.objects.filter((o) => o.uuid !== input.memory_id);
2369
- } else {
2370
- const opts = { limit, distance: 1 - minSimilarity, returnMetadata: ["distance"] };
2371
- if (combinedFilter)
2372
- opts.filters = combinedFilter;
2373
- results = await this.collection.query.nearText(input.text, opts);
2374
2385
  }
2386
+ const results = await this.retryWithoutDeletedFilter(async (useDeletedFilter) => {
2387
+ const deletedFilter = useDeletedFilter ? buildDeletedFilter(this.collection, input.deleted_filter || "exclude") : null;
2388
+ const combinedFilter = combineFiltersWithAnd([deletedFilter, ...ghostFilters].filter((f) => f !== null));
2389
+ if (input.memory_id) {
2390
+ const opts = { limit: limit + 1, distance: 1 - minSimilarity, returnMetadata: ["distance"] };
2391
+ if (combinedFilter)
2392
+ opts.filters = combinedFilter;
2393
+ const res = await this.collection.query.nearObject(input.memory_id, opts);
2394
+ res.objects = res.objects.filter((o) => o.uuid !== input.memory_id);
2395
+ return res;
2396
+ } else {
2397
+ const opts = { limit, distance: 1 - minSimilarity, returnMetadata: ["distance"] };
2398
+ if (combinedFilter)
2399
+ opts.filters = combinedFilter;
2400
+ return this.collection.query.nearText(input.text, opts);
2401
+ }
2402
+ });
2375
2403
  if (!input.include_relationships) {
2376
2404
  results.objects = results.objects.filter((o) => o.properties.doc_type === "memory");
2377
2405
  }
@@ -2388,7 +2416,6 @@ var MemoryService = class {
2388
2416
  throw new Error("Query cannot be empty");
2389
2417
  const limit = input.limit ?? 5;
2390
2418
  const minRelevance = input.min_relevance ?? 0.6;
2391
- const deletedFilter = buildDeletedFilter(this.collection, input.deleted_filter || "exclude");
2392
2419
  const searchFilters = buildCombinedSearchFilters(this.collection, input.filters);
2393
2420
  const ghostFilters = [];
2394
2421
  if (input.ghost_context) {
@@ -2397,11 +2424,14 @@ var MemoryService = class {
2397
2424
  if (!input.ghost_context?.include_ghost_content) {
2398
2425
  ghostFilters.push(this.collection.filter.byProperty("content_type").notEqual("ghost"));
2399
2426
  }
2400
- const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters, ...ghostFilters].filter((f) => f !== null));
2401
- const opts = { limit, distance: 1 - minRelevance, returnMetadata: ["distance"] };
2402
- if (combinedFilters)
2403
- opts.filters = combinedFilters;
2404
- const results = await this.collection.query.nearText(input.query, opts);
2427
+ const results = await this.retryWithoutDeletedFilter(async (useDeletedFilter) => {
2428
+ const deletedFilter = useDeletedFilter ? buildDeletedFilter(this.collection, input.deleted_filter || "exclude") : null;
2429
+ const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters, ...ghostFilters].filter((f) => f !== null));
2430
+ const opts = { limit, distance: 1 - minRelevance, returnMetadata: ["distance"] };
2431
+ if (combinedFilters)
2432
+ opts.filters = combinedFilters;
2433
+ return this.collection.query.nearText(input.query, opts);
2434
+ });
2405
2435
  const items = results.objects.map((obj) => ({
2406
2436
  id: obj.uuid,
2407
2437
  ...obj.properties,
@@ -3510,7 +3540,6 @@ var SpaceService = class {
3510
3540
  // ── Private: Build Base Filters ─────────────────────────────────────
3511
3541
  buildBaseFilters(collection, input) {
3512
3542
  const filterList = [];
3513
- filterList.push(collection.filter.byProperty("deleted_at").isNull(true));
3514
3543
  filterList.push(collection.filter.byProperty("doc_type").equal("memory"));
3515
3544
  const moderationFilter = buildModerationFilter(collection, input.moderation_filter);
3516
3545
  if (moderationFilter)
package/dist/server.js CHANGED
@@ -1940,6 +1940,20 @@ var MemoryService = class {
1940
1940
  this.userId = userId;
1941
1941
  this.logger = logger2;
1942
1942
  }
1943
+ /**
1944
+ * Execute a search function, retrying without the deleted_at filter if
1945
+ * the collection lacks indexNullState (created before soft-delete support).
1946
+ */
1947
+ async retryWithoutDeletedFilter(fn) {
1948
+ try {
1949
+ return await fn(true);
1950
+ } catch (err2) {
1951
+ if (err2?.message?.includes("Nullstate must be indexed")) {
1952
+ return fn(false);
1953
+ }
1954
+ throw err2;
1955
+ }
1956
+ }
1943
1957
  // ── Create ──────────────────────────────────────────────────────────
1944
1958
  async create(input) {
1945
1959
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1985,7 +1999,6 @@ var MemoryService = class {
1985
1999
  const alpha = input.alpha ?? 0.7;
1986
2000
  const limit = input.limit ?? 10;
1987
2001
  const offset = input.offset ?? 0;
1988
- const deletedFilter = buildDeletedFilter(this.collection, input.deleted_filter || "exclude");
1989
2002
  const searchFilters = includeRelationships ? buildCombinedSearchFilters(this.collection, input.filters) : buildMemoryOnlyFilters(this.collection, input.filters);
1990
2003
  const ghostFilters = [];
1991
2004
  if (input.ghost_context) {
@@ -1994,11 +2007,21 @@ var MemoryService = class {
1994
2007
  if (!input.ghost_context?.include_ghost_content) {
1995
2008
  ghostFilters.push(this.collection.filter.byProperty("content_type").notEqual("ghost"));
1996
2009
  }
1997
- const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters, ...ghostFilters].filter((f) => f !== null));
1998
- const searchOptions = { alpha, limit: limit + offset };
1999
- if (combinedFilters)
2000
- searchOptions.filters = combinedFilters;
2001
- const results = await this.collection.query.hybrid(input.query, searchOptions);
2010
+ const isWildcard = input.query === "*";
2011
+ const executeSearch = async (useDeletedFilter) => {
2012
+ const deletedFilter = useDeletedFilter ? buildDeletedFilter(this.collection, input.deleted_filter || "exclude") : null;
2013
+ const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters, ...ghostFilters].filter((f) => f !== null));
2014
+ const searchOptions = { limit: limit + offset };
2015
+ if (combinedFilters)
2016
+ searchOptions.filters = combinedFilters;
2017
+ if (isWildcard) {
2018
+ return this.collection.query.fetchObjects(searchOptions);
2019
+ } else {
2020
+ searchOptions.alpha = alpha;
2021
+ return this.collection.query.hybrid(input.query, searchOptions);
2022
+ }
2023
+ };
2024
+ const results = await this.retryWithoutDeletedFilter(executeSearch);
2002
2025
  const paginated = results.objects.slice(offset);
2003
2026
  const memories = [];
2004
2027
  const relationships = [];
@@ -2025,7 +2048,6 @@ var MemoryService = class {
2025
2048
  throw new Error("Provide either memory_id or text, not both");
2026
2049
  const limit = input.limit ?? 10;
2027
2050
  const minSimilarity = input.min_similarity ?? 0.7;
2028
- const deletedFilter = buildDeletedFilter(this.collection, input.deleted_filter || "exclude");
2029
2051
  const ghostFilters = [];
2030
2052
  if (input.ghost_context) {
2031
2053
  ghostFilters.push(buildTrustFilter(this.collection, input.ghost_context.accessor_trust_level));
@@ -2033,29 +2055,35 @@ var MemoryService = class {
2033
2055
  if (!input.ghost_context?.include_ghost_content) {
2034
2056
  ghostFilters.push(this.collection.filter.byProperty("content_type").notEqual("ghost"));
2035
2057
  }
2036
- const combinedFilter = combineFiltersWithAnd([deletedFilter, ...ghostFilters].filter((f) => f !== null));
2037
- let results;
2058
+ let memoryObj = null;
2038
2059
  if (input.memory_id) {
2039
- const memory = await this.collection.query.fetchObjectById(input.memory_id, {
2060
+ memoryObj = await this.collection.query.fetchObjectById(input.memory_id, {
2040
2061
  returnProperties: ["user_id", "doc_type", "content"]
2041
2062
  });
2042
- if (!memory)
2063
+ if (!memoryObj)
2043
2064
  throw new Error(`Memory not found: ${input.memory_id}`);
2044
- if (memory.properties.user_id !== this.userId)
2065
+ if (memoryObj.properties.user_id !== this.userId)
2045
2066
  throw new Error("Unauthorized");
2046
- if (memory.properties.doc_type !== "memory")
2067
+ if (memoryObj.properties.doc_type !== "memory")
2047
2068
  throw new Error("Can only find similar for memory documents");
2048
- const opts = { limit: limit + 1, distance: 1 - minSimilarity, returnMetadata: ["distance"] };
2049
- if (combinedFilter)
2050
- opts.filters = combinedFilter;
2051
- results = await this.collection.query.nearObject(input.memory_id, opts);
2052
- results.objects = results.objects.filter((o) => o.uuid !== input.memory_id);
2053
- } else {
2054
- const opts = { limit, distance: 1 - minSimilarity, returnMetadata: ["distance"] };
2055
- if (combinedFilter)
2056
- opts.filters = combinedFilter;
2057
- results = await this.collection.query.nearText(input.text, opts);
2058
2069
  }
2070
+ const results = await this.retryWithoutDeletedFilter(async (useDeletedFilter) => {
2071
+ const deletedFilter = useDeletedFilter ? buildDeletedFilter(this.collection, input.deleted_filter || "exclude") : null;
2072
+ const combinedFilter = combineFiltersWithAnd([deletedFilter, ...ghostFilters].filter((f) => f !== null));
2073
+ if (input.memory_id) {
2074
+ const opts = { limit: limit + 1, distance: 1 - minSimilarity, returnMetadata: ["distance"] };
2075
+ if (combinedFilter)
2076
+ opts.filters = combinedFilter;
2077
+ const res = await this.collection.query.nearObject(input.memory_id, opts);
2078
+ res.objects = res.objects.filter((o) => o.uuid !== input.memory_id);
2079
+ return res;
2080
+ } else {
2081
+ const opts = { limit, distance: 1 - minSimilarity, returnMetadata: ["distance"] };
2082
+ if (combinedFilter)
2083
+ opts.filters = combinedFilter;
2084
+ return this.collection.query.nearText(input.text, opts);
2085
+ }
2086
+ });
2059
2087
  if (!input.include_relationships) {
2060
2088
  results.objects = results.objects.filter((o) => o.properties.doc_type === "memory");
2061
2089
  }
@@ -2072,7 +2100,6 @@ var MemoryService = class {
2072
2100
  throw new Error("Query cannot be empty");
2073
2101
  const limit = input.limit ?? 5;
2074
2102
  const minRelevance = input.min_relevance ?? 0.6;
2075
- const deletedFilter = buildDeletedFilter(this.collection, input.deleted_filter || "exclude");
2076
2103
  const searchFilters = buildCombinedSearchFilters(this.collection, input.filters);
2077
2104
  const ghostFilters = [];
2078
2105
  if (input.ghost_context) {
@@ -2081,11 +2108,14 @@ var MemoryService = class {
2081
2108
  if (!input.ghost_context?.include_ghost_content) {
2082
2109
  ghostFilters.push(this.collection.filter.byProperty("content_type").notEqual("ghost"));
2083
2110
  }
2084
- const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters, ...ghostFilters].filter((f) => f !== null));
2085
- const opts = { limit, distance: 1 - minRelevance, returnMetadata: ["distance"] };
2086
- if (combinedFilters)
2087
- opts.filters = combinedFilters;
2088
- const results = await this.collection.query.nearText(input.query, opts);
2111
+ const results = await this.retryWithoutDeletedFilter(async (useDeletedFilter) => {
2112
+ const deletedFilter = useDeletedFilter ? buildDeletedFilter(this.collection, input.deleted_filter || "exclude") : null;
2113
+ const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters, ...ghostFilters].filter((f) => f !== null));
2114
+ const opts = { limit, distance: 1 - minRelevance, returnMetadata: ["distance"] };
2115
+ if (combinedFilters)
2116
+ opts.filters = combinedFilters;
2117
+ return this.collection.query.nearText(input.query, opts);
2118
+ });
2089
2119
  const items = results.objects.map((obj) => ({
2090
2120
  id: obj.uuid,
2091
2121
  ...obj.properties,
@@ -3194,7 +3224,6 @@ var SpaceService = class {
3194
3224
  // ── Private: Build Base Filters ─────────────────────────────────────
3195
3225
  buildBaseFilters(collection, input) {
3196
3226
  const filterList = [];
3197
- filterList.push(collection.filter.byProperty("deleted_at").isNull(true));
3198
3227
  filterList.push(collection.filter.byProperty("doc_type").equal("memory"));
3199
3228
  const moderationFilter = buildModerationFilter(collection, input.moderation_filter);
3200
3229
  if (moderationFilter)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/remember-mcp",
3
- "version": "3.14.1",
3
+ "version": "3.14.2",
4
4
  "description": "Multi-tenant memory system MCP server with vector search and relationships",
5
5
  "main": "dist/server.js",
6
6
  "type": "module",