@anuma/sdk 3.12.2 → 3.13.1

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.
@@ -15992,6 +15992,31 @@ var ENTITY_KINDS = [
15992
15992
  function normalizeEntityName(name) {
15993
15993
  return name.trim().toLowerCase();
15994
15994
  }
15995
+ function serializeTopics(topics) {
15996
+ return JSON.stringify(topics);
15997
+ }
15998
+ function parseTopics(value) {
15999
+ if (typeof value !== "string" || value.length === 0) return null;
16000
+ let parsed;
16001
+ try {
16002
+ parsed = JSON.parse(value);
16003
+ } catch {
16004
+ return null;
16005
+ }
16006
+ if (!Array.isArray(parsed)) return null;
16007
+ const out = [];
16008
+ for (const raw of parsed) {
16009
+ if (typeof raw !== "object" || raw === null) continue;
16010
+ const { name, kind, source } = raw;
16011
+ if (typeof name !== "string" || name.trim().length === 0) continue;
16012
+ out.push({
16013
+ name,
16014
+ ...typeof kind === "string" && kind.length > 0 ? { kind } : {},
16015
+ source: source === "user" ? "user" : "auto"
16016
+ });
16017
+ }
16018
+ return out;
16019
+ }
15995
16020
 
15996
16021
  // src/lib/db/entities/operations.ts
15997
16022
  function entityToStored(e) {
@@ -16041,9 +16066,62 @@ async function upsertEntitiesInWrite(ctx, entities) {
16041
16066
  for (const record of created) out.set(record.canonicalName, entityToStored(record));
16042
16067
  return { entities: out, operations: [...created, ...updated] };
16043
16068
  }
16069
+ async function findVaultRowInWrite(ctx, memoryId) {
16070
+ try {
16071
+ const rows = await ctx.database.get("memory_vault").query(import_watermelondb2.Q.where("id", memoryId)).fetch();
16072
+ return rows[0] ?? null;
16073
+ } catch {
16074
+ return null;
16075
+ }
16076
+ }
16077
+ function prepareTopicsUpdate(row, topics, now) {
16078
+ const originalUpdatedAt = row.updatedAt.getTime();
16079
+ return row.prepareUpdate((r) => {
16080
+ r._setRaw("topics", serializeTopics(topics));
16081
+ r._setRaw("topics_updated_at", now);
16082
+ r._setRaw("updated_at", originalUpdatedAt);
16083
+ });
16084
+ }
16085
+ function displayNamesOf(entities) {
16086
+ const out = /* @__PURE__ */ new Map();
16087
+ for (const e of entities) {
16088
+ const name = e.name.trim();
16089
+ const normalized = normalizeEntityName(name);
16090
+ if (normalized.length === 0 || out.has(normalized)) continue;
16091
+ out.set(normalized, name);
16092
+ }
16093
+ return out;
16094
+ }
16095
+ function topicsEqual(stored, computed) {
16096
+ if (stored === null || stored.length !== computed.length) return false;
16097
+ const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
16098
+ const storedKeys = stored.map(key).sort();
16099
+ const computedKeys = computed.map(key).sort();
16100
+ return storedKeys.every((k, i) => k === computedKeys[i]);
16101
+ }
16102
+ function resolveTopicsWrite(row, linked, displayNames, source) {
16103
+ if (row === null || source === null) return null;
16104
+ const topics = topicsForEntities(linked, displayNames, source);
16105
+ if (topicsEqual(parseTopics(row.topics), topics)) return null;
16106
+ return { row, topics };
16107
+ }
16108
+ function topicsForEntities(entities, displayNames, source) {
16109
+ return entities.map((e) => {
16110
+ const name = displayNames.get(e.canonicalName) ?? e.canonicalName;
16111
+ return { name, ...e.kind ? { kind: e.kind } : {}, source };
16112
+ });
16113
+ }
16114
+ function toEntityObjects(entityInputs) {
16115
+ return entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
16116
+ }
16117
+ async function prepareMemoryTopicsUpdate(ctx, memoryId, linked, inputs, source) {
16118
+ const row = await findVaultRowInWrite(ctx, memoryId);
16119
+ const write = resolveTopicsWrite(row, linked, displayNamesOf(toEntityObjects(inputs)), source);
16120
+ return write === null ? null : prepareTopicsUpdate(write.row, write.topics, Date.now());
16121
+ }
16044
16122
  async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
16045
16123
  if (entityInputs.length === 0) return [];
16046
- const normalized = entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
16124
+ const normalized = toEntityObjects(entityInputs);
16047
16125
  const userId = ctx.userId;
16048
16126
  let skipped = false;
16049
16127
  let entities = [];
@@ -16053,7 +16131,8 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
16053
16131
  normalized
16054
16132
  );
16055
16133
  entities = Array.from(byName.values());
16056
- if (options?.unlessTopicsUserManaged && await autoLinkBlocked(ctx, memoryId)) {
16134
+ const vaultRow = await findVaultRowInWrite(ctx, memoryId);
16135
+ if (options?.unlessTopicsUserManaged && autoLinkBlocked(vaultRow)) {
16057
16136
  if (entityOps.length > 0) {
16058
16137
  await ctx.database.batch(...entityOps);
16059
16138
  }
@@ -16064,7 +16143,18 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
16064
16143
  const existingLinks = await ctx.memoryEntityCollection.query(import_watermelondb2.Q.where("memory_id", memoryId)).fetch();
16065
16144
  const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
16066
16145
  const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
16067
- if (entityOps.length === 0 && toCreate.length === 0) return;
16146
+ const keptIds = entities.map((e) => e.uniqueId);
16147
+ const carriedOver = await resolveEntitiesByIds(
16148
+ ctx,
16149
+ [...existingEntityIds].filter((id) => !keptIds.includes(id))
16150
+ );
16151
+ const topicsWrite = resolveTopicsWrite(
16152
+ vaultRow,
16153
+ [...carriedOver, ...entities],
16154
+ displayNamesOf(normalized),
16155
+ options?.topicsSource ?? "auto"
16156
+ );
16157
+ if (entityOps.length === 0 && toCreate.length === 0 && topicsWrite === null) return;
16068
16158
  const linkOps = toCreate.map(
16069
16159
  (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
16070
16160
  record._setRaw("memory_id", memoryId);
@@ -16072,26 +16162,42 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
16072
16162
  if (userId !== void 0) record._setRaw("user_id", userId);
16073
16163
  })
16074
16164
  );
16075
- await ctx.database.batch(...entityOps, ...linkOps);
16165
+ await ctx.database.batch(
16166
+ ...entityOps,
16167
+ ...linkOps,
16168
+ ...topicsWrite ? [prepareTopicsUpdate(topicsWrite.row, topicsWrite.topics, Date.now())] : []
16169
+ );
16076
16170
  });
