@anuma/sdk 9.1.0 → 9.1.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.
@@ -11312,11 +11312,12 @@ function isRemoteWorkLeaseExpired(error) {
11312
11312
 
11313
11313
  // src/lib/memory/store/remotePersistence.ts
11314
11314
  var RemoteMemoryError = class extends Error {
11315
- constructor(message, status, code, retryAfterMs) {
11315
+ constructor(message, status, code, retryAfterMs, rateLimitBucket) {
11316
11316
  super(message);
11317
11317
  this.status = status;
11318
11318
  this.code = code;
11319
11319
  this.retryAfterMs = retryAfterMs;
11320
+ this.rateLimitBucket = rateLimitBucket;
11320
11321
  this.name = "RemoteMemoryError";
11321
11322
  }
11322
11323
  };
@@ -11411,6 +11412,14 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
11411
11412
  throw new Error("timeoutMs must be a positive number");
11412
11413
  const root = base.href.replace(/\/$/, "") + apiPath;
11413
11414
  const fetcher = options.fetch ?? globalThis.fetch;
11415
+ const cooldowns = /* @__PURE__ */ new Map();
11416
+ const memoryBudget = (path, method) => {
11417
+ if (method === "PUT")
11418
+ return path === "/topics" ? "private-memory-import" : "private-memory-write";
11419
+ if (method === "POST" && ["/import", "/memories/batch", "/topics/import"].includes(path))
11420
+ return "private-memory-import";
11421
+ return "private-memory-read";
11422
+ };
11414
11423
  const request = async (path, init = {}, signal) => {
11415
11424
  const controller = new AbortController();
11416
11425
  let timedOut = false;
@@ -11434,6 +11443,25 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
11434
11443
  const token = await Promise.race([options.getToken(), aborted2]);
11435
11444
  if (controller.signal.aborted) await aborted2;
11436
11445
  if (!token) throw new RemoteMemoryError("Authentication required", 401);
11446
+ const pathname = path.split("?")[0];
11447
+ const route = `${init.method ?? "GET"} ${pathname}`;
11448
+ const budgets = ["*", route];
11449
+ if (apiPath === "/api/private-memories")
11450
+ budgets.push("private-memory-ip", memoryBudget(pathname, init.method ?? "GET"));
11451
+ for (const bucket of budgets) {
11452
+ const cooldown = cooldowns.get(bucket);
11453
+ if (!cooldown) continue;
11454
+ const remaining = cooldown.until - Date.now();
11455
+ if (remaining > 0)
11456
+ throw new RemoteMemoryError(
11457
+ cooldown.error.message,
11458
+ 429,
11459
+ cooldown.error.code,
11460
+ remaining,
11461
+ cooldown.error.rateLimitBucket
11462
+ );
11463
+ cooldowns.delete(bucket);
11464
+ }
11437
11465
  const response = await fetcher(root + path, {
11438
11466
  ...init,
11439
11467
  headers: {
@@ -11446,12 +11474,18 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
11446
11474
  if (!response.ok) {
11447
11475
  const body = await response.json().catch(() => null);
11448
11476
  const retryAfter = parseRetryAfterMs(response.headers.get("Retry-After"));
11449
- throw new RemoteMemoryError(
11477
+ const error = new RemoteMemoryError(
11450
11478
  record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
11451
11479
  response.status,
11452
11480
  record(body) && typeof body.code === "string" ? body.code : void 0,
11453
- retryAfter ?? void 0
11481
+ retryAfter ?? void 0,
11482
+ record(body) && typeof body.rate_limit_bucket === "string" ? body.rate_limit_bucket : void 0
11454
11483
  );
11484
+ if (response.status === 429 && retryAfter !== null && retryAfter > 0 && (!error.code || error.code === "rate_limited")) {
11485
+ const bucket = error.rateLimitBucket && budgets.includes(error.rateLimitBucket) ? error.rateLimitBucket : record(body) && (body.limit_scope === "account" || body.limit_scope === "ip") && !error.rateLimitBucket ? "*" : route;
11486
+ cooldowns.set(bucket, { until: Date.now() + retryAfter, error });
11487
+ }
11488
+ throw error;
11455
11489
  }
11456
11490
  return await response.json();
11457
11491
  } catch (error) {
@@ -11691,6 +11725,7 @@ async function createRemoteMemoryPersistence(options) {
11691
11725
  return {
11692
11726
  ...createRemoteTopicPersistence(request),
11693
11727
  ...createRemoteWorkPersistence(request),
11728
+ supportsRealtimeChanges: account.realtime_changes === true,
11694
11729
  counts: async () => {
11695
11730
  const result = await request("/counts", {});
11696
11731
  if (!record(result) || ["live", "archived", "quarantined"].some(
@@ -23021,6 +23056,9 @@ var RemoteMemoryPartialCreateError = class extends Error {
23021
23056
  function rejectsInput(error) {
23022
23057
  return error instanceof EmbeddingHttpError && error.status !== void 0 && error.status >= 400 && error.status < 500 && error.status !== 429 && !isFatalEmbeddingError(error);
23023
23058
  }
23059
+ function rejectsMemoryWrite(error) {
23060
+ return error instanceof RemoteMemoryError && (error.status === 400 || error.status === 422) && (error.code === void 0 || error.code === "unknown_field");
23061
+ }
23024
23062
  function warnFailed(failed) {
23025
23063
  if (failed.length)
23026
23064
  getLogger().warn(
@@ -23108,16 +23146,47 @@ function createRemoteMemoryStore(options) {
23108
23146
  const { persistence, embeddingOptions } = options;
23109
23147
  const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
23110
23148
  const pollIntervalMs = options.pollIntervalMs ?? 6e4;
23149
+ const activity = options.activity ?? {
23150
+ isActive: () => (typeof document === "undefined" || document.visibilityState !== "hidden") && (typeof navigator === "undefined" || navigator.onLine !== false),
23151
+ subscribe: (onChange) => {
23152
+ if (typeof window === "undefined" || typeof document === "undefined") return () => {
23153
+ };
23154
+ document.addEventListener("visibilitychange", onChange);
23155
+ window.addEventListener("online", onChange);
23156
+ window.addEventListener("offline", onChange);
23157
+ return () => {
23158
+ document.removeEventListener("visibilitychange", onChange);
23159
+ window.removeEventListener("online", onChange);
23160
+ window.removeEventListener("offline", onChange);
23161
+ };
23162
+ }
23163
+ };
23111
23164
  const pipeline = createRemoteMemoryPipeline({
23112
23165
  ...options,
23113
23166
  graphRanking: options.graphRanking ?? ((query, _traverse, recallOptions) => topicGraphRanking(query, recallOptions)),
23114
23167
  temporalRanking: options.temporalRanking ?? ((query, now) => eventTimeRanking(query, now))
23115
23168
  });
23116
23169
  const subscribers = /* @__PURE__ */ new Set();
23170
+ const retainTopics = () => pollIntervalMs > 0 && [...subscribers].some((subscriber) => subscriber.options.topics);
23117
23171
  const seen = /* @__PURE__ */ new Map();
23172
+ const reads = /* @__PURE__ */ new Map();
23173
+ const metadataReads = /* @__PURE__ */ new Map();
23174
+ let topicSnapshot;
23175
+ let topicCatalog;
23176
+ const invalidateReads = () => {
23177
+ reads.clear();
23178
+ metadataReads.clear();
23179
+ topicSnapshot = void 0;
23180
+ topicCatalog = void 0;
23181
+ };
23118
23182
  let timer;
23183
+ let scheduledAt;
23184
+ let stopActivity;
23185
+ let stopChanges;
23186
+ let changesConnected = false;
23119
23187
  const notify = (change, records = []) => {
23120
- if (timer)
23188
+ invalidateReads();
23189
+ if (subscribers.size)
23121
23190
  for (const record2 of records) {
23122
23191
  const previous = seen.get(record2.memory.memory_id);
23123
23192
  if ((previous?.version ?? 0) + 1 === record2.version)
@@ -23141,8 +23210,37 @@ function createRemoteMemoryStore(options) {
23141
23210
  } while (cursor2 && records.length < max);
23142
23211
  return records.slice(0, max);
23143
23212
  };
23144
- const decrypted = (options2) => persistence.query(options2);
23145
- const metadata3 = (options2) => persistence.queryMetadata(options2);
23213
+ const shareRead = (inflight, options2, read) => {
23214
+ if (options2.signal) return read();
23215
+ const key = JSON.stringify(Object.entries(options2).sort(([a], [b]) => a.localeCompare(b)));
23216
+ const active = inflight.get(key);
23217
+ if (active) return active;
23218
+ const pending2 = read();
23219
+ inflight.set(key, pending2);
23220
+ const clear = () => {
23221
+ if (inflight.get(key) === pending2) inflight.delete(key);
23222
+ };
23223
+ void pending2.then(clear, clear);
23224
+ return pending2;
23225
+ };
23226
+ const decrypted = (options2) => shareRead(reads, options2, () => persistence.query(options2));
23227
+ const metadata3 = (options2) => shareRead(
23228
+ metadataReads,
23229
+ options2,
23230
+ () => persistence.queryMetadata(options2)
23231
+ );
23232
+ const readTopics = () => {
23233
+ if (topicCatalog) return topicCatalog;
23234
+ const pending2 = persistence.topics();
23235
+ topicCatalog = pending2;
23236
+ const clear = () => {
23237
+ if (topicCatalog === pending2) topicCatalog = void 0;
23238
+ };
23239
+ void pending2.then(() => {
23240
+ if (!retainTopics()) clear();
23241
+ }, clear);
23242
+ return pending2;
23243
+ };
23146
23244
  const enumerate = (filters, max = Infinity) => pages(decrypted, filters, max);
23147
23245
  const memoriesByTopics = async (names) => {
23148
23246
  const wanted = new Set(names.map(normalizeEntityName).filter(Boolean));
@@ -23596,11 +23694,11 @@ function createRemoteMemoryStore(options) {
23596
23694
  };
23597
23695
  const changesSince = async (cursor2, pending2) => {
23598
23696
  const records = [];
23599
- const failed = /* @__PURE__ */ new Set();
23697
+ const failed = /* @__PURE__ */ new Map();
23600
23698
  const collect = (page) => {
23601
23699
  warnFailed(page.failed);
23602
23700
  records.push(...page.items);
23603
- for (const failure of page.failed) failed.add(failure.memory_id);
23701
+ for (const failure of page.failed) failed.set(failure.memory_id, failure.version);
23604
23702
  };
23605
23703
  let resume = cursor2;
23606
23704
  let next;
@@ -23634,25 +23732,72 @@ function createRemoteMemoryStore(options) {
23634
23732
  let ready = false;
23635
23733
  let cursor;
23636
23734
  let pending = /* @__PURE__ */ new Set();
23735
+ let failedVersions = /* @__PURE__ */ new Map();
23637
23736
  let topicFingerprint;
23638
23737
  let polling = false;
23738
+ let pollRequested = false;
23739
+ let failures = 0;
23740
+ let retryAt = 0;
23741
+ const backoff = (error) => {
23742
+ failures++;
23743
+ retryAt = Date.now() + Math.max(
23744
+ error instanceof RemoteMemoryError ? error.retryAfterMs ?? 0 : 0,
23745
+ Math.min(pollIntervalMs * 2 ** Math.min(failures - 1, 10), 15 * 6e4)
23746
+ );
23747
+ };
23748
+ const schedulePoll = (delay, keepEarlier = false) => {
23749
+ const at = Math.max(Date.now() + delay, retryAt);
23750
+ if (keepEarlier && timer && scheduledAt !== void 0 && scheduledAt <= at) return;
23751
+ if (timer) clearTimeout(timer);
23752
+ timer = void 0;
23753
+ scheduledAt = void 0;
23754
+ if (!subscribers.size || pollIntervalMs <= 0 || !activity.isActive()) return;
23755
+ scheduledAt = at;
23756
+ timer = setTimeout(poll, Math.max(0, at - Date.now()));
23757
+ };
23639
23758
  const poll = () => {
23640
- if (polling) return;
23759
+ if (timer) clearTimeout(timer);
23760
+ timer = void 0;
23761
+ scheduledAt = void 0;
23762
+ if (!subscribers.size || pollIntervalMs <= 0 || !activity.isActive()) return;
23763
+ if (Date.now() < retryAt) {
23764
+ schedulePoll(0);
23765
+ return;
23766
+ }
23767
+ if (polling) {
23768
+ pollRequested = true;
23769
+ return;
23770
+ }
23641
23771
  polling = true;
23772
+ pollRequested = false;
23642
23773
  const current = generation;
23643
23774
  changesSince(cursor, pending).then(async ({ records, resume, failed }) => {
23644
23775
  let topicState;
23776
+ let topicFailed = false;
23645
23777
  if ([...subscribers].some((s) => s.options.topics))
23646
23778
  try {
23647
- topicState = JSON.stringify(
23648
- (await persistence.topics()).map((t) => [t.name, t.version])
23649
- );
23779
+ topicCatalog = void 0;
23780
+ topicState = JSON.stringify((await readTopics()).map((t) => [t.name, t.version]));
23650
23781
  } catch (error) {
23782
+ topicFailed = true;
23783
+ if (current === generation) backoff(error);
23651
23784
  getLogger().warn("[memory/remote-store] Topic subscription poll failed:", error);
23652
23785
  }
23653
23786
  if (current !== generation) return;
23787
+ if (!topicFailed) {
23788
+ failures = 0;
23789
+ retryAt = 0;
23790
+ }
23791
+ const failedChanged = [...failed].some(
23792
+ ([id2, version]) => failedVersions.get(id2) !== version
23793
+ );
23794
+ if (records.length || failedChanged || topicState !== void 0 && topicState !== topicFingerprint) {
23795
+ reads.clear();
23796
+ metadataReads.clear();
23797
+ topicSnapshot = void 0;
23798
+ }
23654
23799
  const changed = /* @__PURE__ */ new Set();
23655
- if (topicState !== void 0 && topicFingerprint !== void 0 && topicState !== topicFingerprint) {
23800
+ if (ready && failedChanged || topicState !== void 0 && topicFingerprint !== void 0 && topicState !== topicFingerprint) {
23656
23801
  for (const subscriber of subscribers)
23657
23802
  if (subscriber.options.topics) changed.add(subscriber);
23658
23803
  }
@@ -23669,15 +23814,40 @@ function createRemoteMemoryStore(options) {
23669
23814
  }
23670
23815
  ready = true;
23671
23816
  cursor = resume;
23672
- pending = failed;
23817
+ pending = new Set(failed.keys());
23818
+ failedVersions = failed;
23673
23819
  for (const subscriber of changed)
23674
23820
  if (subscribers.has(subscriber)) safely(subscriber.onChange);
23675
23821
  }).catch((error) => {
23822
+ if (current === generation) backoff(error);
23676
23823
  getLogger().warn("[memory/remote-store] Subscription poll failed:", error);
23677
23824
  }).finally(() => {
23678
23825
  polling = false;
23826
+ schedulePoll(
23827
+ current !== generation ? 0 : pollRequested ? 200 : changesConnected ? Math.max(pollIntervalMs, 5 * 6e4) : pollIntervalMs
23828
+ );
23679
23829
  });
23680
23830
  };
23831
+ const refreshActivity = () => {
23832
+ if (timer) clearTimeout(timer);
23833
+ timer = void 0;
23834
+ if (!activity.isActive()) {
23835
+ stopChanges?.();
23836
+ stopChanges = void 0;
23837
+ changesConnected = false;
23838
+ return;
23839
+ }
23840
+ if (!stopChanges && persistence.supportsRealtimeChanges && options.subscribeChanges)
23841
+ stopChanges = options.subscribeChanges((connected) => {
23842
+ changesConnected = connected;
23843
+ if (polling) {
23844
+ pollRequested = true;
23845
+ return;
23846
+ }
23847
+ schedulePoll(connected ? 200 : 0, true);
23848
+ });
23849
+ poll();
23850
+ };
23681
23851
  const unrepairable = /* @__PURE__ */ new Set();
23682
23852
  let repairCursor;
23683
23853
  const repairEmbeddingsUnlocked = async ({
@@ -23733,40 +23903,78 @@ function createRemoteMemoryStore(options) {
23733
23903
  result.failed += targets.length;
23734
23904
  return finish();
23735
23905
  }
23736
- for (const [i, record2] of targets.entries()) {
23906
+ const writes = targets.flatMap((record2, i) => {
23737
23907
  const vector = vectors[i];
23738
23908
  if (!vector) {
23739
23909
  result.failed++;
23740
- continue;
23910
+ return [];
23741
23911
  }
23742
- await serialized(record2.memory.memory_id, async () => {
23743
- signal?.throwIfAborted();
23744
- try {
23745
- const [saved] = await persistence.putMany(
23746
- [
23747
- {
23748
- memory: {
23749
- ...record2.memory,
23750
- embedding: storedVector(vector),
23751
- embedding_model: model
23752
- },
23753
- expectedVersion: record2
23754
- }
23755
- ],
23756
- signal,
23757
- leaseToken
23758
- );
23759
- notify("embedding", [saved]);
23760
- repaired.add(record2.memory.memory_id);
23761
- result.reembedded++;
23762
- } catch (error) {
23912
+ try {
23913
+ return [
23914
+ {
23915
+ memory: {
23916
+ ...record2.memory,
23917
+ embedding: storedVector(vector),
23918
+ embedding_model: model
23919
+ },
23920
+ expectedVersion: record2
23921
+ }
23922
+ ];
23923
+ } catch {
23924
+ result.failed++;
23925
+ return [];
23926
+ }
23927
+ });
23928
+ for (const batch of chunks2(writes, MAX_BATCH)) {
23929
+ const continueRepair = await serializedAll(
23930
+ batch.map(({ memory }) => memory.memory_id),
23931
+ async () => {
23763
23932
  signal?.throwIfAborted();
23764
- if (isRemoteWorkLeaseExpired(error)) throw error;
23765
- if (error instanceof RemoteMemoryError && error.code === "version_conflict")
23766
- result.skippedConflict++;
23767
- else result.failed++;
23933
+ const commit = async (slice) => {
23934
+ const saved = await persistence.putMany(slice, signal, leaseToken);
23935
+ for (const record2 of saved) repaired.add(record2.memory.memory_id);
23936
+ result.reembedded += saved.length;
23937
+ notify("embedding", saved);
23938
+ };
23939
+ try {
23940
+ await commit(batch);
23941
+ } catch (error) {
23942
+ signal?.throwIfAborted();
23943
+ if (isRemoteWorkLeaseExpired(error)) throw error;
23944
+ if (!(error instanceof RemoteMemoryError && error.code === "version_conflict") && !rejectsMemoryWrite(error)) {
23945
+ result.failed += batch.length;
23946
+ return false;
23947
+ }
23948
+ if (batch.length === 1) {
23949
+ if (rejectsMemoryWrite(error)) {
23950
+ unrepairable.add(batch[0].memory.memory_id);
23951
+ result.failed++;
23952
+ } else result.skippedConflict++;
23953
+ return true;
23954
+ }
23955
+ for (const [index, write] of batch.entries()) {
23956
+ signal?.throwIfAborted();
23957
+ try {
23958
+ await commit([write]);
23959
+ } catch (error2) {
23960
+ signal?.throwIfAborted();
23961
+ if (isRemoteWorkLeaseExpired(error2)) throw error2;
23962
+ if (error2 instanceof RemoteMemoryError && error2.code === "version_conflict")
23963
+ result.skippedConflict++;
23964
+ else if (rejectsMemoryWrite(error2)) {
23965
+ unrepairable.add(write.memory.memory_id);
23966
+ result.failed++;
23967
+ } else {
23968
+ result.failed += batch.length - index;
23969
+ return false;
23970
+ }
23971
+ }
23972
+ }
23973
+ }
23974
+ return true;
23768
23975
  }
23769
- });
23976
+ );
23977
+ if (!continueRepair) break;
23770
23978
  }
23771
23979
  return finish();
23772
23980
  };
@@ -23806,7 +24014,7 @@ function createRemoteMemoryStore(options) {
23806
24014
  },
23807
24015
  importTopics: async (topics) => {
23808
24016
  if (!topics.length) return;
23809
- const existing = new Set((await persistence.topics()).map((topic2) => topic2.name));
24017
+ const existing = new Set((await readTopics()).map((topic2) => topic2.name));
23810
24018
  const missing = topics.flatMap((topic2) => {
23811
24019
  const name = normalizeEntityName(topic2.name);
23812
24020
  if (existing.has(name)) return [];
@@ -23815,6 +24023,7 @@ function createRemoteMemoryStore(options) {
23815
24023
  });
23816
24024
  if (!missing.length) return;
23817
24025
  await persistence.importTopics(missing);
24026
+ invalidateReads();
23818
24027
  for (const subscriber of [...subscribers])
23819
24028
  if (subscriber.options.topics) safely(subscriber.onChange);
23820
24029
  },
@@ -23828,40 +24037,51 @@ function createRemoteMemoryStore(options) {
23828
24037
  listProjections: async (listOptions = {}) => (await listRows(metadata3, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
23829
24038
  projection
23830
24039
  ),
23831
- listTopics: async () => {
23832
- const topics = /* @__PURE__ */ new Map();
23833
- for (const { memory } of await pages(metadata3, {
23834
- include_archived: true,
23835
- include_quarantined: true,
23836
- include_superseded: true
23837
- })) {
23838
- for (const topic2 of parseTopics(memory.topics) ?? []) {
23839
- const name = normalizeEntityName(topic2.name);
23840
- if (!name) continue;
23841
- const entry = topics.get(name) ?? {
23842
- name,
23843
- kind: null,
23844
- memoryCount: 0,
23845
- members: /* @__PURE__ */ new Set()
23846
- };
23847
- entry.kind ?? (entry.kind = topic2.kind ?? null);
23848
- entry.members.add(memory.memory_id);
23849
- topics.set(name, entry);
23850
- }
23851
- }
23852
- for (const topic2 of await persistence.topics()) {
23853
- if (topic2.is_deleted) continue;
23854
- const current = topics.get(topic2.name);
23855
- if (current) current.kind ?? (current.kind = topic2.kind ?? null);
23856
- else
23857
- topics.set(topic2.name, {
23858
- name: topic2.name,
23859
- kind: topic2.kind ?? null,
23860
- memoryCount: 0,
23861
- members: /* @__PURE__ */ new Set()
23862
- });
23863
- }
23864
- return [...topics.values()].map(({ members, ...topic2 }) => ({ ...topic2, memoryCount: members.size })).sort((a, b) => a.name.localeCompare(b.name));
24040
+ listTopics: () => {
24041
+ if (topicSnapshot) return topicSnapshot.then((topics) => structuredClone(topics));
24042
+ const snapshot = (async () => {
24043
+ const topics = /* @__PURE__ */ new Map();
24044
+ for (const { memory } of await pages(metadata3, {
24045
+ include_archived: true,
24046
+ include_quarantined: true,
24047
+ include_superseded: true
24048
+ })) {
24049
+ for (const topic2 of parseTopics(memory.topics) ?? []) {
24050
+ const name = normalizeEntityName(topic2.name);
24051
+ if (!name) continue;
24052
+ const entry = topics.get(name) ?? {
24053
+ name,
24054
+ kind: null,
24055
+ memoryCount: 0,
24056
+ members: /* @__PURE__ */ new Set()
24057
+ };
24058
+ entry.kind ?? (entry.kind = topic2.kind ?? null);
24059
+ entry.members.add(memory.memory_id);
24060
+ topics.set(name, entry);
24061
+ }
24062
+ }
24063
+ for (const topic2 of await readTopics()) {
24064
+ if (topic2.is_deleted) continue;
24065
+ const current = topics.get(topic2.name);
24066
+ if (current) current.kind ?? (current.kind = topic2.kind ?? null);
24067
+ else
24068
+ topics.set(topic2.name, {
24069
+ name: topic2.name,
24070
+ kind: topic2.kind ?? null,
24071
+ memoryCount: 0,
24072
+ members: /* @__PURE__ */ new Set()
24073
+ });
24074
+ }
24075
+ return [...topics.values()].map(({ members, ...topic2 }) => ({ ...topic2, memoryCount: members.size })).sort((a, b) => a.name.localeCompare(b.name));
24076
+ })();
24077
+ topicSnapshot = snapshot;
24078
+ const clear = () => {
24079
+ if (topicSnapshot === snapshot) topicSnapshot = void 0;
24080
+ };
24081
+ void snapshot.then(() => {
24082
+ if (!retainTopics()) clear();
24083
+ }, clear);
24084
+ return snapshot.then((topics) => structuredClone(topics));
23865
24085
  },
23866
24086
  get: async (id2) => asStored(await live(id2)),
23867
24087
  listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
@@ -24042,20 +24262,23 @@ function createRemoteMemoryStore(options) {
24042
24262
  subscribe: (onChange, subscribeOptions = {}) => {
24043
24263
  const subscriber = { onChange, options: subscribeOptions };
24044
24264
  subscribers.add(subscriber);
24045
- if (pollIntervalMs > 0 && !timer) {
24046
- timer = setInterval(poll, pollIntervalMs);
24047
- poll();
24265
+ if (pollIntervalMs > 0 && subscribers.size === 1) {
24266
+ stopActivity = activity.subscribe(refreshActivity);
24267
+ refreshActivity();
24048
24268
  }
24049
24269
  return () => {
24050
24270
  subscribers.delete(subscriber);
24051
- if (subscribers.size || !timer) return;
24052
- clearInterval(timer);
24271
+ if (!retainTopics()) invalidateReads();
24272
+ if (subscribers.size) return;
24273
+ if (timer) clearTimeout(timer);
24053
24274
  timer = void 0;
24275
+ stopActivity?.();
24276
+ stopActivity = void 0;
24277
+ stopChanges?.();
24278
+ stopChanges = void 0;
24279
+ changesConnected = false;
24054
24280
  generation++;
24055
- seen.clear();
24056
- ready = false;
24057
- cursor = void 0;
24058
- pending = /* @__PURE__ */ new Set();
24281
+ invalidateReads();
24059
24282
  };
24060
24283
  }
24061
24284
  };
@@ -9873,7 +9873,8 @@ declare class RemoteMemoryError extends Error {
9873
9873
  readonly status: number;
9874
9874
  readonly code?: string | undefined;
9875
9875
  readonly retryAfterMs?: number | undefined;
9876
- constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined);
9876
+ readonly rateLimitBucket?: string | undefined;
9877
+ constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined, rateLimitBucket?: string | undefined);
9877
9878
  }
9878
9879
  /**
9879
9880
  * Remote persistence foundation for MemoryStore, not yet its recall/retain implementation.
@@ -9882,6 +9883,7 @@ declare class RemoteMemoryError extends Error {
9882
9883
  * Migration must have activated the account under the canonical key before construction.
9883
9884
  */
9884
9885
  interface RemoteMemoryPersistence extends RemoteTopicPersistence, RemoteMemoryWorkPersistence {
9886
+ supportsRealtimeChanges?: boolean;
9885
9887
  counts(): Promise<MemoryCounts>;
9886
9888
  temporal(window: {
9887
9889
  start: number;
@@ -10013,6 +10015,12 @@ interface RemoteMemoryStoreOptions {
10013
10015
  graphRanking?: RecallFactSource["graphRanking"];
10014
10016
  temporalRanking?: RecallFactSource["temporalRanking"];
10015
10017
  pollIntervalMs?: number;
10018
+ activity?: {
10019
+ isActive: () => boolean;
10020
+ subscribe: (onChange: () => void) => () => void;
10021
+ };
10022
+ /** Report connection state on subscribe/reconnect and true on each account memory change. */
10023
+ subscribeChanges?: (onChange: (connected: boolean) => void) => () => void;
10016
10024
  }
10017
10025
  declare class RemoteMemoryPartialCreateError extends Error {
10018
10026
  readonly created: StoredVaultMemory[];
@@ -9873,7 +9873,8 @@ declare class RemoteMemoryError extends Error {
9873
9873
  readonly status: number;
9874
9874
  readonly code?: string | undefined;
9875
9875
  readonly retryAfterMs?: number | undefined;
9876
- constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined);
9876
+ readonly rateLimitBucket?: string | undefined;
9877
+ constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined, rateLimitBucket?: string | undefined);
9877
9878
  }
9878
9879
  /**
9879
9880
  * Remote persistence foundation for MemoryStore, not yet its recall/retain implementation.
@@ -9882,6 +9883,7 @@ declare class RemoteMemoryError extends Error {
9882
9883
  * Migration must have activated the account under the canonical key before construction.
9883
9884
  */
9884
9885
  interface RemoteMemoryPersistence extends RemoteTopicPersistence, RemoteMemoryWorkPersistence {
9886
+ supportsRealtimeChanges?: boolean;
9885
9887
  counts(): Promise<MemoryCounts>;
9886
9888
  temporal(window: {
9887
9889
  start: number;
@@ -10013,6 +10015,12 @@ interface RemoteMemoryStoreOptions {
10013
10015
  graphRanking?: RecallFactSource["graphRanking"];
10014
10016
  temporalRanking?: RecallFactSource["temporalRanking"];
10015
10017
  pollIntervalMs?: number;
10018
+ activity?: {
10019
+ isActive: () => boolean;
10020
+ subscribe: (onChange: () => void) => () => void;
10021
+ };
10022
+ /** Report connection state on subscribe/reconnect and true on each account memory change. */
10023
+ subscribeChanges?: (onChange: (connected: boolean) => void) => () => void;
10016
10024
  }
10017
10025
  declare class RemoteMemoryPartialCreateError extends Error {
10018
10026
  readonly created: StoredVaultMemory[];