@anuma/sdk 3.8.2 → 3.8.4

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.
@@ -108,7 +108,7 @@ import {
108
108
  upsertMessageOp,
109
109
  useEncryption,
110
110
  vaultMemoryToStored
111
- } from "./chunk-IFZZQPRO.mjs";
111
+ } from "./chunk-42Y42CAZ.mjs";
112
112
  import {
113
113
  PII_PATTERNS,
114
114
  PiiRedactor,
@@ -5930,6 +5930,162 @@ var WalletPoller = class {
5930
5930
  // src/lib/memory/autoExtract.ts
5931
5931
  import { Q as Q3 } from "@nozbe/watermelondb";
5932
5932
 
5933
+ // src/lib/memory/entitySalience.ts
5934
+ var GENERIC_ENTITY_NAMES = /* @__PURE__ */ new Set([
5935
+ // Relative and absolute time
5936
+ "today",
5937
+ "tomorrow",
5938
+ "yesterday",
5939
+ "tonight",
5940
+ "morning",
5941
+ "afternoon",
5942
+ "evening",
5943
+ "night",
5944
+ "day",
5945
+ "date",
5946
+ "time",
5947
+ "week",
5948
+ "weekend",
5949
+ "weekday",
5950
+ "month",
5951
+ "year",
5952
+ "monday",
5953
+ "tuesday",
5954
+ "wednesday",
5955
+ "thursday",
5956
+ "friday",
5957
+ "saturday",
5958
+ "sunday",
5959
+ "january",
5960
+ "february",
5961
+ "march",
5962
+ "april",
5963
+ "may",
5964
+ "june",
5965
+ "july",
5966
+ "august",
5967
+ "september",
5968
+ "october",
5969
+ "november",
5970
+ "december",
5971
+ // Generic containers and venues — the named ones ("Blue Bottle on Valencia",
5972
+ // "Stanford") are unaffected because they are not bare tokens.
5973
+ "home",
5974
+ "house",
5975
+ "apartment",
5976
+ "room",
5977
+ "office",
5978
+ "work",
5979
+ "workplace",
5980
+ "school",
5981
+ "gym",
5982
+ "store",
5983
+ "shop",
5984
+ "hospital",
5985
+ "airport",
5986
+ "hotel",
5987
+ "city",
5988
+ "town",
5989
+ "country",
5990
+ "place",
5991
+ // Generic calendar entries — "Chicago Marathon" survives, "meeting" doesn't.
5992
+ "meeting",
5993
+ "call",
5994
+ "appointment",
5995
+ "reminder",
5996
+ "event",
5997
+ "birthday",
5998
+ "breakfast",
5999
+ "lunch",
6000
+ "dinner",
6001
+ "brunch",
6002
+ "vacation",
6003
+ "holiday",
6004
+ "trip",
6005
+ // Plurals are listed explicitly rather than stemmed: naive `s`-stripping
6006
+ // would fold real titles into generics ("The Times" → "time"). Only plurals
6007
+ // that are junk as topics in their own right belong here — note the absence
6008
+ // of "times", "places", and anything else that reads as a name.
6009
+ "days",
6010
+ "weeks",
6011
+ "weekends",
6012
+ "months",
6013
+ "years",
6014
+ "rooms",
6015
+ "offices",
6016
+ "houses",
6017
+ "apartments",
6018
+ "stores",
6019
+ "shops",
6020
+ "hotels",
6021
+ "meetings",
6022
+ "calls",
6023
+ "appointments",
6024
+ "reminders",
6025
+ "events",
6026
+ "birthdays",
6027
+ "trips",
6028
+ "vacations",
6029
+ "holidays",
6030
+ // Meta / filler the models occasionally echo back as an entity
6031
+ "user",
6032
+ "assistant",
6033
+ "memory",
6034
+ "memories",
6035
+ "note",
6036
+ "notes",
6037
+ "thing",
6038
+ "things",
6039
+ "stuff",
6040
+ "something",
6041
+ "someone",
6042
+ "anything",
6043
+ "everything",
6044
+ "none",
6045
+ "other",
6046
+ "misc",
6047
+ "general",
6048
+ "unknown"
6049
+ ]);
6050
+ function isGenericEntityName(name) {
6051
+ const tokens = name.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((token) => token.length > 0);
6052
+ if (tokens.length === 0) return true;
6053
+ const distinctive = tokens.filter(
6054
+ (token) => !GENERIC_ENTITY_NAMES.has(token) && !ARTICLES.has(token) && !WEAK_MODIFIERS.has(token)
6055
+ );
6056
+ if (distinctive.length > 0) return false;
6057
+ const generic = tokens.filter((token) => GENERIC_ENTITY_NAMES.has(token));
6058
+ if (generic.length === 0) return true;
6059
+ const titleShaped = generic.length === 1 && tokens.some((token) => ARTICLES.has(token)) && !tokens.some((token) => WEAK_MODIFIERS.has(token));
6060
+ return !titleShaped;
6061
+ }
6062
+ var ARTICLES = /* @__PURE__ */ new Set(["the", "a", "an"]);
6063
+ var WEAK_MODIFIERS = /* @__PURE__ */ new Set([
6064
+ "my",
6065
+ "our",
6066
+ "their",
6067
+ "his",
6068
+ "her",
6069
+ "its",
6070
+ "this",
6071
+ "that",
6072
+ "next",
6073
+ "last",
6074
+ "upcoming",
6075
+ "every",
6076
+ "at",
6077
+ "in",
6078
+ "on",
6079
+ "of",
6080
+ "for",
6081
+ "with",
6082
+ "from",
6083
+ "to",
6084
+ "by",
6085
+ "and",
6086
+ "or"
6087
+ ]);
6088
+
5933
6089
  // src/lib/memory/injectionClassifier.ts
5934
6090
  var DEFAULT_MODEL = "inclusionai/ling-2.6-flash";
5935
6091
  var DEFAULT_ATTEMPTS = 2;
@@ -6858,13 +7014,13 @@ function parseEntities(raw) {
6858
7014
  for (const e of raw) {
6859
7015
  if (typeof e === "string") {
6860
7016
  const name2 = e.trim();
6861
- if (name2.length > 0) out.push({ name: name2 });
7017
+ if (name2.length > 0 && !isGenericEntityName(name2)) out.push({ name: name2 });
6862
7018
  continue;
6863
7019
  }
6864
7020
  if (typeof e !== "object" || e === null) continue;
6865
7021
  const obj = e;
6866
7022
  const name = typeof obj.name === "string" ? obj.name.trim() : "";
6867
- if (name.length === 0) continue;
7023
+ if (name.length === 0 || isGenericEntityName(name)) continue;
6868
7024
  const kind = typeof obj.kind === "string" && ENTITY_KINDS.includes(obj.kind) ? obj.kind : void 0;
6869
7025
  out.push(kind !== void 0 ? { name, kind } : { name });
6870
7026
  }
@@ -8167,7 +8323,11 @@ var SYSTEM_PROMPT4 = `You assign topics to saved memories for a personal memory
8167
8323
 
8168
8324
  Each memory is a short statement about the user. For each memory, list the NAMED entities it mentions \u2014 these become the memory's topics, used to connect related memories in a knowledge graph.
8169
8325
 
8170
- Include only NAMED entities, skip generic/common nouns. ${ENTITY_KIND_GUIDELINES}
8326
+ Include only NAMED entities, skip generic/common nouns. A topic must identify a specific thing the user could recognize by name; if it would be equally true of thousands of unrelated memories, leave it out:
8327
+ - SKIP bare generic nouns even when the memory capitalizes them or a calendar entry is titled that way \u2014 "Home", "Work", "Meeting", "Lunch", "Birthday", "Appointment", "Trip", "Today", "Friday", "March" are NOT topics.
8328
+ - KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
8329
+ - Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
8330
+ ${ENTITY_KIND_GUIDELINES}
8171
8331
 
8172
8332
  Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
8173
8333
  - exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
@@ -8179,7 +8339,7 @@ async function extractEntitiesForMemories(memories, options) {
8179
8339
  const redactor = resolvePiiRedactor(options.piiRedaction);
8180
8340
  const vocabulary = (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES).map((n) => redactor ? redactor.redactText(n).text : n);
8181
8341
  const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
8182
- When a memory refers to one of these, reuse the EXACT existing name (same spelling and casing) instead of a variant.
8342
+ When a memory refers to one of these, reuse the EXACT existing name (same spelling, casing, spacing and punctuation) instead of a variant \u2014 if "Foo.ai" is listed, never emit "Foo ai" or "Foo AI", and if "Jane Roe" is listed, emit that rather than a bare "Jane".
8183
8343
 
8184
8344
  ` : "";
8185
8345
  for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-IFZZQPRO.mjs";
3
+ } from "./chunk-42Y42CAZ.mjs";
4
4
  import "./chunk-BOY27A2C.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
@@ -1929,7 +1929,7 @@ function entityToStored(e) {
1929
1929
  updatedAt: e.updatedAt
1930
1930
  };
1931
1931
  }
1932
- async function upsertEntitiesOp(ctx, entities) {
1932
+ async function upsertEntitiesInWrite(ctx, entities) {
1933
1933
  const kindByName = /* @__PURE__ */ new Map();
1934
1934
  for (const e of entities) {
1935
1935
  const name = normalizeEntityName(e.name);
@@ -1943,60 +1943,62 @@ async function upsertEntitiesOp(ctx, entities) {
1943
1943
  }
1944
1944
  const unique = Array.from(kindByName.keys());
1945
1945
  const out = /* @__PURE__ */ new Map();
1946
- if (unique.length === 0) return out;
1947
- return await ctx.database.write(async () => {
1948
- const existing = await ctx.entityCollection.query(Q2.where("canonical_name", Q2.oneOf(unique))).fetch();
1949
- const existingNames = new Set(existing.map((e) => e.canonicalName));
1950
- const updates = existing.filter((e) => {
1951
- const incoming = kindByName.get(e.canonicalName);
1952
- return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
1953
- });
1954
- const missing = unique.filter((n) => !existingNames.has(n));
1955
- const created = missing.map(
1956
- (name) => ctx.entityCollection.prepareCreate((record) => {
1957
- record._setRaw("canonical_name", name);
1958
- const kind = kindByName.get(name);
1959
- if (kind !== void 0) record._setRaw("kind", kind);
1960
- })
1961
- );
1962
- const updated = updates.map(
1963
- (e) => e.prepareUpdate((record) => {
1964
- record._setRaw("kind", kindByName.get(e.canonicalName));
1965
- })
1966
- );
1967
- if (created.length > 0 || updated.length > 0) {
1968
- await ctx.database.batch(...created, ...updated);
1969
- }
1970
- for (const e of existing) out.set(e.canonicalName, entityToStored(e));
1971
- for (const record of created) out.set(record.canonicalName, entityToStored(record));
1972
- return out;
1946
+ if (unique.length === 0) return { entities: out, operations: [] };
1947
+ const existing = await ctx.entityCollection.query(Q2.where("canonical_name", Q2.oneOf(unique))).fetch();
1948
+ const existingNames = new Set(existing.map((e) => e.canonicalName));
1949
+ const updates = existing.filter((e) => {
1950
+ const incoming = kindByName.get(e.canonicalName);
1951
+ return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
1973
1952
  });
1953
+ const missing = unique.filter((n) => !existingNames.has(n));
1954
+ const created = missing.map(
1955
+ (name) => ctx.entityCollection.prepareCreate((record) => {
1956
+ record._setRaw("canonical_name", name);
1957
+ const kind = kindByName.get(name);
1958
+ if (kind !== void 0) record._setRaw("kind", kind);
1959
+ })
1960
+ );
1961
+ const updated = updates.map(
1962
+ (e) => e.prepareUpdate((record) => {
1963
+ record._setRaw("kind", kindByName.get(e.canonicalName));
1964
+ })
1965
+ );
1966
+ for (const e of existing) out.set(e.canonicalName, entityToStored(e));
1967
+ for (const record of created) out.set(record.canonicalName, entityToStored(record));
1968
+ return { entities: out, operations: [...created, ...updated] };
1974
1969
  }
1975
1970
  async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
1976
1971
  if (entityInputs.length === 0) return [];
1977
1972
  const normalized = entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
1978
- const byName = await upsertEntitiesOp(ctx, normalized);
1979
- const entities = Array.from(byName.values());
1980
- if (entities.length === 0) return [];
1981
1973
  const userId = ctx.userId;
1982
1974
  let skipped = false;
1975
+ let entities = [];
1983
1976
  await ctx.database.write(async () => {
1977
+ const { entities: byName, operations: entityOps } = await upsertEntitiesInWrite(
1978
+ ctx,
1979
+ normalized
1980
+ );
1981
+ entities = Array.from(byName.values());
1984
1982
  if (options?.unlessTopicsUserManaged && await autoLinkBlocked(ctx, memoryId)) {
1983
+ if (entityOps.length > 0) {
1984
+ await ctx.database.batch(...entityOps);
1985
+ }
1985
1986
  skipped = true;
1986
1987
  return;
1987
1988
  }
1989
+ if (entities.length === 0) return;
1988
1990
  const existingLinks = await ctx.memoryEntityCollection.query(Q2.where("memory_id", memoryId)).fetch();
1989
1991
  const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
1990
1992
  const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
1991
- if (toCreate.length === 0) return;
1992
- const prepared = toCreate.map(
1993
+ if (entityOps.length === 0 && toCreate.length === 0) return;
1994
+ const linkOps = toCreate.map(
1993
1995
  (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
1994
1996
  record._setRaw("memory_id", memoryId);
1995
1997
  record._setRaw("entity_id", e.uniqueId);
1996
1998
  if (userId !== void 0) record._setRaw("user_id", userId);
1997
1999
  })
1998
2000
  );
1999
- await ctx.database.batch(...prepared);
2001
+ await ctx.database.batch(...entityOps, ...linkOps);
2000
2002
  });
2001
2003
  return skipped ? [] : entities;
2002
2004
  }
@@ -2011,22 +2013,28 @@ async function autoLinkBlocked(ctx, memoryId) {
2011
2013
  }
2012
2014
  async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
2013
2015
  const normalized = entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
2014
- const byName = await upsertEntitiesOp(ctx, normalized);
2015
- const entities = Array.from(byName.values());
2016
2016
  const userId = ctx.userId;
2017
2017
  let skipped = false;
2018
+ let entities = [];
2018
2019
  await ctx.database.write(async () => {
2019
2020
  if (await autoLinkBlocked(ctx, memoryId)) {
2020
2021
  skipped = true;
2021
2022
  return;
2022
2023
  }
2024
+ const { entities: byName, operations: entityOps } = await upsertEntitiesInWrite(
2025
+ ctx,
2026
+ normalized
2027
+ );
2028
+ entities = Array.from(byName.values());
2023
2029
  const existingLinks = await ctx.memoryEntityCollection.query(Q2.where("memory_id", memoryId)).fetch();
2024
2030
  const keep = new Set(entities.map((e) => e.uniqueId));
2025
2031
  const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
2026
2032
  const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
2027
2033
  const toDestroy = existingLinks.filter((l) => !keep.has(String(l.entityId)));
2028
- if (toCreate.length === 0 && toDestroy.length === 0) return;
2034
+ if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0) return;
2035
+ const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
2029
2036
  await ctx.database.batch(
2037
+ ...entityOps,
2030
2038
  ...toCreate.map(
2031
2039
  (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
2032
2040
  record._setRaw("memory_id", memoryId);
@@ -2034,11 +2042,23 @@ async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
2034
2042
  if (userId !== void 0) record._setRaw("user_id", userId);
2035
2043
  })
2036
2044
  ),
2037
- ...toDestroy.map((l) => l.prepareDestroyPermanently())
2045
+ ...toDestroy.map((l) => l.prepareDestroyPermanently()),
2046
+ ...orphans.map((e) => e.prepareDestroyPermanently())
2038
2047
  );
2039
2048
  });
2040
2049
  return skipped ? null : entities;
2041
2050
  }
2051
+ async function findOrphanedEntities(ctx, memoryId, toDestroy) {
2052
+ const candidateIds = [...new Set(toDestroy.map((l) => String(l.entityId)))];
2053
+ if (candidateIds.length === 0) return [];
2054
+ const links = await ctx.memoryEntityCollection.query(Q2.where("entity_id", Q2.oneOf(candidateIds))).fetch();
2055
+ const stillLinked = new Set(
2056
+ links.filter((l) => String(l.memoryId) !== memoryId).map((l) => String(l.entityId))
2057
+ );
2058
+ const orphanIds = candidateIds.filter((id) => !stillLinked.has(id));
2059
+ if (orphanIds.length === 0) return [];
2060
+ return await ctx.entityCollection.query(Q2.where("id", Q2.oneOf(orphanIds))).fetch();
2061
+ }
2042
2062
  async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
2043
2063
  if (memoryIds.length === 0) return;
2044
2064
  const links = await ctx.memoryEntityCollection.query(Q2.where("memory_id", Q2.oneOf(Array.from(memoryIds)))).fetch();
@@ -2738,7 +2758,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
2738
2758
  (record) => vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
2739
2759
  );
2740
2760
  }
2741
- var TOPICS_EXTRACTION_VERSION = 2;
2761
+ var TOPICS_EXTRACTION_VERSION = 3;
2742
2762
  async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
2743
2763
  const entityCtx = ctx.entityCtx;
2744
2764
  if (!entityCtx) {
@@ -5641,7 +5661,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
5641
5661
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
5642
5662
  );
5643
5663
  }
5644
- const { recall: recall2 } = await import("./recall-JUERXQA7.mjs");
5664
+ const { recall: recall2 } = await import("./recall-BCEH7U2Z.mjs");
5645
5665
  const result = await recall2(
5646
5666
  query,
5647
5667
  { vaultCtx, embeddingOptions, vaultCache: cache },