16077
16171
  return skipped ? [] : entities;
16078
16172
  }
16079
- async function autoLinkBlocked(ctx, memoryId) {
16080
- try {
16081
- const rows = await ctx.database.get("memory_vault").query(import_watermelondb2.Q.where("id", memoryId)).fetch();
16082
- const row = rows[0];
16083
- return !row || !!row.isDeleted || !!row.topicsUserManaged;
16084
- } catch {
16085
- return true;
16086
- }
16173
+ async function resolveEntitiesByIds(ctx, entityIds) {
16174
+ if (entityIds.length === 0) return [];
16175
+ const rows = await ctx.entityCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf(Array.from(entityIds)))).fetch();
16176
+ return rows.map(entityToStored);
16177
+ }
16178
+ function autoLinkBlocked(row) {
16179
+ return !row || !!row.isDeleted || !!row.topicsUserManaged;
16087
16180
  }
16088
16181
  async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
16089
- const normalized = entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
16182
+ return replaceMemoryEntities(ctx, memoryId, entityInputs, {
16183
+ guarded: true,
16184
+ topicsSource: "auto"
16185
+ });
16186
+ }
16187
+ async function relinkMemoryEntitiesFromTopicsOp(ctx, memoryId, topics) {
16188
+ return replaceMemoryEntities(ctx, memoryId, topics, {
16189
+ guarded: false,
16190
+ topicsSource: null
16191
+ });
16192
+ }
16193
+ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
16194
+ const normalized = toEntityObjects(entityInputs);
16090
16195
  const userId = ctx.userId;
