@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.
- package/dist/expo/index.cjs +309 -86
- package/dist/expo/index.d.mts +9 -1
- package/dist/expo/index.d.ts +9 -1
- package/dist/expo/index.mjs +308 -85
- package/dist/index.cjs +37 -3
- package/dist/index.mjs +37 -3
- package/dist/react/index.cjs +309 -86
- package/dist/react/index.d.mts +9 -1
- package/dist/react/index.d.ts +9 -1
- package/dist/react/index.mjs +309 -86
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1623,11 +1623,12 @@ function parseRetryAfterMs(header) {
|
|
|
1623
1623
|
|
|
1624
1624
|
// src/lib/memory/store/remotePersistence.ts
|
|
1625
1625
|
var RemoteMemoryError = class extends Error {
|
|
1626
|
-
constructor(message, status, code, retryAfterMs) {
|
|
1626
|
+
constructor(message, status, code, retryAfterMs, rateLimitBucket) {
|
|
1627
1627
|
super(message);
|
|
1628
1628
|
this.status = status;
|
|
1629
1629
|
this.code = code;
|
|
1630
1630
|
this.retryAfterMs = retryAfterMs;
|
|
1631
|
+
this.rateLimitBucket = rateLimitBucket;
|
|
1631
1632
|
this.name = "RemoteMemoryError";
|
|
1632
1633
|
}
|
|
1633
1634
|
};
|
|
@@ -1646,6 +1647,14 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
|
|
|
1646
1647
|
throw new Error("timeoutMs must be a positive number");
|
|
1647
1648
|
const root = base.href.replace(/\/$/, "") + apiPath;
|
|
1648
1649
|
const fetcher = options.fetch ?? globalThis.fetch;
|
|
1650
|
+
const cooldowns = /* @__PURE__ */ new Map();
|
|
1651
|
+
const memoryBudget = (path, method) => {
|
|
1652
|
+
if (method === "PUT")
|
|
1653
|
+
return path === "/topics" ? "private-memory-import" : "private-memory-write";
|
|
1654
|
+
if (method === "POST" && ["/import", "/memories/batch", "/topics/import"].includes(path))
|
|
1655
|
+
return "private-memory-import";
|
|
1656
|
+
return "private-memory-read";
|
|
1657
|
+
};
|
|
1649
1658
|
const request = async (path, init = {}, signal) => {
|
|
1650
1659
|
const controller = new AbortController();
|
|
1651
1660
|
let timedOut = false;
|
|
@@ -1669,6 +1678,25 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
|
|
|
1669
1678
|
const token = await Promise.race([options.getToken(), aborted]);
|
|
1670
1679
|
if (controller.signal.aborted) await aborted;
|
|
1671
1680
|
if (!token) throw new RemoteMemoryError("Authentication required", 401);
|
|
1681
|
+
const pathname = path.split("?")[0];
|
|
1682
|
+
const route = `${init.method ?? "GET"} ${pathname}`;
|
|
1683
|
+
const budgets = ["*", route];
|
|
1684
|
+
if (apiPath === "/api/private-memories")
|
|
1685
|
+
budgets.push("private-memory-ip", memoryBudget(pathname, init.method ?? "GET"));
|
|
1686
|
+
for (const bucket of budgets) {
|
|
1687
|
+
const cooldown = cooldowns.get(bucket);
|
|
1688
|
+
if (!cooldown) continue;
|
|
1689
|
+
const remaining = cooldown.until - Date.now();
|
|
1690
|
+
if (remaining > 0)
|
|
1691
|
+
throw new RemoteMemoryError(
|
|
1692
|
+
cooldown.error.message,
|
|
1693
|
+
429,
|
|
1694
|
+
cooldown.error.code,
|
|
1695
|
+
remaining,
|
|
1696
|
+
cooldown.error.rateLimitBucket
|
|
1697
|
+
);
|
|
1698
|
+
cooldowns.delete(bucket);
|
|
1699
|
+
}
|
|
1672
1700
|
const response = await fetcher(root + path, {
|
|
1673
1701
|
...init,
|
|
1674
1702
|
headers: {
|
|
@@ -1681,12 +1709,18 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
|
|
|
1681
1709
|
if (!response.ok) {
|
|
1682
1710
|
const body = await response.json().catch(() => null);
|
|
1683
1711
|
const retryAfter = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
1684
|
-
|
|
1712
|
+
const error = new RemoteMemoryError(
|
|
1685
1713
|
record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
|
|
1686
1714
|
response.status,
|
|
1687
1715
|
record(body) && typeof body.code === "string" ? body.code : void 0,
|
|
1688
|
-
retryAfter ?? void 0
|
|
1716
|
+
retryAfter ?? void 0,
|
|
1717
|
+
record(body) && typeof body.rate_limit_bucket === "string" ? body.rate_limit_bucket : void 0
|
|
1689
1718
|
);
|
|
1719
|
+
if (response.status === 429 && retryAfter !== null && retryAfter > 0 && (!error.code || error.code === "rate_limited")) {
|
|
1720
|
+
const bucket = error.rateLimitBucket && budgets.includes(error.rateLimitBucket) ? error.rateLimitBucket : record(body) && (body.limit_scope === "account" || body.limit_scope === "ip") && !error.rateLimitBucket ? "*" : route;
|
|
1721
|
+
cooldowns.set(bucket, { until: Date.now() + retryAfter, error });
|
|
1722
|
+
}
|
|
1723
|
+
throw error;
|
|
1690
1724
|
}
|
|
1691
1725
|
return await response.json();
|
|
1692
1726
|
} catch (error) {
|
package/dist/react/index.cjs
CHANGED
|
@@ -12118,11 +12118,12 @@ function isRemoteWorkLeaseExpired(error) {
|
|
|
12118
12118
|
|
|
12119
12119
|
// src/lib/memory/store/remotePersistence.ts
|
|
12120
12120
|
var RemoteMemoryError = class extends Error {
|
|
12121
|
-
constructor(message, status, code, retryAfterMs) {
|
|
12121
|
+
constructor(message, status, code, retryAfterMs, rateLimitBucket) {
|
|
12122
12122
|
super(message);
|
|
12123
12123
|
this.status = status;
|
|
12124
12124
|
this.code = code;
|
|
12125
12125
|
this.retryAfterMs = retryAfterMs;
|
|
12126
|
+
this.rateLimitBucket = rateLimitBucket;
|
|
12126
12127
|
this.name = "RemoteMemoryError";
|
|
12127
12128
|
}
|
|
12128
12129
|
};
|
|
@@ -12217,6 +12218,14 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
|
|
|
12217
12218
|
throw new Error("timeoutMs must be a positive number");
|
|
12218
12219
|
const root = base.href.replace(/\/$/, "") + apiPath;
|
|
12219
12220
|
const fetcher = options.fetch ?? globalThis.fetch;
|
|
12221
|
+
const cooldowns = /* @__PURE__ */ new Map();
|
|
12222
|
+
const memoryBudget = (path, method) => {
|
|
12223
|
+
if (method === "PUT")
|
|
12224
|
+
return path === "/topics" ? "private-memory-import" : "private-memory-write";
|
|
12225
|
+
if (method === "POST" && ["/import", "/memories/batch", "/topics/import"].includes(path))
|
|
12226
|
+
return "private-memory-import";
|
|
12227
|
+
return "private-memory-read";
|
|
12228
|
+
};
|
|
12220
12229
|
const request = async (path, init = {}, signal) => {
|
|
12221
12230
|
const controller = new AbortController();
|
|
12222
12231
|
let timedOut = false;
|
|
@@ -12240,6 +12249,25 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
|
|
|
12240
12249
|
const token = await Promise.race([options.getToken(), aborted2]);
|
|
12241
12250
|
if (controller.signal.aborted) await aborted2;
|
|
12242
12251
|
if (!token) throw new RemoteMemoryError("Authentication required", 401);
|
|
12252
|
+
const pathname = path.split("?")[0];
|
|
12253
|
+
const route = `${init.method ?? "GET"} ${pathname}`;
|
|
12254
|
+
const budgets = ["*", route];
|
|
12255
|
+
if (apiPath === "/api/private-memories")
|
|
12256
|
+
budgets.push("private-memory-ip", memoryBudget(pathname, init.method ?? "GET"));
|
|
12257
|
+
for (const bucket of budgets) {
|
|
12258
|
+
const cooldown = cooldowns.get(bucket);
|
|
12259
|
+
if (!cooldown) continue;
|
|
12260
|
+
const remaining = cooldown.until - Date.now();
|
|
12261
|
+
if (remaining > 0)
|
|
12262
|
+
throw new RemoteMemoryError(
|
|
12263
|
+
cooldown.error.message,
|
|
12264
|
+
429,
|
|
12265
|
+
cooldown.error.code,
|
|
12266
|
+
remaining,
|
|
12267
|
+
cooldown.error.rateLimitBucket
|
|
12268
|
+
);
|
|
12269
|
+
cooldowns.delete(bucket);
|
|
12270
|
+
}
|
|
12243
12271
|
const response = await fetcher(root + path, {
|
|
12244
12272
|
...init,
|
|
12245
12273
|
headers: {
|
|
@@ -12252,12 +12280,18 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
|
|
|
12252
12280
|
if (!response.ok) {
|
|
12253
12281
|
const body = await response.json().catch(() => null);
|
|
12254
12282
|
const retryAfter = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
12255
|
-
|
|
12283
|
+
const error = new RemoteMemoryError(
|
|
12256
12284
|
record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
|
|
12257
12285
|
response.status,
|
|
12258
12286
|
record(body) && typeof body.code === "string" ? body.code : void 0,
|
|
12259
|
-
retryAfter ?? void 0
|
|
12287
|
+
retryAfter ?? void 0,
|
|
12288
|
+
record(body) && typeof body.rate_limit_bucket === "string" ? body.rate_limit_bucket : void 0
|
|
12260
12289
|
);
|
|
12290
|
+
if (response.status === 429 && retryAfter !== null && retryAfter > 0 && (!error.code || error.code === "rate_limited")) {
|
|
12291
|
+
const bucket = error.rateLimitBucket && budgets.includes(error.rateLimitBucket) ? error.rateLimitBucket : record(body) && (body.limit_scope === "account" || body.limit_scope === "ip") && !error.rateLimitBucket ? "*" : route;
|
|
12292
|
+
cooldowns.set(bucket, { until: Date.now() + retryAfter, error });
|
|
12293
|
+
}
|
|
12294
|
+
throw error;
|
|
12261
12295
|
}
|
|
12262
12296
|
return await response.json();
|
|
12263
12297
|
} catch (error) {
|
|
@@ -12497,6 +12531,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
12497
12531
|
return {
|
|
12498
12532
|
...createRemoteTopicPersistence(request),
|
|
12499
12533
|
...createRemoteWorkPersistence(request),
|
|
12534
|
+
supportsRealtimeChanges: account.realtime_changes === true,
|
|
12500
12535
|
counts: async () => {
|
|
12501
12536
|
const result = await request("/counts", {});
|
|
12502
12537
|
if (!record(result) || ["live", "archived", "quarantined"].some(
|
|
@@ -25334,6 +25369,9 @@ var RemoteMemoryPartialCreateError = class extends Error {
|
|
|
25334
25369
|
function rejectsInput(error) {
|
|
25335
25370
|
return error instanceof EmbeddingHttpError && error.status !== void 0 && error.status >= 400 && error.status < 500 && error.status !== 429 && !isFatalEmbeddingError(error);
|
|
25336
25371
|
}
|
|
25372
|
+
function rejectsMemoryWrite(error) {
|
|
25373
|
+
return error instanceof RemoteMemoryError && (error.status === 400 || error.status === 422) && (error.code === void 0 || error.code === "unknown_field");
|
|
25374
|
+
}
|
|
25337
25375
|
function warnFailed(failed) {
|
|
25338
25376
|
if (failed.length)
|
|
25339
25377
|
getLogger().warn(
|
|
@@ -25421,16 +25459,47 @@ function createRemoteMemoryStore(options) {
|
|
|
25421
25459
|
const { persistence, embeddingOptions } = options;
|
|
25422
25460
|
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
25423
25461
|
const pollIntervalMs = options.pollIntervalMs ?? 6e4;
|
|
25462
|
+
const activity = options.activity ?? {
|
|
25463
|
+
isActive: () => (typeof document === "undefined" || document.visibilityState !== "hidden") && (typeof navigator === "undefined" || navigator.onLine !== false),
|
|
25464
|
+
subscribe: (onChange) => {
|
|
25465
|
+
if (typeof window === "undefined" || typeof document === "undefined") return () => {
|
|
25466
|
+
};
|
|
25467
|
+
document.addEventListener("visibilitychange", onChange);
|
|
25468
|
+
window.addEventListener("online", onChange);
|
|
25469
|
+
window.addEventListener("offline", onChange);
|
|
25470
|
+
return () => {
|
|
25471
|
+
document.removeEventListener("visibilitychange", onChange);
|
|
25472
|
+
window.removeEventListener("online", onChange);
|
|
25473
|
+
window.removeEventListener("offline", onChange);
|
|
25474
|
+
};
|
|
25475
|
+
}
|
|
25476
|
+
};
|
|
25424
25477
|
const pipeline = createRemoteMemoryPipeline({
|
|
25425
25478
|
...options,
|
|
25426
25479
|
graphRanking: options.graphRanking ?? ((query, _traverse, recallOptions) => topicGraphRanking(query, recallOptions)),
|
|
25427
25480
|
temporalRanking: options.temporalRanking ?? ((query, now) => eventTimeRanking(query, now))
|
|
25428
25481
|
});
|
|
25429
25482
|
const subscribers = /* @__PURE__ */ new Set();
|
|
25483
|
+
const retainTopics = () => pollIntervalMs > 0 && [...subscribers].some((subscriber) => subscriber.options.topics);
|
|
25430
25484
|
const seen = /* @__PURE__ */ new Map();
|
|
25485
|
+
const reads = /* @__PURE__ */ new Map();
|
|
25486
|
+
const metadataReads = /* @__PURE__ */ new Map();
|
|
25487
|
+
let topicSnapshot;
|
|
25488
|
+
let topicCatalog;
|
|
25489
|
+
const invalidateReads = () => {
|
|
25490
|
+
reads.clear();
|
|
25491
|
+
metadataReads.clear();
|
|
25492
|
+
topicSnapshot = void 0;
|
|
25493
|
+
topicCatalog = void 0;
|
|
25494
|
+
};
|
|
25431
25495
|
let timer;
|
|
25496
|
+
let scheduledAt;
|
|
25497
|
+
let stopActivity;
|
|
25498
|
+
let stopChanges;
|
|
25499
|
+
let changesConnected = false;
|
|
25432
25500
|
const notify = (change, records = []) => {
|
|
25433
|
-
|
|
25501
|
+
invalidateReads();
|
|
25502
|
+
if (subscribers.size)
|
|
25434
25503
|
for (const record2 of records) {
|
|
25435
25504
|
const previous = seen.get(record2.memory.memory_id);
|
|
25436
25505
|
if ((previous?.version ?? 0) + 1 === record2.version)
|
|
@@ -25454,8 +25523,37 @@ function createRemoteMemoryStore(options) {
|
|
|
25454
25523
|
} while (cursor2 && records.length < max);
|
|
25455
25524
|
return records.slice(0, max);
|
|
25456
25525
|
};
|
|
25457
|
-
const
|
|
25458
|
-
|
|
25526
|
+
const shareRead = (inflight, options2, read) => {
|
|
25527
|
+
if (options2.signal) return read();
|
|
25528
|
+
const key = JSON.stringify(Object.entries(options2).sort(([a], [b]) => a.localeCompare(b)));
|
|
25529
|
+
const active = inflight.get(key);
|
|
25530
|
+
if (active) return active;
|
|
25531
|
+
const pending2 = read();
|
|
25532
|
+
inflight.set(key, pending2);
|
|
25533
|
+
const clear = () => {
|
|
25534
|
+
if (inflight.get(key) === pending2) inflight.delete(key);
|
|
25535
|
+
};
|
|
25536
|
+
void pending2.then(clear, clear);
|
|
25537
|
+
return pending2;
|
|
25538
|
+
};
|
|
25539
|
+
const decrypted = (options2) => shareRead(reads, options2, () => persistence.query(options2));
|
|
25540
|
+
const metadata3 = (options2) => shareRead(
|
|
25541
|
+
metadataReads,
|
|
25542
|
+
options2,
|
|
25543
|
+
() => persistence.queryMetadata(options2)
|
|
25544
|
+
);
|
|
25545
|
+
const readTopics = () => {
|
|
25546
|
+
if (topicCatalog) return topicCatalog;
|
|
25547
|
+
const pending2 = persistence.topics();
|
|
25548
|
+
topicCatalog = pending2;
|
|
25549
|
+
const clear = () => {
|
|
25550
|
+
if (topicCatalog === pending2) topicCatalog = void 0;
|
|
25551
|
+
};
|
|
25552
|
+
void pending2.then(() => {
|
|
25553
|
+
if (!retainTopics()) clear();
|
|
25554
|
+
}, clear);
|
|
25555
|
+
return pending2;
|
|
25556
|
+
};
|
|
25459
25557
|
const enumerate = (filters, max = Infinity) => pages(decrypted, filters, max);
|
|
25460
25558
|
const memoriesByTopics = async (names) => {
|
|
25461
25559
|
const wanted = new Set(names.map(normalizeEntityName).filter(Boolean));
|
|
@@ -25909,11 +26007,11 @@ function createRemoteMemoryStore(options) {
|
|
|
25909
26007
|
};
|
|
25910
26008
|
const changesSince = async (cursor2, pending2) => {
|
|
25911
26009
|
const records = [];
|
|
25912
|
-
const failed = /* @__PURE__ */ new
|
|
26010
|
+
const failed = /* @__PURE__ */ new Map();
|
|
25913
26011
|
const collect = (page) => {
|
|
25914
26012
|
warnFailed(page.failed);
|
|
25915
26013
|
records.push(...page.items);
|
|
25916
|
-
for (const failure of page.failed) failed.
|
|
26014
|
+
for (const failure of page.failed) failed.set(failure.memory_id, failure.version);
|
|
25917
26015
|
};
|
|
25918
26016
|
let resume = cursor2;
|
|
25919
26017
|
let next;
|
|
@@ -25947,25 +26045,72 @@ function createRemoteMemoryStore(options) {
|
|
|
25947
26045
|
let ready = false;
|
|
25948
26046
|
let cursor;
|
|
25949
26047
|
let pending = /* @__PURE__ */ new Set();
|
|
26048
|
+
let failedVersions = /* @__PURE__ */ new Map();
|
|
25950
26049
|
let topicFingerprint;
|
|
25951
26050
|
let polling = false;
|
|
26051
|
+
let pollRequested = false;
|
|
26052
|
+
let failures = 0;
|
|
26053
|
+
let retryAt = 0;
|
|
26054
|
+
const backoff = (error) => {
|
|
26055
|
+
failures++;
|
|
26056
|
+
retryAt = Date.now() + Math.max(
|
|
26057
|
+
error instanceof RemoteMemoryError ? error.retryAfterMs ?? 0 : 0,
|
|
26058
|
+
Math.min(pollIntervalMs * 2 ** Math.min(failures - 1, 10), 15 * 6e4)
|
|
26059
|
+
);
|
|
26060
|
+
};
|
|
26061
|
+
const schedulePoll = (delay, keepEarlier = false) => {
|
|
26062
|
+
const at = Math.max(Date.now() + delay, retryAt);
|
|
26063
|
+
if (keepEarlier && timer && scheduledAt !== void 0 && scheduledAt <= at) return;
|
|
26064
|
+
if (timer) clearTimeout(timer);
|
|
26065
|
+
timer = void 0;
|
|
26066
|
+
scheduledAt = void 0;
|
|
26067
|
+
if (!subscribers.size || pollIntervalMs <= 0 || !activity.isActive()) return;
|
|
26068
|
+
scheduledAt = at;
|
|
26069
|
+
timer = setTimeout(poll, Math.max(0, at - Date.now()));
|
|
26070
|
+
};
|
|
25952
26071
|
const poll = () => {
|
|
25953
|
-
if (
|
|
26072
|
+
if (timer) clearTimeout(timer);
|
|
26073
|
+
timer = void 0;
|
|
26074
|
+
scheduledAt = void 0;
|
|
26075
|
+
if (!subscribers.size || pollIntervalMs <= 0 || !activity.isActive()) return;
|
|
26076
|
+
if (Date.now() < retryAt) {
|
|
26077
|
+
schedulePoll(0);
|
|
26078
|
+
return;
|
|
26079
|
+
}
|
|
26080
|
+
if (polling) {
|
|
26081
|
+
pollRequested = true;
|
|
26082
|
+
return;
|
|
26083
|
+
}
|
|
25954
26084
|
polling = true;
|
|
26085
|
+
pollRequested = false;
|
|
25955
26086
|
const current = generation;
|
|
25956
26087
|
changesSince(cursor, pending).then(async ({ records, resume, failed }) => {
|
|
25957
26088
|
let topicState;
|
|
26089
|
+
let topicFailed = false;
|
|
25958
26090
|
if ([...subscribers].some((s) => s.options.topics))
|
|
25959
26091
|
try {
|
|
25960
|
-
|
|
25961
|
-
|
|
25962
|
-
);
|
|
26092
|
+
topicCatalog = void 0;
|
|
26093
|
+
topicState = JSON.stringify((await readTopics()).map((t) => [t.name, t.version]));
|
|
25963
26094
|
} catch (error) {
|
|
26095
|
+
topicFailed = true;
|
|
26096
|
+
if (current === generation) backoff(error);
|
|
25964
26097
|
getLogger().warn("[memory/remote-store] Topic subscription poll failed:", error);
|
|
25965
26098
|
}
|
|
25966
26099
|
if (current !== generation) return;
|
|
26100
|
+
if (!topicFailed) {
|
|
26101
|
+
failures = 0;
|
|
26102
|
+
retryAt = 0;
|
|
26103
|
+
}
|
|
26104
|
+
const failedChanged = [...failed].some(
|
|
26105
|
+
([id2, version]) => failedVersions.get(id2) !== version
|
|
26106
|
+
);
|
|
26107
|
+
if (records.length || failedChanged || topicState !== void 0 && topicState !== topicFingerprint) {
|
|
26108
|
+
reads.clear();
|
|
26109
|
+
metadataReads.clear();
|
|
26110
|
+
topicSnapshot = void 0;
|
|
26111
|
+
}
|
|
25967
26112
|
const changed = /* @__PURE__ */ new Set();
|
|
25968
|
-
if (topicState !== void 0 && topicFingerprint !== void 0 && topicState !== topicFingerprint) {
|
|
26113
|
+
if (ready && failedChanged || topicState !== void 0 && topicFingerprint !== void 0 && topicState !== topicFingerprint) {
|
|
25969
26114
|
for (const subscriber of subscribers)
|
|
25970
26115
|
if (subscriber.options.topics) changed.add(subscriber);
|
|
25971
26116
|
}
|
|
@@ -25982,15 +26127,40 @@ function createRemoteMemoryStore(options) {
|
|
|
25982
26127
|
}
|
|
25983
26128
|
ready = true;
|
|
25984
26129
|
cursor = resume;
|
|
25985
|
-
pending = failed;
|
|
26130
|
+
pending = new Set(failed.keys());
|
|
26131
|
+
failedVersions = failed;
|
|
25986
26132
|
for (const subscriber of changed)
|
|
25987
26133
|
if (subscribers.has(subscriber)) safely(subscriber.onChange);
|
|
25988
26134
|
}).catch((error) => {
|
|
26135
|
+
if (current === generation) backoff(error);
|
|
25989
26136
|
getLogger().warn("[memory/remote-store] Subscription poll failed:", error);
|
|
25990
26137
|
}).finally(() => {
|
|
25991
26138
|
polling = false;
|
|
26139
|
+
schedulePoll(
|
|
26140
|
+
current !== generation ? 0 : pollRequested ? 200 : changesConnected ? Math.max(pollIntervalMs, 5 * 6e4) : pollIntervalMs
|
|
26141
|
+
);
|
|
25992
26142
|
});
|
|
25993
26143
|
};
|
|
26144
|
+
const refreshActivity = () => {
|
|
26145
|
+
if (timer) clearTimeout(timer);
|
|
26146
|
+
timer = void 0;
|
|
26147
|
+
if (!activity.isActive()) {
|
|
26148
|
+
stopChanges?.();
|
|
26149
|
+
stopChanges = void 0;
|
|
26150
|
+
changesConnected = false;
|
|
26151
|
+
return;
|
|
26152
|
+
}
|
|
26153
|
+
if (!stopChanges && persistence.supportsRealtimeChanges && options.subscribeChanges)
|
|
26154
|
+
stopChanges = options.subscribeChanges((connected) => {
|
|
26155
|
+
changesConnected = connected;
|
|
26156
|
+
if (polling) {
|
|
26157
|
+
pollRequested = true;
|
|
26158
|
+
return;
|
|
26159
|
+
}
|
|
26160
|
+
schedulePoll(connected ? 200 : 0, true);
|
|
26161
|
+
});
|
|
26162
|
+
poll();
|
|
26163
|
+
};
|
|
25994
26164
|
const unrepairable = /* @__PURE__ */ new Set();
|
|
25995
26165
|
let repairCursor;
|
|
25996
26166
|
const repairEmbeddingsUnlocked = async ({
|
|
@@ -26046,40 +26216,78 @@ function createRemoteMemoryStore(options) {
|
|
|
26046
26216
|
result.failed += targets.length;
|
|
26047
26217
|
return finish();
|
|
26048
26218
|
}
|
|
26049
|
-
|
|
26219
|
+
const writes = targets.flatMap((record2, i) => {
|
|
26050
26220
|
const vector = vectors[i];
|
|
26051
26221
|
if (!vector) {
|
|
26052
26222
|
result.failed++;
|
|
26053
|
-
|
|
26223
|
+
return [];
|
|
26054
26224
|
}
|
|
26055
|
-
|
|
26056
|
-
|
|
26057
|
-
|
|
26058
|
-
|
|
26059
|
-
|
|
26060
|
-
|
|
26061
|
-
|
|
26062
|
-
|
|
26063
|
-
|
|
26064
|
-
|
|
26065
|
-
|
|
26066
|
-
|
|
26067
|
-
|
|
26068
|
-
|
|
26069
|
-
|
|
26070
|
-
|
|
26071
|
-
|
|
26072
|
-
|
|
26073
|
-
|
|
26074
|
-
|
|
26075
|
-
} catch (error) {
|
|
26225
|
+
try {
|
|
26226
|
+
return [
|
|
26227
|
+
{
|
|
26228
|
+
memory: {
|
|
26229
|
+
...record2.memory,
|
|
26230
|
+
embedding: storedVector(vector),
|
|
26231
|
+
embedding_model: model
|
|
26232
|
+
},
|
|
26233
|
+
expectedVersion: record2
|
|
26234
|
+
}
|
|
26235
|
+
];
|
|
26236
|
+
} catch {
|
|
26237
|
+
result.failed++;
|
|
26238
|
+
return [];
|
|
26239
|
+
}
|
|
26240
|
+
});
|
|
26241
|
+
for (const batch of chunks2(writes, MAX_BATCH)) {
|
|
26242
|
+
const continueRepair = await serializedAll(
|
|
26243
|
+
batch.map(({ memory }) => memory.memory_id),
|
|
26244
|
+
async () => {
|
|
26076
26245
|
signal?.throwIfAborted();
|
|
26077
|
-
|
|
26078
|
-
|
|
26079
|
-
|
|
26080
|
-
|
|
26246
|
+
const commit = async (slice) => {
|
|
26247
|
+
const saved = await persistence.putMany(slice, signal, leaseToken);
|
|
26248
|
+
for (const record2 of saved) repaired.add(record2.memory.memory_id);
|
|
26249
|
+
result.reembedded += saved.length;
|
|
26250
|
+
notify("embedding", saved);
|
|
26251
|
+
};
|
|
26252
|
+
try {
|
|
26253
|
+
await commit(batch);
|
|
26254
|
+
} catch (error) {
|
|
26255
|
+
signal?.throwIfAborted();
|
|
26256
|
+
if (isRemoteWorkLeaseExpired(error)) throw error;
|
|
26257
|
+
if (!(error instanceof RemoteMemoryError && error.code === "version_conflict") && !rejectsMemoryWrite(error)) {
|
|
26258
|
+
result.failed += batch.length;
|
|
26259
|
+
return false;
|
|
26260
|
+
}
|
|
26261
|
+
if (batch.length === 1) {
|
|
26262
|
+
if (rejectsMemoryWrite(error)) {
|
|
26263
|
+
unrepairable.add(batch[0].memory.memory_id);
|
|
26264
|
+
result.failed++;
|
|
26265
|
+
} else result.skippedConflict++;
|
|
26266
|
+
return true;
|
|
26267
|
+
}
|
|
26268
|
+
for (const [index, write] of batch.entries()) {
|
|
26269
|
+
signal?.throwIfAborted();
|
|
26270
|
+
try {
|
|
26271
|
+
await commit([write]);
|
|
26272
|
+
} catch (error2) {
|
|
26273
|
+
signal?.throwIfAborted();
|
|
26274
|
+
if (isRemoteWorkLeaseExpired(error2)) throw error2;
|
|
26275
|
+
if (error2 instanceof RemoteMemoryError && error2.code === "version_conflict")
|
|
26276
|
+
result.skippedConflict++;
|
|
26277
|
+
else if (rejectsMemoryWrite(error2)) {
|
|
26278
|
+
unrepairable.add(write.memory.memory_id);
|
|
26279
|
+
result.failed++;
|
|
26280
|
+
} else {
|
|
26281
|
+
result.failed += batch.length - index;
|
|
26282
|
+
return false;
|
|
26283
|
+
}
|
|
26284
|
+
}
|
|
26285
|
+
}
|
|
26286
|
+
}
|
|
26287
|
+
return true;
|
|
26081
26288
|
}
|
|
26082
|
-
|
|
26289
|
+
);
|
|
26290
|
+
if (!continueRepair) break;
|
|
26083
26291
|
}
|
|
26084
26292
|
return finish();
|
|
26085
26293
|
};
|
|
@@ -26119,7 +26327,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26119
26327
|
},
|
|
26120
26328
|
importTopics: async (topics) => {
|
|
26121
26329
|
if (!topics.length) return;
|
|
26122
|
-
const existing = new Set((await
|
|
26330
|
+
const existing = new Set((await readTopics()).map((topic2) => topic2.name));
|
|
26123
26331
|
const missing = topics.flatMap((topic2) => {
|
|
26124
26332
|
const name = normalizeEntityName(topic2.name);
|
|
26125
26333
|
if (existing.has(name)) return [];
|
|
@@ -26128,6 +26336,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26128
26336
|
});
|
|
26129
26337
|
if (!missing.length) return;
|
|
26130
26338
|
await persistence.importTopics(missing);
|
|
26339
|
+
invalidateReads();
|
|
26131
26340
|
for (const subscriber of [...subscribers])
|
|
26132
26341
|
if (subscriber.options.topics) safely(subscriber.onChange);
|
|
26133
26342
|
},
|
|
@@ -26141,40 +26350,51 @@ function createRemoteMemoryStore(options) {
|
|
|
26141
26350
|
listProjections: async (listOptions = {}) => (await listRows(metadata3, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
|
|
26142
26351
|
projection
|
|
26143
26352
|
),
|
|
26144
|
-
listTopics:
|
|
26145
|
-
|
|
26146
|
-
|
|
26147
|
-
|
|
26148
|
-
|
|
26149
|
-
|
|
26150
|
-
|
|
26151
|
-
|
|
26152
|
-
|
|
26153
|
-
|
|
26154
|
-
|
|
26155
|
-
name
|
|
26156
|
-
|
|
26157
|
-
|
|
26158
|
-
|
|
26159
|
-
|
|
26160
|
-
|
|
26161
|
-
|
|
26162
|
-
|
|
26163
|
-
|
|
26164
|
-
|
|
26165
|
-
|
|
26166
|
-
|
|
26167
|
-
const
|
|
26168
|
-
|
|
26169
|
-
|
|
26170
|
-
|
|
26171
|
-
|
|
26172
|
-
|
|
26173
|
-
|
|
26174
|
-
|
|
26175
|
-
|
|
26176
|
-
|
|
26177
|
-
|
|
26353
|
+
listTopics: () => {
|
|
26354
|
+
if (topicSnapshot) return topicSnapshot.then((topics) => structuredClone(topics));
|
|
26355
|
+
const snapshot = (async () => {
|
|
26356
|
+
const topics = /* @__PURE__ */ new Map();
|
|
26357
|
+
for (const { memory } of await pages(metadata3, {
|
|
26358
|
+
include_archived: true,
|
|
26359
|
+
include_quarantined: true,
|
|
26360
|
+
include_superseded: true
|
|
26361
|
+
})) {
|
|
26362
|
+
for (const topic2 of parseTopics(memory.topics) ?? []) {
|
|
26363
|
+
const name = normalizeEntityName(topic2.name);
|
|
26364
|
+
if (!name) continue;
|
|
26365
|
+
const entry = topics.get(name) ?? {
|
|
26366
|
+
name,
|
|
26367
|
+
kind: null,
|
|
26368
|
+
memoryCount: 0,
|
|
26369
|
+
members: /* @__PURE__ */ new Set()
|
|
26370
|
+
};
|
|
26371
|
+
entry.kind ?? (entry.kind = topic2.kind ?? null);
|
|
26372
|
+
entry.members.add(memory.memory_id);
|
|
26373
|
+
topics.set(name, entry);
|
|
26374
|
+
}
|
|
26375
|
+
}
|
|
26376
|
+
for (const topic2 of await readTopics()) {
|
|
26377
|
+
if (topic2.is_deleted) continue;
|
|
26378
|
+
const current = topics.get(topic2.name);
|
|
26379
|
+
if (current) current.kind ?? (current.kind = topic2.kind ?? null);
|
|
26380
|
+
else
|
|
26381
|
+
topics.set(topic2.name, {
|
|
26382
|
+
name: topic2.name,
|
|
26383
|
+
kind: topic2.kind ?? null,
|
|
26384
|
+
memoryCount: 0,
|
|
26385
|
+
members: /* @__PURE__ */ new Set()
|
|
26386
|
+
});
|
|
26387
|
+
}
|
|
26388
|
+
return [...topics.values()].map(({ members, ...topic2 }) => ({ ...topic2, memoryCount: members.size })).sort((a, b) => a.name.localeCompare(b.name));
|
|
26389
|
+
})();
|
|
26390
|
+
topicSnapshot = snapshot;
|
|
26391
|
+
const clear = () => {
|
|
26392
|
+
if (topicSnapshot === snapshot) topicSnapshot = void 0;
|
|
26393
|
+
};
|
|
26394
|
+
void snapshot.then(() => {
|
|
26395
|
+
if (!retainTopics()) clear();
|
|
26396
|
+
}, clear);
|
|
26397
|
+
return snapshot.then((topics) => structuredClone(topics));
|
|
26178
26398
|
},
|
|
26179
26399
|
get: async (id2) => asStored(await live(id2)),
|
|
26180
26400
|
listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
|
|
@@ -26355,20 +26575,23 @@ function createRemoteMemoryStore(options) {
|
|
|
26355
26575
|
subscribe: (onChange, subscribeOptions = {}) => {
|
|
26356
26576
|
const subscriber = { onChange, options: subscribeOptions };
|
|
26357
26577
|
subscribers.add(subscriber);
|
|
26358
|
-
if (pollIntervalMs > 0 &&
|
|
26359
|
-
|
|
26360
|
-
|
|
26578
|
+
if (pollIntervalMs > 0 && subscribers.size === 1) {
|
|
26579
|
+
stopActivity = activity.subscribe(refreshActivity);
|
|
26580
|
+
refreshActivity();
|
|
26361
26581
|
}
|
|
26362
26582
|
return () => {
|
|
26363
26583
|
subscribers.delete(subscriber);
|
|
26364
|
-
if (
|
|
26365
|
-
|
|
26584
|
+
if (!retainTopics()) invalidateReads();
|
|
26585
|
+
if (subscribers.size) return;
|
|
26586
|
+
if (timer) clearTimeout(timer);
|
|
26366
26587
|
timer = void 0;
|
|
26588
|
+
stopActivity?.();
|
|
26589
|
+
stopActivity = void 0;
|
|
26590
|
+
stopChanges?.();
|
|
26591
|
+
stopChanges = void 0;
|
|
26592
|
+
changesConnected = false;
|
|
26367
26593
|
generation++;
|
|
26368
|
-
|
|
26369
|
-
ready = false;
|
|
26370
|
-
cursor = void 0;
|
|
26371
|
-
pending = /* @__PURE__ */ new Set();
|
|
26594
|
+
invalidateReads();
|
|
26372
26595
|
};
|
|
26373
26596
|
}
|
|
26374
26597
|
};
|
package/dist/react/index.d.mts
CHANGED
|
@@ -11607,7 +11607,8 @@ declare class RemoteMemoryError extends Error {
|
|
|
11607
11607
|
readonly status: number;
|
|
11608
11608
|
readonly code?: string | undefined;
|
|
11609
11609
|
readonly retryAfterMs?: number | undefined;
|
|
11610
|
-
|
|
11610
|
+
readonly rateLimitBucket?: string | undefined;
|
|
11611
|
+
constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined, rateLimitBucket?: string | undefined);
|
|
11611
11612
|
}
|
|
11612
11613
|
/**
|
|
11613
11614
|
* Remote persistence foundation for MemoryStore, not yet its recall/retain implementation.
|
|
@@ -11616,6 +11617,7 @@ declare class RemoteMemoryError extends Error {
|
|
|
11616
11617
|
* Migration must have activated the account under the canonical key before construction.
|
|
11617
11618
|
*/
|
|
11618
11619
|
interface RemoteMemoryPersistence extends RemoteTopicPersistence, RemoteMemoryWorkPersistence {
|
|
11620
|
+
supportsRealtimeChanges?: boolean;
|
|
11619
11621
|
counts(): Promise<MemoryCounts>;
|
|
11620
11622
|
temporal(window: {
|
|
11621
11623
|
start: number;
|
|
@@ -11747,6 +11749,12 @@ interface RemoteMemoryStoreOptions {
|
|
|
11747
11749
|
graphRanking?: RecallFactSource["graphRanking"];
|
|
11748
11750
|
temporalRanking?: RecallFactSource["temporalRanking"];
|
|
11749
11751
|
pollIntervalMs?: number;
|
|
11752
|
+
activity?: {
|
|
11753
|
+
isActive: () => boolean;
|
|
11754
|
+
subscribe: (onChange: () => void) => () => void;
|
|
11755
|
+
};
|
|
11756
|
+
/** Report connection state on subscribe/reconnect and true on each account memory change. */
|
|
11757
|
+
subscribeChanges?: (onChange: (connected: boolean) => void) => () => void;
|
|
11750
11758
|
}
|
|
11751
11759
|
declare class RemoteMemoryPartialCreateError extends Error {
|
|
11752
11760
|
readonly created: StoredVaultMemory[];
|