@anuma/sdk 7.3.4 → 7.5.0

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.
@@ -17095,9 +17095,51 @@ function isBorderline(input) {
17095
17095
  }
17096
17096
  return false;
17097
17097
  }
17098
+ function vaultDecayBackend(vaultCtx) {
17099
+ return {
17100
+ candidates: () => getDecayCandidatesRawOp(vaultCtx),
17101
+ archive: async (rows, now) => {
17102
+ const archived = /* @__PURE__ */ new Set();
17103
+ for (const c of rows) {
17104
+ const ok = await archiveVaultMemoryOp(vaultCtx, c.uniqueId, {
17105
+ now,
17106
+ expectedUpdatedAt: c.updatedAt,
17107
+ expectedLastObservedAt: c.lastObservedAt ?? null
17108
+ });
17109
+ if (ok) archived.add(c.uniqueId);
17110
+ }
17111
+ return archived;
17112
+ },
17113
+ hardDelete: async (rows, deleteOptions) => {
17114
+ const deleted = /* @__PURE__ */ new Set();
17115
+ for (const c of rows) {
17116
+ if (await hardDeleteDecayedOp(vaultCtx, c.uniqueId, deleteOptions)) deleted.add(c.uniqueId);
17117
+ }
17118
+ return deleted;
17119
+ }
17120
+ };
17121
+ }
17098
17122
  function createDecaySweeper(options) {
17099
- const { vaultCtx, policy, classifier, onSwept, onError } = options;
17123
+ const { vaultCtx, ...sweepOptions } = options;
17100
17124
  assertVaultScopeForSweep(vaultCtx);
17125
+ return createDecaySweeperOver(vaultDecayBackend(vaultCtx), sweepOptions);
17126
+ }
17127
+ function ruleBasedDecayOptions(options = {}) {
17128
+ if (options.classifier !== void 0)
17129
+ throw new Error(
17130
+ "MemoryStore.decay sweeps by rule only; a decay classifier needs decrypted content"
17131
+ );
17132
+ const { now, policy, onSwept, onError } = options;
17133
+ return {
17134
+ ...now !== void 0 && { now },
17135
+ ...policy && { policy },
17136
+ ...onSwept && { onSwept },
17137
+ ...onError && { onError }
17138
+ };
17139
+ }
17140
+ function createDecaySweeperOver(backend, options) {
17141
+ const { policy, classifier, onSwept, onError } = options;
17142
+ const maxTransitions = options.maxTransitionsPerSweep ?? Number.POSITIVE_INFINITY;
17101
17143
  const hardDeleteWindowMs = policy?.hardDeleteWindowMs ?? DEFAULT_DECAY_POLICY.hardDeleteWindowMs;
17102
17144
  const maxClassifierCalls = options.maxClassifierCallsPerSweep ?? DEFAULT_MAX_CLASSIFIER_CALLS_PER_SWEEP;
17103
17145
  const classifierCache = /* @__PURE__ */ new Map();
@@ -17139,7 +17181,7 @@ function createDecaySweeper(options) {
17139
17181
  const now = resolveNow(options.now);
17140
17182
  let candidates;
17141
17183
  try {
17142
- candidates = await getDecayCandidatesRawOp(vaultCtx);
17184
+ candidates = await backend.candidates();
17143
17185
  } catch (err) {
17144
17186
  onError?.(err instanceof Error ? err : new Error(String(err)));
17145
17187
  return emptyResult();
@@ -17162,25 +17204,37 @@ function createDecaySweeper(options) {
17162
17204
  result.scanned = candidates.length;
17163
17205
  result.classifierCalls = sweep.classifierCalls;
17164
17206
  result.classifierCapHits = sweep.classifierCapHits;
17207
+ let landed = 0;
17208
+ const apply = async (queue, run, count2) => {
17209
+ let next = 0;
17210
+ while (next < queue.length && landed < maxTransitions) {
17211
+ const batch = queue.slice(next, next + (maxTransitions - landed));
17212
+ next += batch.length;
17213
+ const done = await run(batch.map(({ candidate }) => candidate));
17214
+ for (const { candidate, source } of batch) {
17215
+ if (!done.has(candidate.uniqueId)) continue;
17216
+ landed++;
17217
+ count2(source);
17218
+ }
17219
+ }
17220
+ };
17165
17221
  try {
17166
- for (const { candidate: c, source } of toArchive) {
17167
- const ok = await archiveVaultMemoryOp(vaultCtx, c.uniqueId, {
17168
- now,
17169
- expectedUpdatedAt: c.updatedAt,
17170
- expectedLastObservedAt: c.lastObservedAt ?? null
17171
- });
17172
- if (ok) {
17222
+ await apply(
17223
+ toArchive,
17224
+ (rows) => backend.archive(rows, now),
17225
+ (source) => {
17173
17226
  result.archived++;
17174
17227
  result[source].archived++;
17175
17228
  }
17176
- }
17177
- for (const { candidate: c, source } of toDelete) {
17178
- const ok = await hardDeleteDecayedOp(vaultCtx, c.uniqueId, { hardDeleteWindowMs, now });
17179
- if (ok) {
17229
+ );
17230
+ await apply(
17231
+ toDelete,
17232
+ (rows) => backend.hardDelete(rows, { hardDeleteWindowMs, now }),
17233
+ (source) => {
17180
17234
  result.deleted++;
17181
17235
  result[source].deleted++;
17182
17236
  }
17183
- }
17237
+ );
17184
17238
  } catch (err) {
17185
17239
  onError?.(err instanceof Error ? err : new Error(String(err)));
17186
17240
  }
@@ -19224,7 +19278,10 @@ function createLocalMemoryStore(options) {
19224
19278
  return () => subscriptions.forEach((s) => s.unsubscribe());
19225
19279
  },
19226
19280
  maintenance,
19227
- topicMaintenance: maintenance
19281
+ topicMaintenance: maintenance,
19282
+ decay: {
19283
+ createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...ruleBasedDecayOptions(sweeperOptions), vaultCtx })
19284
+ }
19228
19285
  };
19229
19286
  }
19230
19287
 
@@ -20614,6 +20671,9 @@ var MAX_QUERY_TOPICS = 100;
20614
20671
  var MAX_QUERY_FILTER = 20;
20615
20672
  var GRAPH_LANE_ROWS = 256;
20616
20673
  var TEMPORAL_LANE_ROWS = 256;
20674
+ var REPAIR_ROWS = 50;
20675
+ var REPAIR_SCAN = 2e3;
20676
+ var DECAY_TRANSITIONS_PER_SWEEP = 200;
20617
20677
  var RemoteMemoryPartialCreateError = class extends Error {
20618
20678
  constructor(created, cause) {
20619
20679
  super(`createMany stored ${created.length} memories before a batch failed`);
@@ -20622,6 +20682,9 @@ var RemoteMemoryPartialCreateError = class extends Error {
20622
20682
  this.name = "RemoteMemoryPartialCreateError";
20623
20683
  }
20624
20684
  };
20685
+ function rejectsInput(error) {
20686
+ return error instanceof EmbeddingHttpError && error.status !== void 0 && error.status >= 400 && error.status < 500 && error.status !== 429 && !isFatalEmbeddingError(error);
20687
+ }
20625
20688
  function warnFailed(failed) {
20626
20689
  if (failed.length)
20627
20690
  getLogger().warn(
@@ -21127,6 +21190,42 @@ function createRemoteMemoryStore(options) {
21127
21190
  relinkTopics: () => Promise.resolve([]),
21128
21191
  backfillTopics: () => Promise.resolve([])
21129
21192
  };
21193
+ const decayRow = (memory) => ({
21194
+ uniqueId: memory.memory_id,
21195
+ factType: memory.fact_type ?? null,
21196
+ eventTimeEnd: memory.event_time_end ?? null,
21197
+ eventTimeKind: memory.event_time_kind ?? null,
21198
+ updatedAt: memory.updated_at,
21199
+ lastObservedAt: memory.last_observed_at ?? null,
21200
+ archivedAt: memory.archived_at ?? null,
21201
+ source: memory.source ?? null,
21202
+ trustTier: memory.trust_tier ?? null
21203
+ });
21204
+ const decayWrite = async (rows, change, edit) => {
21205
+ if (rows.length === 0) return /* @__PURE__ */ new Set();
21206
+ const seen2 = new Map(rows.map((row) => [row.uniqueId, row]));
21207
+ const { saved, failed } = await mutateMany(
21208
+ [...seen2.keys()],
21209
+ () => change,
21210
+ (memory) => edit(memory, seen2.get(memory.memory_id))
21211
+ );
21212
+ if (failed.size)
21213
+ getLogger().warn("[memory/remote-store] Decay skipped memories:", [...failed.values()]);
21214
+ return new Set(saved.keys());
21215
+ };
21216
+ const decayBackend = {
21217
+ candidates: async () => (await pages(metadata2, { include_archived: true, include_quarantined: true })).filter(({ memory }) => memory.kind === void 0 || memory.kind === null).map(({ memory }) => decayRow(memory)),
21218
+ archive: (rows, now) => decayWrite(
21219
+ rows,
21220
+ "edit",
21221
+ (memory, seen2) => (memory.archived_at ?? null) === null && memory.updated_at === seen2.updatedAt && (memory.last_observed_at ?? null) === (seen2.lastObservedAt ?? null) ? { ...memory, archived_at: now } : null
21222
+ ),
21223
+ hardDelete: (rows, { hardDeleteWindowMs, now }) => decayWrite(
21224
+ rows,
21225
+ "membership",
21226
+ (memory) => memory.archived_at !== void 0 && memory.archived_at !== null && now - memory.archived_at > hardDeleteWindowMs ? { ...memory, is_deleted: true } : null
21227
+ )
21228
+ };
21130
21229
  const everyState = {
21131
21230
  include_deleted: true,
21132
21231
  include_archived: true,
@@ -21202,9 +21301,104 @@ function createRemoteMemoryStore(options) {
21202
21301
  polling = false;
21203
21302
  });
21204
21303
  };
21304
+ const unrepairable = /* @__PURE__ */ new Set();
21305
+ let repairCursor;
21306
+ const repairEmbeddings = async ({
21307
+ maxRows = REPAIR_ROWS,
21308
+ maxScan = REPAIR_SCAN,
21309
+ cursor: start = repairCursor
21310
+ } = {}) => {
21311
+ const scannedRows = [];
21312
+ let cursor2 = start;
21313
+ do {
21314
+ const page = await metadata2({
21315
+ include_deleted: true,
21316
+ include_archived: true,
21317
+ include_quarantined: true,
21318
+ include_superseded: true,
21319
+ limit: Math.min(200, Math.max(1, maxScan - scannedRows.length)),
21320
+ ...cursor2 && { cursor: cursor2 }
21321
+ });
21322
+ scannedRows.push(...page.items);
21323
+ cursor2 = page.next_cursor;
21324
+ } while (cursor2 && scannedRows.length < maxScan);
21325
+ const allStale = scannedRows.filter(
21326
+ ({ memory }) => memory.embedding_model !== model && !unrepairable.has(memory.memory_id)
21327
+ );
21328
+ const repaired = /* @__PURE__ */ new Set();
21329
+ const result = {
21330
+ scanned: scannedRows.length,
21331
+ reembedded: 0,
21332
+ failed: 0,
21333
+ skippedConflict: 0
21334
+ };
21335
+ const finish = () => {
21336
+ const settled = allStale.every(
21337
+ ({ memory }) => repaired.has(memory.memory_id) || unrepairable.has(memory.memory_id)
21338
+ );
21339
+ repairCursor = settled ? cursor2 : start;
21340
+ return repairCursor ? { ...result, cursor: repairCursor } : result;
21341
+ };
21342
+ const stale = allStale.slice(0, maxRows).map(({ memory }) => memory.memory_id);
21343
+ if (stale.length === 0) return finish();
21344
+ const { records, unreadable } = await readEveryState(stale);
21345
+ result.failed += unreadable.size;
21346
+ for (const id of stale)
21347
+ if (unreadable.has(id) || !records.get(id)?.memory.content.trim()) unrepairable.add(id);
21348
+ const targets = stale.filter((id) => !unrepairable.has(id)).map((id) => records.get(id));
21349
+ if (targets.length === 0) return finish();
21350
+ const vectors = await embedForRepair(targets);
21351
+ if (!vectors) {
21352
+ result.failed += targets.length;
21353
+ return finish();
21354
+ }
21355
+ for (const [i, record2] of targets.entries()) {
21356
+ const vector = vectors[i];
21357
+ if (!vector) {
21358
+ result.failed++;
21359
+ continue;
21360
+ }
21361
+ await serialized(record2.memory.memory_id, async () => {
21362
+ try {
21363
+ const saved = await persistence.put(
21364
+ { ...record2.memory, embedding: storedVector(vector), embedding_model: model },
21365
+ record2
21366
+ );
21367
+ notify("embedding", [saved]);
21368
+ repaired.add(record2.memory.memory_id);
21369
+ result.reembedded++;
21370
+ } catch (error) {
21371
+ if (error instanceof RemoteMemoryError && error.code === "version_conflict")
21372
+ result.skippedConflict++;
21373
+ else result.failed++;
21374
+ }
21375
+ });
21376
+ }
21377
+ return finish();
21378
+ };
21379
+ const embedForRepair = async (targets) => {
21380
+ const texts = targets.map(({ memory }) => memory.content);
21381
+ try {
21382
+ return await generateEmbeddings(texts, embeddingOptions);
21383
+ } catch (error) {
21384
+ getLogger().warn("[memory/remote-store] Failed to embed memories for repair:", error);
21385
+ if (!rejectsInput(error)) return null;
21386
+ }
21387
+ const vectors = [];
21388
+ for (const [i, text14] of texts.entries()) {
21389
+ try {
21390
+ [vectors[i]] = await generateEmbeddings([text14], embeddingOptions);
21391
+ } catch (error) {
21392
+ if (!rejectsInput(error)) return null;
21393
+ unrepairable.add(targets[i].memory.memory_id);
21394
+ }
21395
+ }
21396
+ return vectors;
21397
+ };
21205
21398
  return {
21206
21399
  masksEmbeddingInput: embeddingOptions.maskInput !== void 0,
21207
21400
  topicMaintenance,
21401
+ repairEmbeddings,
21208
21402
  list: async (listOptions = {}) => (await listRows(decrypted, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
21209
21403
  (r) => stored(r.memory)
21210
21404
  ),
@@ -21404,6 +21598,12 @@ function createRemoteMemoryStore(options) {
21404
21598
  else if (result.action === "update" || result.action === "merge") notify("edit");
21405
21599
  return result;
21406
21600
  },
21601
+ decay: {
21602
+ createDecaySweeper: (sweeperOptions) => createDecaySweeperOver(decayBackend, {
21603
+ ...ruleBasedDecayOptions(sweeperOptions),
21604
+ maxTransitionsPerSweep: DECAY_TRANSITIONS_PER_SWEEP
21605
+ })
21606
+ },
21407
21607
  subscribe: (onChange, subscribeOptions = {}) => {
21408
21608
  const subscriber = { onChange, options: subscribeOptions };
21409
21609
  subscribers.add(subscriber);
@@ -21016,9 +21016,51 @@ function isBorderline(input) {
21016
21016
  }
21017
21017
  return false;
21018
21018
  }
21019
+ function vaultDecayBackend(vaultCtx) {
21020
+ return {
21021
+ candidates: () => getDecayCandidatesRawOp(vaultCtx),
21022
+ archive: async (rows, now) => {
21023
+ const archived = /* @__PURE__ */ new Set();
21024
+ for (const c of rows) {
21025
+ const ok = await archiveVaultMemoryOp(vaultCtx, c.uniqueId, {
21026
+ now,
21027
+ expectedUpdatedAt: c.updatedAt,
21028
+ expectedLastObservedAt: c.lastObservedAt ?? null
21029
+ });
21030
+ if (ok) archived.add(c.uniqueId);
21031
+ }
21032
+ return archived;
21033
+ },
21034
+ hardDelete: async (rows, deleteOptions) => {
21035
+ const deleted = /* @__PURE__ */ new Set();
21036
+ for (const c of rows) {
21037
+ if (await hardDeleteDecayedOp(vaultCtx, c.uniqueId, deleteOptions)) deleted.add(c.uniqueId);
21038
+ }
21039
+ return deleted;
21040
+ }
21041
+ };
21042
+ }
21019
21043
  function createDecaySweeper(options) {
21020
- const { vaultCtx, policy, classifier, onSwept, onError } = options;
21044
+ const { vaultCtx, ...sweepOptions } = options;
21021
21045
  assertVaultScopeForSweep(vaultCtx);
21046
+ return createDecaySweeperOver(vaultDecayBackend(vaultCtx), sweepOptions);
21047
+ }
21048
+ function ruleBasedDecayOptions(options = {}) {
21049
+ if (options.classifier !== void 0)
21050
+ throw new Error(
21051
+ "MemoryStore.decay sweeps by rule only; a decay classifier needs decrypted content"
21052
+ );
21053
+ const { now, policy, onSwept, onError } = options;
21054
+ return {
21055
+ ...now !== void 0 && { now },
21056
+ ...policy && { policy },
21057
+ ...onSwept && { onSwept },
21058
+ ...onError && { onError }
21059
+ };
21060
+ }
21061
+ function createDecaySweeperOver(backend, options) {
21062
+ const { policy, classifier, onSwept, onError } = options;
21063
+ const maxTransitions = options.maxTransitionsPerSweep ?? Number.POSITIVE_INFINITY;
21022
21064
  const hardDeleteWindowMs = policy?.hardDeleteWindowMs ?? DEFAULT_DECAY_POLICY.hardDeleteWindowMs;
21023
21065
  const maxClassifierCalls = options.maxClassifierCallsPerSweep ?? DEFAULT_MAX_CLASSIFIER_CALLS_PER_SWEEP;
21024
21066
  const classifierCache = /* @__PURE__ */ new Map();
@@ -21060,7 +21102,7 @@ function createDecaySweeper(options) {
21060
21102
  const now = resolveNow(options.now);
21061
21103
  let candidates;
21062
21104
  try {
21063
- candidates = await getDecayCandidatesRawOp(vaultCtx);
21105
+ candidates = await backend.candidates();
21064
21106
  } catch (err) {
21065
21107
  onError?.(err instanceof Error ? err : new Error(String(err)));
21066
21108
  return emptyResult();
@@ -21083,25 +21125,37 @@ function createDecaySweeper(options) {
21083
21125
  result.scanned = candidates.length;
21084
21126
  result.classifierCalls = sweep.classifierCalls;
21085
21127
  result.classifierCapHits = sweep.classifierCapHits;
21128
+ let landed = 0;
21129
+ const apply = async (queue, run, count2) => {
21130
+ let next = 0;
21131
+ while (next < queue.length && landed < maxTransitions) {
21132
+ const batch = queue.slice(next, next + (maxTransitions - landed));
21133
+ next += batch.length;
21134
+ const done = await run(batch.map(({ candidate }) => candidate));
21135
+ for (const { candidate, source } of batch) {
21136
+ if (!done.has(candidate.uniqueId)) continue;
21137
+ landed++;
21138
+ count2(source);
21139
+ }
21140
+ }
21141
+ };
21086
21142
  try {
21087
- for (const { candidate: c, source } of toArchive) {
21088
- const ok = await archiveVaultMemoryOp(vaultCtx, c.uniqueId, {
21089
- now,
21090
- expectedUpdatedAt: c.updatedAt,
21091
- expectedLastObservedAt: c.lastObservedAt ?? null
21092
- });
21093
- if (ok) {
21143
+ await apply(
21144
+ toArchive,
21145
+ (rows) => backend.archive(rows, now),
21146
+ (source) => {
21094
21147
  result.archived++;
21095
21148
  result[source].archived++;
21096
21149
  }
21097
- }
21098
- for (const { candidate: c, source } of toDelete) {
21099
- const ok = await hardDeleteDecayedOp(vaultCtx, c.uniqueId, { hardDeleteWindowMs, now });
21100
- if (ok) {
21150
+ );
21151
+ await apply(
21152
+ toDelete,
21153
+ (rows) => backend.hardDelete(rows, { hardDeleteWindowMs, now }),
21154
+ (source) => {
21101
21155
  result.deleted++;
21102
21156
  result[source].deleted++;
21103
21157
  }
21104
- }
21158
+ );
21105
21159
  } catch (err) {
21106
21160
  onError?.(err instanceof Error ? err : new Error(String(err)));
21107
21161
  }
@@ -23186,7 +23240,10 @@ function createLocalMemoryStore(options) {
23186
23240
  return () => subscriptions.forEach((s) => s.unsubscribe());
23187
23241
  },
23188
23242
  maintenance,
23189
- topicMaintenance: maintenance
23243
+ topicMaintenance: maintenance,
23244
+ decay: {
23245
+ createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...ruleBasedDecayOptions(sweeperOptions), vaultCtx })
23246
+ }
23190
23247
  };
23191
23248
  }
23192
23249
 
@@ -24582,6 +24639,9 @@ var MAX_QUERY_TOPICS = 100;
24582
24639
  var MAX_QUERY_FILTER = 20;
24583
24640
  var GRAPH_LANE_ROWS = 256;
24584
24641
  var TEMPORAL_LANE_ROWS = 256;
24642
+ var REPAIR_ROWS = 50;
24643
+ var REPAIR_SCAN = 2e3;
24644
+ var DECAY_TRANSITIONS_PER_SWEEP = 200;
24585
24645
  var RemoteMemoryPartialCreateError = class extends Error {
24586
24646
  constructor(created, cause) {
24587
24647
  super(`createMany stored ${created.length} memories before a batch failed`);
@@ -24590,6 +24650,9 @@ var RemoteMemoryPartialCreateError = class extends Error {
24590
24650
  this.name = "RemoteMemoryPartialCreateError";
24591
24651
  }
24592
24652
  };
24653
+ function rejectsInput(error) {
24654
+ return error instanceof EmbeddingHttpError && error.status !== void 0 && error.status >= 400 && error.status < 500 && error.status !== 429 && !isFatalEmbeddingError(error);
24655
+ }
24593
24656
  function warnFailed(failed) {
24594
24657
  if (failed.length)
24595
24658
  getLogger().warn(
@@ -25095,6 +25158,42 @@ function createRemoteMemoryStore(options) {
25095
25158
  relinkTopics: () => Promise.resolve([]),
25096
25159
  backfillTopics: () => Promise.resolve([])
25097
25160
  };
25161
+ const decayRow = (memory) => ({
25162
+ uniqueId: memory.memory_id,
25163
+ factType: memory.fact_type ?? null,
25164
+ eventTimeEnd: memory.event_time_end ?? null,
25165
+ eventTimeKind: memory.event_time_kind ?? null,
25166
+ updatedAt: memory.updated_at,
25167
+ lastObservedAt: memory.last_observed_at ?? null,
25168
+ archivedAt: memory.archived_at ?? null,
25169
+ source: memory.source ?? null,
25170
+ trustTier: memory.trust_tier ?? null
25171
+ });
25172
+ const decayWrite = async (rows, change, edit) => {
25173
+ if (rows.length === 0) return /* @__PURE__ */ new Set();
25174
+ const seen2 = new Map(rows.map((row) => [row.uniqueId, row]));
25175
+ const { saved, failed } = await mutateMany(
25176
+ [...seen2.keys()],
25177
+ () => change,
25178
+ (memory) => edit(memory, seen2.get(memory.memory_id))
25179
+ );
25180
+ if (failed.size)
25181
+ getLogger().warn("[memory/remote-store] Decay skipped memories:", [...failed.values()]);
25182
+ return new Set(saved.keys());
25183
+ };
25184
+ const decayBackend = {
25185
+ candidates: async () => (await pages(metadata2, { include_archived: true, include_quarantined: true })).filter(({ memory }) => memory.kind === void 0 || memory.kind === null).map(({ memory }) => decayRow(memory)),
25186
+ archive: (rows, now) => decayWrite(
25187
+ rows,
25188
+ "edit",
25189
+ (memory, seen2) => (memory.archived_at ?? null) === null && memory.updated_at === seen2.updatedAt && (memory.last_observed_at ?? null) === (seen2.lastObservedAt ?? null) ? { ...memory, archived_at: now } : null
25190
+ ),
25191
+ hardDelete: (rows, { hardDeleteWindowMs, now }) => decayWrite(
25192
+ rows,
25193
+ "membership",
25194
+ (memory) => memory.archived_at !== void 0 && memory.archived_at !== null && now - memory.archived_at > hardDeleteWindowMs ? { ...memory, is_deleted: true } : null
25195
+ )
25196
+ };
25098
25197
  const everyState = {
25099
25198
  include_deleted: true,
25100
25199
  include_archived: true,
@@ -25170,9 +25269,104 @@ function createRemoteMemoryStore(options) {
25170
25269
  polling = false;
25171
25270
  });
25172
25271
  };
25272
+ const unrepairable = /* @__PURE__ */ new Set();
25273
+ let repairCursor;
25274
+ const repairEmbeddings = async ({
25275
+ maxRows = REPAIR_ROWS,
25276
+ maxScan = REPAIR_SCAN,
25277
+ cursor: start = repairCursor
25278
+ } = {}) => {
25279
+ const scannedRows = [];
25280
+ let cursor2 = start;
25281
+ do {
25282
+ const page = await metadata2({
25283
+ include_deleted: true,
25284
+ include_archived: true,
25285
+ include_quarantined: true,
25286
+ include_superseded: true,
25287
+ limit: Math.min(200, Math.max(1, maxScan - scannedRows.length)),
25288
+ ...cursor2 && { cursor: cursor2 }
25289
+ });
25290
+ scannedRows.push(...page.items);
25291
+ cursor2 = page.next_cursor;
25292
+ } while (cursor2 && scannedRows.length < maxScan);
25293
+ const allStale = scannedRows.filter(
25294
+ ({ memory }) => memory.embedding_model !== model && !unrepairable.has(memory.memory_id)
25295
+ );
25296
+ const repaired = /* @__PURE__ */ new Set();
25297
+ const result = {
25298
+ scanned: scannedRows.length,
25299
+ reembedded: 0,
25300
+ failed: 0,
25301
+ skippedConflict: 0
25302
+ };
25303
+ const finish = () => {
25304
+ const settled = allStale.every(
25305
+ ({ memory }) => repaired.has(memory.memory_id) || unrepairable.has(memory.memory_id)
25306
+ );
25307
+ repairCursor = settled ? cursor2 : start;
25308
+ return repairCursor ? { ...result, cursor: repairCursor } : result;
25309
+ };
25310
+ const stale = allStale.slice(0, maxRows).map(({ memory }) => memory.memory_id);
25311
+ if (stale.length === 0) return finish();
25312
+ const { records, unreadable } = await readEveryState(stale);
25313
+ result.failed += unreadable.size;
25314
+ for (const id of stale)
25315
+ if (unreadable.has(id) || !records.get(id)?.memory.content.trim()) unrepairable.add(id);
25316
+ const targets = stale.filter((id) => !unrepairable.has(id)).map((id) => records.get(id));
25317
+ if (targets.length === 0) return finish();
25318
+ const vectors = await embedForRepair(targets);
25319
+ if (!vectors) {
25320
+ result.failed += targets.length;
25321
+ return finish();
25322
+ }
25323
+ for (const [i, record2] of targets.entries()) {
25324
+ const vector = vectors[i];
25325
+ if (!vector) {
25326
+ result.failed++;
25327
+ continue;
25328
+ }
25329
+ await serialized(record2.memory.memory_id, async () => {
25330
+ try {
25331
+ const saved = await persistence.put(
25332
+ { ...record2.memory, embedding: storedVector(vector), embedding_model: model },
25333
+ record2
25334
+ );
25335
+ notify("embedding", [saved]);
25336
+ repaired.add(record2.memory.memory_id);
25337
+ result.reembedded++;
25338
+ } catch (error) {
25339
+ if (error instanceof RemoteMemoryError && error.code === "version_conflict")
25340
+ result.skippedConflict++;
25341
+ else result.failed++;
25342
+ }
25343
+ });
25344
+ }
25345
+ return finish();
25346
+ };
25347
+ const embedForRepair = async (targets) => {
25348
+ const texts = targets.map(({ memory }) => memory.content);
25349
+ try {
25350
+ return await generateEmbeddings(texts, embeddingOptions);
25351
+ } catch (error) {
25352
+ getLogger().warn("[memory/remote-store] Failed to embed memories for repair:", error);
25353
+ if (!rejectsInput(error)) return null;
25354
+ }
25355
+ const vectors = [];
25356
+ for (const [i, text14] of texts.entries()) {
25357
+ try {
25358
+ [vectors[i]] = await generateEmbeddings([text14], embeddingOptions);
25359
+ } catch (error) {
25360
+ if (!rejectsInput(error)) return null;
25361
+ unrepairable.add(targets[i].memory.memory_id);
25362
+ }
25363
+ }
25364
+ return vectors;
25365
+ };
25173
25366
  return {
25174
25367
  masksEmbeddingInput: embeddingOptions.maskInput !== void 0,
25175
25368
  topicMaintenance,
25369
+ repairEmbeddings,
25176
25370
  list: async (listOptions = {}) => (await listRows(decrypted, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
25177
25371
  (r) => stored(r.memory)
25178
25372
  ),
@@ -25372,6 +25566,12 @@ function createRemoteMemoryStore(options) {
25372
25566
  else if (result.action === "update" || result.action === "merge") notify("edit");
25373
25567
  return result;
25374
25568
  },
25569
+ decay: {
25570
+ createDecaySweeper: (sweeperOptions) => createDecaySweeperOver(decayBackend, {
25571
+ ...ruleBasedDecayOptions(sweeperOptions),
25572
+ maxTransitionsPerSweep: DECAY_TRANSITIONS_PER_SWEEP
25573
+ })
25574
+ },
25375
25575
  subscribe: (onChange, subscribeOptions = {}) => {
25376
25576
  const subscriber = { onChange, options: subscribeOptions };
25377
25577
  subscribers.add(subscriber);