16091
16196
  let skipped = false;
16092
16197
  let entities = [];
16093
16198
  await ctx.database.write(async () => {
16094
- if (await autoLinkBlocked(ctx, memoryId)) {
16199
+ const vaultRow = await findVaultRowInWrite(ctx, memoryId);
16200
+ if (options.guarded && autoLinkBlocked(vaultRow)) {
16095
16201
  skipped = true;
16096
16202
  return;
16097
16203
  }
@@ -16105,7 +16211,15 @@ async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
16105
16211
  const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
16106
16212
  const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
16107
16213
  const toDestroy = existingLinks.filter((l) => !keep.has(String(l.entityId)));
16108
- if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0) return;
16214
+ const topicsWrite = resolveTopicsWrite(
16215
+ vaultRow,
16216
+ entities,
16217
+ displayNamesOf(normalized),
16218
+ options.topicsSource
16219
+ );
16220
+ if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
16221
+ return;
16222
+ }
16109
16223
  const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
16110
16224
  await ctx.database.batch(
16111
16225
  ...entityOps,
@@ -16117,7 +16231,8 @@ async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
16117
16231
  })
16118
16232
  ),
16119
16233
  ...toDestroy.map((l) => l.prepareDestroyPermanently()),
16120
- ...orphans.map((e) => e.prepareDestroyPermanently())
16234
+ ...orphans.map((e) => e.prepareDestroyPermanently()),
16235
+ ...topicsWrite ? [prepareTopicsUpdate(topicsWrite.row, topicsWrite.topics, Date.now())] : []
16121
16236
  );
16122
16237
  });
16123
16238
  return skipped ? null : entities;
@@ -16305,6 +16420,8 @@ function vaultMemoryToStoredRaw(memory) {
16305
16420
  eventTimeEnd: memory.eventTimeEnd ?? null,
16306
16421
  eventTimeKind: memory.eventTimeKind ?? null,
16307
16422
  topicsUserManaged: memory.topicsUserManaged ?? false,
16423
+ topics: parseTopics(memory.topics),
16424
+ topicsUpdatedAt: memory.topicsUpdatedAt ?? null,
16308
16425
  topicsExtractedAt: memory.topicsExtractedAt ?? null,
16309
16426
  topicsExtractedVersion: memory.topicsExtractedVersion ?? null,
16310
16427
  supersededBy: memory.supersededBy ?? null,
@@ -16581,6 +16698,8 @@ function vaultMemoryRawToStoredRaw(raw) {
16581
16698
  eventTimeKind: raw.event_time_kind ?? null,
16582
16699
  // SQLite stores booleans as 0/1, LokiJS as true/false — coerce both.
16583
16700
  topicsUserManaged: raw.topics_user_managed === true || raw.topics_user_managed === 1,
16701
+ topics: parseTopics(raw.topics),
16702
+ topicsUpdatedAt: raw.topics_updated_at ?? null,
16584
16703
  topicsExtractedAt: raw.topics_extracted_at ?? null,
16585
16704
  topicsExtractedVersion: raw.topics_extracted_version ?? null,
16586
16705
  supersededBy: raw.superseded_by ?? null,
@@ -16928,56 +17047,111 @@ async function getUnfiledVaultMemoriesOp(ctx) {
16928
17047
  );
16929
17048
  }
16930
17049
  var TOPICS_EXTRACTION_VERSION = 3;
17050
+ async function linkedEntityNamesByMemory(entityCtx, memoryIds) {
17051
+ const CHUNK = 500;
17052
+ const entityIdByMemory = /* @__PURE__ */ new Map();
17053
+ const allEntityIds = /* @__PURE__ */ new Set();
17054
+ for (let i = 0; i < memoryIds.length; i += CHUNK) {
17055
+ const links = await entityCtx.memoryEntityCollection.query(import_watermelondb3.Q.where("memory_id", import_watermelondb3.Q.oneOf(memoryIds.slice(i, i + CHUNK)))).unsafeFetchRaw();
17056
+ for (const link of links) {
17057
+ const memoryId = String(link.memory_id);
17058
+ const entityId = String(link.entity_id);
17059
+ allEntityIds.add(entityId);
17060
+ let bucket = entityIdByMemory.get(memoryId);
17061
+ if (!bucket) {
17062
+ bucket = /* @__PURE__ */ new Set();
17063
+ entityIdByMemory.set(memoryId, bucket);
17064
+ }
17065
+ bucket.add(entityId);
17066
+ }
17067
+ }
17068
+ const entityIds = Array.from(allEntityIds);
17069
+ const nameById = /* @__PURE__ */ new Map();
17070
+ for (let i = 0; i < entityIds.length; i += CHUNK) {
17071
+ const entities = await entityCtx.entityCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(entityIds.slice(i, i + CHUNK)))).unsafeFetchRaw();
17072
+ for (const e of entities) {
17073
+ if (typeof e.canonical_name === "string") nameById.set(String(e.id), e.canonical_name);
17074
+ }
17075
+ }
17076
+ const out = /* @__PURE__ */ new Map();
17077
+ for (const [memoryId, ids] of entityIdByMemory) {
17078
+ const names = /* @__PURE__ */ new Set();
17079
+ for (const id of ids) {
17080
+ const name = nameById.get(id);
17081
+ if (name !== void 0) names.add(name);
17082
+ }
17083
+ if (names.size > 0) out.set(memoryId, names);
17084
+ }
17085
+ return out;
17086
+ }
17087
+ function linksDivergeFromTopics(topics, linked) {
17088
+ const wanted = new Set(
17089
+ topics.map((t) => normalizeEntityName(t.name)).filter((n) => n.length > 0)
17090
+ );
17091
+ if (wanted.size !== linked.size) return true;
17092
+ for (const name of wanted) if (!linked.has(name)) return true;
17093
+ return false;
17094
+ }
16931
17095
  async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
16932
17096
  const entityCtx = ctx.entityCtx;
16933
17097
  if (!entityCtx) {
16934
17098
  throw new Error("getMemoriesNeedingTopicExtractionOp requires ctx.entityCtx");
16935
17099
  }
16936
- const conditions = [
16937
- // Boolean optional column: null (legacy) and false both mean auto-managed.
16938
- // Q.notEq(true) is a NULL trap on SQLite (NULL <> TRUE is NULL) — enumerate.
16939
- import_watermelondb3.Q.or(import_watermelondb3.Q.where("topics_user_managed", null), import_watermelondb3.Q.where("topics_user_managed", false)),
16940
- ...baseVaultConditions(ctx),
16941
- import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)
16942
- ];
17100
+ const conditions = [...baseVaultConditions(ctx), import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)];
16943
17101
  const rows = await ctx.vaultMemoryCollection.query(...conditions).unsafeFetchRaw();
16944
- const stampedPending = [];
16945
- const unstamped = [];
17102
+ const linkedNames = await linkedEntityNamesByMemory(
17103
+ entityCtx,
17104
+ rows.map((r) => r.id)
17105
+ );
17106
+ const pendingRaw = [];
17107
+ const stampedPendingRaw = [];
17108
+ const linkedUnstampedAll = [];
17109
+ const topicsToRelinkAll = [];
17110
+ const topicsBackfillAll = [];
16946
17111
  for (const raw of rows) {
17112
+ const id = raw.id;
17113
+ const topics = parseTopics(raw.topics);
17114
+ const linked = linkedNames.get(id);
17115
+ if (topics !== null && topics.length > 0 && linksDivergeFromTopics(topics, linked ?? /* @__PURE__ */ new Set())) {
17116
+ topicsToRelinkAll.push(id);
17117
+ continue;
17118
+ }
17119
+ if (raw.topics_user_managed) {
17120
+ if (topics === null && linked !== void 0) topicsBackfillAll.push(id);
17121
+ continue;
17122
+ }
16947
17123
  const stamp = raw.topics_extracted_at ?? null;
17124
+ let isPending = false;
16948
17125
  if (stamp !== null) {
16949
17126
  const version = raw.topics_extracted_version ?? 0;
16950
17127
  if (raw.updated_at > stamp || version < TOPICS_EXTRACTION_VERSION) {
16951
- stampedPending.push(raw);
17128
+ stampedPendingRaw.push(raw);
17129
+ isPending = true;
16952
17130
  }
16953
- } else {
16954
- unstamped.push(raw);
16955
- }
16956
- }
16957
- const linkedIds = /* @__PURE__ */ new Set();
16958
- const CHUNK = 500;
16959
- for (let i = 0; i < unstamped.length; i += CHUNK) {
16960
- const ids = unstamped.slice(i, i + CHUNK).map((r) => r.id);
16961
- const links = await entityCtx.memoryEntityCollection.query(import_watermelondb3.Q.where("memory_id", import_watermelondb3.Q.oneOf(ids))).unsafeFetchRaw();
16962
- for (const link of links) linkedIds.add(String(link.memory_id));
16963
- }
16964
- const linkedUnstampedAll = [];
16965
- const pendingRaw = [...stampedPending];
16966
- for (const raw of unstamped) {
16967
- if (linkedIds.has(raw.id)) {
16968
- linkedUnstampedAll.push(raw.id);
17131
+ } else if (linked !== void 0) {
17132
+ linkedUnstampedAll.push(id);
16969
17133
  } else {
16970
17134
  pendingRaw.push(raw);
17135
+ isPending = true;
17136
+ }
17137
+ if (!isPending && topics === null && linked !== void 0) {
17138
+ topicsBackfillAll.push(id);
16971
17139
  }
16972
17140
  }
16973
17141
  const cap = options?.limit !== void 0 && options.limit > 0 ? options.limit : void 0;
16974
- const limitedPendingRaw = cap !== void 0 ? pendingRaw.slice(0, cap) : pendingRaw;
16975
- const linkedUnstamped = cap !== void 0 ? linkedUnstampedAll.slice(0, cap) : linkedUnstampedAll;
17142
+ const orderedPendingRaw = [...stampedPendingRaw, ...pendingRaw];
17143
+ const limitedPendingRaw = cap !== void 0 ? orderedPendingRaw.slice(0, cap) : orderedPendingRaw;
16976
17144
  const pending = await mapInBatches(
16977
17145
  limitedPendingRaw,
16978
17146
  (raw) => vaultMemoryRawToStored(raw, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
16979
17147
  );
16980
- return { pending, linkedUnstamped };
17148
+ const applyCap = (ids) => cap !== void 0 ? ids.slice(0, cap) : ids;
17149
+ return {
17150
+ pending,
17151
+ linkedUnstamped: applyCap(linkedUnstampedAll),
17152
+ topicsToRelink: applyCap(topicsToRelinkAll),
17153
+ topicsBackfill: applyCap(topicsBackfillAll)
17154
+ };
16981
17155
  }
16982
17156
  async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = TOPICS_EXTRACTION_VERSION) {
16983
17157
  if (memoryIds.length === 0) return [];
@@ -17011,6 +17185,61 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
17011
17185
  }
17012
17186
  return stamped;
17013
17187
  }
17188
+ async function relinkMemoryTopicsOp(ctx, memoryIds) {
17189
+ const entityCtx = ctx.entityCtx;
17190
+ if (!entityCtx) {
17191
+ throw new Error("relinkMemoryTopicsOp requires ctx.entityCtx");
17192
+ }
17193
+ const relinked = [];
17194
+ for (const id of Array.from(new Set(memoryIds))) {
17195
+ let record;
17196
+ try {
17197
+ record = await ctx.vaultMemoryCollection.find(id);
17198
+ } catch {
17199
+ continue;
17200
+ }
17201
+ if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
17202
+ const topics = parseTopics(record.topics);
17203
+ if (topics === null || topics.length === 0) continue;
17204
+ try {
17205
+ await relinkMemoryEntitiesFromTopicsOp(entityCtx, id, topics);
17206
+ relinked.push(id);
17207
+ } catch (err) {
17208
+ getLogger().warn("[memory/topics] relink failed", err);
17209
+ }
17210
+ }
17211
+ return relinked;
17212
+ }
17213
+ async function backfillMemoryTopicsOp(ctx, memoryIds) {
17214
+ const entityCtx = ctx.entityCtx;
17215
+ if (!entityCtx) {
17216
+ throw new Error("backfillMemoryTopicsOp requires ctx.entityCtx");
17217
+ }
17218
+ const filled = [];
17219
+ for (const id of Array.from(new Set(memoryIds))) {
17220
+ let record;
17221
+ try {
17222
+ record = await ctx.vaultMemoryCollection.find(id);
17223
+ } catch {
17224
+ continue;
17225
+ }
17226
+ if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
17227
+ if (parseTopics(record.topics) !== null) continue;
17228
+ const links = await entityCtx.memoryEntityCollection.query(import_watermelondb3.Q.where("memory_id", id)).unsafeFetchRaw();
17229
+ const entityIds = links.map((l) => String(l.entity_id));
17230
+ if (entityIds.length === 0) continue;
17231
+ const entities = await entityCtx.entityCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(entityIds))).fetch();
17232
+ if (entities.length === 0) continue;
17233
+ const source = record.topicsUserManaged ? "user" : "auto";
17234
+ await ctx.database.write(async () => {
17235
+ const topicsOp = await prepareMemoryTopicsUpdate(entityCtx, id, entities, [], source);
17236
+ if (!topicsOp) return;
17237
+ await ctx.database.batch(topicsOp);
17238
+ filled.push(id);
17239
+ });
17240
+ }
17241
+ return filled;
17242
+ }
17014
17243
  async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
17015
17244
  if (ctx.userId !== void 0 && ctx.userId !== userId) return 0;
17016
17245
  const records = await ctx.vaultMemoryCollection.query(import_watermelondb3.Q.where("user_id", userId), import_watermelondb3.Q.where("is_deleted", false)).fetch();
@@ -20081,7 +20310,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
20081
20310
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
20082
20311
  );
20083
20312
  }
20084
- const { recall: recall2 } = await import("./recall-SLMMIFHM.mjs");
20313
+ const { recall: recall2 } = await import("./recall-RMCSM6L6.mjs");
20085
20314
  let recallDegraded = [];
20086
20315
  const result = await recall2(
20087
20316
  query,
@@ -21106,6 +21335,8 @@ export {
21106
21335
  TOPICS_EXTRACTION_VERSION,
21107
21336
  getMemoriesNeedingTopicExtractionOp,
21108
21337
  stampTopicsExtractedAtOp,
21338
+ relinkMemoryTopicsOp,
21339
+ backfillMemoryTopicsOp,
21109
21340
  deleteAllVaultMemoriesForUserOp,
21110
21341
  assertVaultScopeForSweep,
21111
21342
  getDecayCandidatesRawOp,