@anuma/sdk 9.1.0 → 9.1.2
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 +349 -97
- package/dist/expo/index.d.mts +10 -15
- package/dist/expo/index.d.ts +10 -15
- package/dist/expo/index.mjs +348 -96
- package/dist/index.cjs +37 -3
- package/dist/index.mjs +37 -3
- package/dist/react/index.cjs +349 -97
- package/dist/react/index.d.mts +10 -15
- package/dist/react/index.d.ts +10 -15
- package/dist/react/index.mjs +349 -97
- package/dist/server/index.cjs +40 -11
- package/dist/server/index.d.mts +1 -14
- package/dist/server/index.d.ts +1 -14
- package/dist/server/index.mjs +40 -11
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
@@ -14782,9 +14817,10 @@ async function getVaultRankingProjectionsOp(ctx, options) {
|
|
|
14782
14817
|
}
|
|
14783
14818
|
function baseVaultSql(ctx, options) {
|
|
14784
14819
|
const clauses = [
|
|
14820
|
+
`"_status" is not 'deleted'`,
|
|
14785
14821
|
'"is_deleted" = 0',
|
|
14786
14822
|
...options?.includeArchived ? [] : ['"archived_at" is null'],
|
|
14787
|
-
`"trust_tier" is not 'quarantined'
|
|
14823
|
+
...options?.includeQuarantined ? [] : [`"trust_tier" is not 'quarantined'`],
|
|
14788
14824
|
'"superseded_by" is null'
|
|
14789
14825
|
];
|
|
14790
14826
|
const args = [];
|
|
@@ -15270,8 +15306,17 @@ async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
|
15270
15306
|
if (!entityCtx) {
|
|
15271
15307
|
throw new Error("getMemoriesNeedingTopicExtractionOp requires ctx.entityCtx");
|
|
15272
15308
|
}
|
|
15273
|
-
|
|
15274
|
-
|
|
15309
|
+
let rows;
|
|
15310
|
+
try {
|
|
15311
|
+
const base = baseVaultSql(ctx);
|
|
15312
|
+
const sql = `select "id", "topics", "topics_user_managed", "topics_extracted_at", "topics_extracted_version", "updated_at" from "memory_vault" where ${base.sql} order by "created_at" desc`;
|
|
15313
|
+
rows = await ctx.vaultMemoryCollection.query(import_watermelondb21.Q.unsafeSqlQuery(sql, base.args)).unsafeFetchRaw();
|
|
15314
|
+
} catch (err) {
|
|
15315
|
+
getLogger().debug(
|
|
15316
|
+
"memoryVault: topic sweep SQL unavailable; use the adapter query: " + (err instanceof Error ? err.message : String(err))
|
|
15317
|
+
);
|
|
15318
|
+
rows = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx), import_watermelondb21.Q.sortBy("created_at", import_watermelondb21.Q.desc)).unsafeFetchRaw();
|
|
15319
|
+
}
|
|
15275
15320
|
const linkedNames = await linkedEntityNamesByMemory(
|
|
15276
15321
|
entityCtx,
|
|
15277
15322
|
rows.map((r) => r.id)
|
|
@@ -15330,10 +15375,19 @@ async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
|
15330
15375
|
}
|
|
15331
15376
|
const orderedPendingRaw = [...stampedPendingRaw, ...pendingRaw];
|
|
15332
15377
|
const limitedPendingRaw = cap !== void 0 ? orderedPendingRaw.slice(0, cap) : orderedPendingRaw;
|
|
15333
|
-
const pending =
|
|
15334
|
-
|
|
15335
|
-
|
|
15336
|
-
|
|
15378
|
+
const pending = [];
|
|
15379
|
+
for (let i = 0; i < limitedPendingRaw.length; i += 500) {
|
|
15380
|
+
const chunk = limitedPendingRaw.slice(i, i + 500);
|
|
15381
|
+
const memories = await getVaultMemoriesByIdsOp(
|
|
15382
|
+
ctx,
|
|
15383
|
+
chunk.map((raw) => raw.id)
|
|
15384
|
+
);
|
|
15385
|
+
const byId = new Map(memories.map((memory) => [memory.uniqueId, memory]));
|
|
15386
|
+
for (const raw of chunk) {
|
|
15387
|
+
const memory = byId.get(raw.id);
|
|
15388
|
+
if (memory) pending.push(memory);
|
|
15389
|
+
}
|
|
15390
|
+
}
|
|
15337
15391
|
const applyCap = (ids) => cap !== void 0 ? ids.slice(0, cap) : ids;
|
|
15338
15392
|
return {
|
|
15339
15393
|
pending,
|
|
@@ -15480,10 +15534,20 @@ function assertVaultScopeForSweep(ctx) {
|
|
|
15480
15534
|
}
|
|
15481
15535
|
async function getDecayCandidatesRawOp(ctx) {
|
|
15482
15536
|
assertVaultScopeForSweep(ctx);
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
|
|
15486
|
-
|
|
15537
|
+
let results;
|
|
15538
|
+
try {
|
|
15539
|
+
const base = baseVaultSql(ctx, { includeArchived: true, includeQuarantined: true });
|
|
15540
|
+
const sql = `select "id", "fact_type", "event_time_end", "event_time_kind", "updated_at", "last_observed_at", "archived_at", "source", "trust_tier" from "memory_vault" where ${base.sql} and "kind" is null`;
|
|
15541
|
+
results = await ctx.vaultMemoryCollection.query(import_watermelondb21.Q.unsafeSqlQuery(sql, base.args)).unsafeFetchRaw();
|
|
15542
|
+
} catch (err) {
|
|
15543
|
+
getLogger().debug(
|
|
15544
|
+
"memoryVault: decay sweep SQL unavailable; use the adapter query: " + (err instanceof Error ? err.message : String(err))
|
|
15545
|
+
);
|
|
15546
|
+
results = await ctx.vaultMemoryCollection.query(
|
|
15547
|
+
...baseVaultConditions(ctx, { includeArchived: true, includeQuarantined: true }),
|
|
15548
|
+
import_watermelondb21.Q.where("kind", null)
|
|
15549
|
+
).unsafeFetchRaw();
|
|
15550
|
+
}
|
|
15487
15551
|
return results.map((raw) => ({
|
|
15488
15552
|
uniqueId: raw.id,
|
|
15489
15553
|
factType: raw.fact_type ?? null,
|
|
@@ -23021,6 +23085,9 @@ var RemoteMemoryPartialCreateError = class extends Error {
|
|
|
23021
23085
|
function rejectsInput(error) {
|
|
23022
23086
|
return error instanceof EmbeddingHttpError && error.status !== void 0 && error.status >= 400 && error.status < 500 && error.status !== 429 && !isFatalEmbeddingError(error);
|
|
23023
23087
|
}
|
|
23088
|
+
function rejectsMemoryWrite(error) {
|
|
23089
|
+
return error instanceof RemoteMemoryError && (error.status === 400 || error.status === 422) && (error.code === void 0 || error.code === "unknown_field");
|
|
23090
|
+
}
|
|
23024
23091
|
function warnFailed(failed) {
|
|
23025
23092
|
if (failed.length)
|
|
23026
23093
|
getLogger().warn(
|
|
@@ -23108,16 +23175,47 @@ function createRemoteMemoryStore(options) {
|
|
|
23108
23175
|
const { persistence, embeddingOptions } = options;
|
|
23109
23176
|
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
23110
23177
|
const pollIntervalMs = options.pollIntervalMs ?? 6e4;
|
|
23178
|
+
const activity = options.activity ?? {
|
|
23179
|
+
isActive: () => (typeof document === "undefined" || document.visibilityState !== "hidden") && (typeof navigator === "undefined" || navigator.onLine !== false),
|
|
23180
|
+
subscribe: (onChange) => {
|
|
23181
|
+
if (typeof window === "undefined" || typeof document === "undefined") return () => {
|
|
23182
|
+
};
|
|
23183
|
+
document.addEventListener("visibilitychange", onChange);
|
|
23184
|
+
window.addEventListener("online", onChange);
|
|
23185
|
+
window.addEventListener("offline", onChange);
|
|
23186
|
+
return () => {
|
|
23187
|
+
document.removeEventListener("visibilitychange", onChange);
|
|
23188
|
+
window.removeEventListener("online", onChange);
|
|
23189
|
+
window.removeEventListener("offline", onChange);
|
|
23190
|
+
};
|
|
23191
|
+
}
|
|
23192
|
+
};
|
|
23111
23193
|
const pipeline = createRemoteMemoryPipeline({
|
|
23112
23194
|
...options,
|
|
23113
23195
|
graphRanking: options.graphRanking ?? ((query, _traverse, recallOptions) => topicGraphRanking(query, recallOptions)),
|
|
23114
23196
|
temporalRanking: options.temporalRanking ?? ((query, now) => eventTimeRanking(query, now))
|
|
23115
23197
|
});
|
|
23116
23198
|
const subscribers = /* @__PURE__ */ new Set();
|
|
23199
|
+
const retainTopics = () => pollIntervalMs > 0 && [...subscribers].some((subscriber) => subscriber.options.topics);
|
|
23117
23200
|
const seen = /* @__PURE__ */ new Map();
|
|
23201
|
+
const reads = /* @__PURE__ */ new Map();
|
|
23202
|
+
const metadataReads = /* @__PURE__ */ new Map();
|
|
23203
|
+
let topicSnapshot;
|
|
23204
|
+
let topicCatalog;
|
|
23205
|
+
const invalidateReads = () => {
|
|
23206
|
+
reads.clear();
|
|
23207
|
+
metadataReads.clear();
|
|
23208
|
+
topicSnapshot = void 0;
|
|
23209
|
+
topicCatalog = void 0;
|
|
23210
|
+
};
|
|
23118
23211
|
let timer;
|
|
23212
|
+
let scheduledAt;
|
|
23213
|
+
let stopActivity;
|
|
23214
|
+
let stopChanges;
|
|
23215
|
+
let changesConnected = false;
|
|
23119
23216
|
const notify = (change, records = []) => {
|
|
23120
|
-
|
|
23217
|
+
invalidateReads();
|
|
23218
|
+
if (subscribers.size)
|
|
23121
23219
|
for (const record2 of records) {
|
|
23122
23220
|
const previous = seen.get(record2.memory.memory_id);
|
|
23123
23221
|
if ((previous?.version ?? 0) + 1 === record2.version)
|
|
@@ -23141,8 +23239,37 @@ function createRemoteMemoryStore(options) {
|
|
|
23141
23239
|
} while (cursor2 && records.length < max);
|
|
23142
23240
|
return records.slice(0, max);
|
|
23143
23241
|
};
|
|
23144
|
-
const
|
|
23145
|
-
|
|
23242
|
+
const shareRead = (inflight, options2, read) => {
|
|
23243
|
+
if (options2.signal) return read();
|
|
23244
|
+
const key = JSON.stringify(Object.entries(options2).sort(([a], [b]) => a.localeCompare(b)));
|
|
23245
|
+
const active = inflight.get(key);
|
|
23246
|
+
if (active) return active;
|
|
23247
|
+
const pending2 = read();
|
|
23248
|
+
inflight.set(key, pending2);
|
|
23249
|
+
const clear = () => {
|
|
23250
|
+
if (inflight.get(key) === pending2) inflight.delete(key);
|
|
23251
|
+
};
|
|
23252
|
+
void pending2.then(clear, clear);
|
|
23253
|
+
return pending2;
|
|
23254
|
+
};
|
|
23255
|
+
const decrypted = (options2) => shareRead(reads, options2, () => persistence.query(options2));
|
|
23256
|
+
const metadata3 = (options2) => shareRead(
|
|
23257
|
+
metadataReads,
|
|
23258
|
+
options2,
|
|
23259
|
+
() => persistence.queryMetadata(options2)
|
|
23260
|
+
);
|
|
23261
|
+
const readTopics = () => {
|
|
23262
|
+
if (topicCatalog) return topicCatalog;
|
|
23263
|
+
const pending2 = persistence.topics();
|
|
23264
|
+
topicCatalog = pending2;
|
|
23265
|
+
const clear = () => {
|
|
23266
|
+
if (topicCatalog === pending2) topicCatalog = void 0;
|
|
23267
|
+
};
|
|
23268
|
+
void pending2.then(() => {
|
|
23269
|
+
if (!retainTopics()) clear();
|
|
23270
|
+
}, clear);
|
|
23271
|
+
return pending2;
|
|
23272
|
+
};
|
|
23146
23273
|
const enumerate = (filters, max = Infinity) => pages(decrypted, filters, max);
|
|
23147
23274
|
const memoriesByTopics = async (names) => {
|
|
23148
23275
|
const wanted = new Set(names.map(normalizeEntityName).filter(Boolean));
|
|
@@ -23596,11 +23723,11 @@ function createRemoteMemoryStore(options) {
|
|
|
23596
23723
|
};
|
|
23597
23724
|
const changesSince = async (cursor2, pending2) => {
|
|
23598
23725
|
const records = [];
|
|
23599
|
-
const failed = /* @__PURE__ */ new
|
|
23726
|
+
const failed = /* @__PURE__ */ new Map();
|
|
23600
23727
|
const collect = (page) => {
|
|
23601
23728
|
warnFailed(page.failed);
|
|
23602
23729
|
records.push(...page.items);
|
|
23603
|
-
for (const failure of page.failed) failed.
|
|
23730
|
+
for (const failure of page.failed) failed.set(failure.memory_id, failure.version);
|
|
23604
23731
|
};
|
|
23605
23732
|
let resume = cursor2;
|
|
23606
23733
|
let next;
|
|
@@ -23634,25 +23761,72 @@ function createRemoteMemoryStore(options) {
|
|
|
23634
23761
|
let ready = false;
|
|
23635
23762
|
let cursor;
|
|
23636
23763
|
let pending = /* @__PURE__ */ new Set();
|
|
23764
|
+
let failedVersions = /* @__PURE__ */ new Map();
|
|
23637
23765
|
let topicFingerprint;
|
|
23638
23766
|
let polling = false;
|
|
23767
|
+
let pollRequested = false;
|
|
23768
|
+
let failures = 0;
|
|
23769
|
+
let retryAt = 0;
|
|
23770
|
+
const backoff = (error) => {
|
|
23771
|
+
failures++;
|
|
23772
|
+
retryAt = Date.now() + Math.max(
|
|
23773
|
+
error instanceof RemoteMemoryError ? error.retryAfterMs ?? 0 : 0,
|
|
23774
|
+
Math.min(pollIntervalMs * 2 ** Math.min(failures - 1, 10), 15 * 6e4)
|
|
23775
|
+
);
|
|
23776
|
+
};
|
|
23777
|
+
const schedulePoll = (delay, keepEarlier = false) => {
|
|
23778
|
+
const at = Math.max(Date.now() + delay, retryAt);
|
|
23779
|
+
if (keepEarlier && timer && scheduledAt !== void 0 && scheduledAt <= at) return;
|
|
23780
|
+
if (timer) clearTimeout(timer);
|
|
23781
|
+
timer = void 0;
|
|
23782
|
+
scheduledAt = void 0;
|
|
23783
|
+
if (!subscribers.size || pollIntervalMs <= 0 || !activity.isActive()) return;
|
|
23784
|
+
scheduledAt = at;
|
|
23785
|
+
timer = setTimeout(poll, Math.max(0, at - Date.now()));
|
|
23786
|
+
};
|
|
23639
23787
|
const poll = () => {
|
|
23640
|
-
if (
|
|
23788
|
+
if (timer) clearTimeout(timer);
|
|
23789
|
+
timer = void 0;
|
|
23790
|
+
scheduledAt = void 0;
|
|
23791
|
+
if (!subscribers.size || pollIntervalMs <= 0 || !activity.isActive()) return;
|
|
23792
|
+
if (Date.now() < retryAt) {
|
|
23793
|
+
schedulePoll(0);
|
|
23794
|
+
return;
|
|
23795
|
+
}
|
|
23796
|
+
if (polling) {
|
|
23797
|
+
pollRequested = true;
|
|
23798
|
+
return;
|
|
23799
|
+
}
|
|
23641
23800
|
polling = true;
|
|
23801
|
+
pollRequested = false;
|
|
23642
23802
|
const current = generation;
|
|
23643
23803
|
changesSince(cursor, pending).then(async ({ records, resume, failed }) => {
|
|
23644
23804
|
let topicState;
|
|
23805
|
+
let topicFailed = false;
|
|
23645
23806
|
if ([...subscribers].some((s) => s.options.topics))
|
|
23646
23807
|
try {
|
|
23647
|
-
|
|
23648
|
-
|
|
23649
|
-
);
|
|
23808
|
+
topicCatalog = void 0;
|
|
23809
|
+
topicState = JSON.stringify((await readTopics()).map((t) => [t.name, t.version]));
|
|
23650
23810
|
} catch (error) {
|
|
23811
|
+
topicFailed = true;
|
|
23812
|
+
if (current === generation) backoff(error);
|
|
23651
23813
|
getLogger().warn("[memory/remote-store] Topic subscription poll failed:", error);
|
|
23652
23814
|
}
|
|
23653
23815
|
if (current !== generation) return;
|
|
23816
|
+
if (!topicFailed) {
|
|
23817
|
+
failures = 0;
|
|
23818
|
+
retryAt = 0;
|
|
23819
|
+
}
|
|
23820
|
+
const failedChanged = [...failed].some(
|
|
23821
|
+
([id2, version]) => failedVersions.get(id2) !== version
|
|
23822
|
+
);
|
|
23823
|
+
if (records.length || failedChanged || topicState !== void 0 && topicState !== topicFingerprint) {
|
|
23824
|
+
reads.clear();
|
|
23825
|
+
metadataReads.clear();
|
|
23826
|
+
topicSnapshot = void 0;
|
|
23827
|
+
}
|
|
23654
23828
|
const changed = /* @__PURE__ */ new Set();
|
|
23655
|
-
if (topicState !== void 0 && topicFingerprint !== void 0 && topicState !== topicFingerprint) {
|
|
23829
|
+
if (ready && failedChanged || topicState !== void 0 && topicFingerprint !== void 0 && topicState !== topicFingerprint) {
|
|
23656
23830
|
for (const subscriber of subscribers)
|
|
23657
23831
|
if (subscriber.options.topics) changed.add(subscriber);
|
|
23658
23832
|
}
|
|
@@ -23669,15 +23843,40 @@ function createRemoteMemoryStore(options) {
|
|
|
23669
23843
|
}
|
|
23670
23844
|
ready = true;
|
|
23671
23845
|
cursor = resume;
|
|
23672
|
-
pending = failed;
|
|
23846
|
+
pending = new Set(failed.keys());
|
|
23847
|
+
failedVersions = failed;
|
|
23673
23848
|
for (const subscriber of changed)
|
|
23674
23849
|
if (subscribers.has(subscriber)) safely(subscriber.onChange);
|
|
23675
23850
|
}).catch((error) => {
|
|
23851
|
+
if (current === generation) backoff(error);
|
|
23676
23852
|
getLogger().warn("[memory/remote-store] Subscription poll failed:", error);
|
|
23677
23853
|
}).finally(() => {
|
|
23678
23854
|
polling = false;
|
|
23855
|
+
schedulePoll(
|
|
23856
|
+
current !== generation ? 0 : pollRequested ? 200 : changesConnected ? Math.max(pollIntervalMs, 5 * 6e4) : pollIntervalMs
|
|
23857
|
+
);
|
|
23679
23858
|
});
|
|
23680
23859
|
};
|
|
23860
|
+
const refreshActivity = () => {
|
|
23861
|
+
if (timer) clearTimeout(timer);
|
|
23862
|
+
timer = void 0;
|
|
23863
|
+
if (!activity.isActive()) {
|
|
23864
|
+
stopChanges?.();
|
|
23865
|
+
stopChanges = void 0;
|
|
23866
|
+
changesConnected = false;
|
|
23867
|
+
return;
|
|
23868
|
+
}
|
|
23869
|
+
if (!stopChanges && persistence.supportsRealtimeChanges && options.subscribeChanges)
|
|
23870
|
+
stopChanges = options.subscribeChanges((connected) => {
|
|
23871
|
+
changesConnected = connected;
|
|
23872
|
+
if (polling) {
|
|
23873
|
+
pollRequested = true;
|
|
23874
|
+
return;
|
|
23875
|
+
}
|
|
23876
|
+
schedulePoll(connected ? 200 : 0, true);
|
|
23877
|
+
});
|
|
23878
|
+
poll();
|
|
23879
|
+
};
|
|
23681
23880
|
const unrepairable = /* @__PURE__ */ new Set();
|
|
23682
23881
|
let repairCursor;
|
|
23683
23882
|
const repairEmbeddingsUnlocked = async ({
|
|
@@ -23733,40 +23932,78 @@ function createRemoteMemoryStore(options) {
|
|
|
23733
23932
|
result.failed += targets.length;
|
|
23734
23933
|
return finish();
|
|
23735
23934
|
}
|
|
23736
|
-
|
|
23935
|
+
const writes = targets.flatMap((record2, i) => {
|
|
23737
23936
|
const vector = vectors[i];
|
|
23738
23937
|
if (!vector) {
|
|
23739
23938
|
result.failed++;
|
|
23740
|
-
|
|
23939
|
+
return [];
|
|
23741
23940
|
}
|
|
23742
|
-
|
|
23743
|
-
|
|
23744
|
-
|
|
23745
|
-
|
|
23746
|
-
|
|
23747
|
-
|
|
23748
|
-
|
|
23749
|
-
|
|
23750
|
-
|
|
23751
|
-
|
|
23752
|
-
|
|
23753
|
-
|
|
23754
|
-
|
|
23755
|
-
|
|
23756
|
-
|
|
23757
|
-
|
|
23758
|
-
|
|
23759
|
-
|
|
23760
|
-
|
|
23761
|
-
|
|
23762
|
-
} catch (error) {
|
|
23941
|
+
try {
|
|
23942
|
+
return [
|
|
23943
|
+
{
|
|
23944
|
+
memory: {
|
|
23945
|
+
...record2.memory,
|
|
23946
|
+
embedding: storedVector(vector),
|
|
23947
|
+
embedding_model: model
|
|
23948
|
+
},
|
|
23949
|
+
expectedVersion: record2
|
|
23950
|
+
}
|
|
23951
|
+
];
|
|
23952
|
+
} catch {
|
|
23953
|
+
result.failed++;
|
|
23954
|
+
return [];
|
|
23955
|
+
}
|
|
23956
|
+
});
|
|
23957
|
+
for (const batch of chunks2(writes, MAX_BATCH)) {
|
|
23958
|
+
const continueRepair = await serializedAll(
|
|
23959
|
+
batch.map(({ memory }) => memory.memory_id),
|
|
23960
|
+
async () => {
|
|
23763
23961
|
signal?.throwIfAborted();
|
|
23764
|
-
|
|
23765
|
-
|
|
23766
|
-
|
|
23767
|
-
|
|
23962
|
+
const commit = async (slice) => {
|
|
23963
|
+
const saved = await persistence.putMany(slice, signal, leaseToken);
|
|
23964
|
+
for (const record2 of saved) repaired.add(record2.memory.memory_id);
|
|
23965
|
+
result.reembedded += saved.length;
|
|
23966
|
+
notify("embedding", saved);
|
|
23967
|
+
};
|
|
23968
|
+
try {
|
|
23969
|
+
await commit(batch);
|
|
23970
|
+
} catch (error) {
|
|
23971
|
+
signal?.throwIfAborted();
|
|
23972
|
+
if (isRemoteWorkLeaseExpired(error)) throw error;
|
|
23973
|
+
if (!(error instanceof RemoteMemoryError && error.code === "version_conflict") && !rejectsMemoryWrite(error)) {
|
|
23974
|
+
result.failed += batch.length;
|
|
23975
|
+
return false;
|
|
23976
|
+
}
|
|
23977
|
+
if (batch.length === 1) {
|
|
23978
|
+
if (rejectsMemoryWrite(error)) {
|
|
23979
|
+
unrepairable.add(batch[0].memory.memory_id);
|
|
23980
|
+
result.failed++;
|
|
23981
|
+
} else result.skippedConflict++;
|
|
23982
|
+
return true;
|
|
23983
|
+
}
|
|
23984
|
+
for (const [index, write] of batch.entries()) {
|
|
23985
|
+
signal?.throwIfAborted();
|
|
23986
|
+
try {
|
|
23987
|
+
await commit([write]);
|
|
23988
|
+
} catch (error2) {
|
|
23989
|
+
signal?.throwIfAborted();
|
|
23990
|
+
if (isRemoteWorkLeaseExpired(error2)) throw error2;
|
|
23991
|
+
if (error2 instanceof RemoteMemoryError && error2.code === "version_conflict")
|
|
23992
|
+
result.skippedConflict++;
|
|
23993
|
+
else if (rejectsMemoryWrite(error2)) {
|
|
23994
|
+
unrepairable.add(write.memory.memory_id);
|
|
23995
|
+
result.failed++;
|
|
23996
|
+
} else {
|
|
23997
|
+
result.failed += batch.length - index;
|
|
23998
|
+
return false;
|
|
23999
|
+
}
|
|
24000
|
+
}
|
|
24001
|
+
}
|
|
24002
|
+
}
|
|
24003
|
+
return true;
|
|
23768
24004
|
}
|
|
23769
|
-
|
|
24005
|
+
);
|
|
24006
|
+
if (!continueRepair) break;
|
|
23770
24007
|
}
|
|
23771
24008
|
return finish();
|
|
23772
24009
|
};
|
|
@@ -23806,7 +24043,7 @@ function createRemoteMemoryStore(options) {
|
|
|
23806
24043
|
},
|
|
23807
24044
|
importTopics: async (topics) => {
|
|
23808
24045
|
if (!topics.length) return;
|
|
23809
|
-
const existing = new Set((await
|
|
24046
|
+
const existing = new Set((await readTopics()).map((topic2) => topic2.name));
|
|
23810
24047
|
const missing = topics.flatMap((topic2) => {
|
|
23811
24048
|
const name = normalizeEntityName(topic2.name);
|
|
23812
24049
|
if (existing.has(name)) return [];
|
|
@@ -23815,6 +24052,7 @@ function createRemoteMemoryStore(options) {
|
|
|
23815
24052
|
});
|
|
23816
24053
|
if (!missing.length) return;
|
|
23817
24054
|
await persistence.importTopics(missing);
|
|
24055
|
+
invalidateReads();
|
|
23818
24056
|
for (const subscriber of [...subscribers])
|
|
23819
24057
|
if (subscriber.options.topics) safely(subscriber.onChange);
|
|
23820
24058
|
},
|
|
@@ -23828,40 +24066,51 @@ function createRemoteMemoryStore(options) {
|
|
|
23828
24066
|
listProjections: async (listOptions = {}) => (await listRows(metadata3, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
|
|
23829
24067
|
projection
|
|
23830
24068
|
),
|
|
23831
|
-
listTopics:
|
|
23832
|
-
|
|
23833
|
-
|
|
23834
|
-
|
|
23835
|
-
|
|
23836
|
-
|
|
23837
|
-
|
|
23838
|
-
|
|
23839
|
-
|
|
23840
|
-
|
|
23841
|
-
|
|
23842
|
-
name
|
|
23843
|
-
|
|
23844
|
-
|
|
23845
|
-
|
|
23846
|
-
|
|
23847
|
-
|
|
23848
|
-
|
|
23849
|
-
|
|
23850
|
-
|
|
23851
|
-
|
|
23852
|
-
|
|
23853
|
-
|
|
23854
|
-
const
|
|
23855
|
-
|
|
23856
|
-
|
|
23857
|
-
|
|
23858
|
-
|
|
23859
|
-
|
|
23860
|
-
|
|
23861
|
-
|
|
23862
|
-
|
|
23863
|
-
|
|
23864
|
-
|
|
24069
|
+
listTopics: () => {
|
|
24070
|
+
if (topicSnapshot) return topicSnapshot.then((topics) => structuredClone(topics));
|
|
24071
|
+
const snapshot = (async () => {
|
|
24072
|
+
const topics = /* @__PURE__ */ new Map();
|
|
24073
|
+
for (const { memory } of await pages(metadata3, {
|
|
24074
|
+
include_archived: true,
|
|
24075
|
+
include_quarantined: true,
|
|
24076
|
+
include_superseded: true
|
|
24077
|
+
})) {
|
|
24078
|
+
for (const topic2 of parseTopics(memory.topics) ?? []) {
|
|
24079
|
+
const name = normalizeEntityName(topic2.name);
|
|
24080
|
+
if (!name) continue;
|
|
24081
|
+
const entry = topics.get(name) ?? {
|
|
24082
|
+
name,
|
|
24083
|
+
kind: null,
|
|
24084
|
+
memoryCount: 0,
|
|
24085
|
+
members: /* @__PURE__ */ new Set()
|
|
24086
|
+
};
|
|
24087
|
+
entry.kind ?? (entry.kind = topic2.kind ?? null);
|
|
24088
|
+
entry.members.add(memory.memory_id);
|
|
24089
|
+
topics.set(name, entry);
|
|
24090
|
+
}
|
|
24091
|
+
}
|
|
24092
|
+
for (const topic2 of await readTopics()) {
|
|
24093
|
+
if (topic2.is_deleted) continue;
|
|
24094
|
+
const current = topics.get(topic2.name);
|
|
24095
|
+
if (current) current.kind ?? (current.kind = topic2.kind ?? null);
|
|
24096
|
+
else
|
|
24097
|
+
topics.set(topic2.name, {
|
|
24098
|
+
name: topic2.name,
|
|
24099
|
+
kind: topic2.kind ?? null,
|
|
24100
|
+
memoryCount: 0,
|
|
24101
|
+
members: /* @__PURE__ */ new Set()
|
|
24102
|
+
});
|
|
24103
|
+
}
|
|
24104
|
+
return [...topics.values()].map(({ members, ...topic2 }) => ({ ...topic2, memoryCount: members.size })).sort((a, b) => a.name.localeCompare(b.name));
|
|
24105
|
+
})();
|
|
24106
|
+
topicSnapshot = snapshot;
|
|
24107
|
+
const clear = () => {
|
|
24108
|
+
if (topicSnapshot === snapshot) topicSnapshot = void 0;
|
|
24109
|
+
};
|
|
24110
|
+
void snapshot.then(() => {
|
|
24111
|
+
if (!retainTopics()) clear();
|
|
24112
|
+
}, clear);
|
|
24113
|
+
return snapshot.then((topics) => structuredClone(topics));
|
|
23865
24114
|
},
|
|
23866
24115
|
get: async (id2) => asStored(await live(id2)),
|
|
23867
24116
|
listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
|
|
@@ -24042,20 +24291,23 @@ function createRemoteMemoryStore(options) {
|
|
|
24042
24291
|
subscribe: (onChange, subscribeOptions = {}) => {
|
|
24043
24292
|
const subscriber = { onChange, options: subscribeOptions };
|
|
24044
24293
|
subscribers.add(subscriber);
|
|
24045
|
-
if (pollIntervalMs > 0 &&
|
|
24046
|
-
|
|
24047
|
-
|
|
24294
|
+
if (pollIntervalMs > 0 && subscribers.size === 1) {
|
|
24295
|
+
stopActivity = activity.subscribe(refreshActivity);
|
|
24296
|
+
refreshActivity();
|
|
24048
24297
|
}
|
|
24049
24298
|
return () => {
|
|
24050
24299
|
subscribers.delete(subscriber);
|
|
24051
|
-
if (
|
|
24052
|
-
|
|
24300
|
+
if (!retainTopics()) invalidateReads();
|
|
24301
|
+
if (subscribers.size) return;
|
|
24302
|
+
if (timer) clearTimeout(timer);
|
|
24053
24303
|
timer = void 0;
|
|
24304
|
+
stopActivity?.();
|
|
24305
|
+
stopActivity = void 0;
|
|
24306
|
+
stopChanges?.();
|
|
24307
|
+
stopChanges = void 0;
|
|
24308
|
+
changesConnected = false;
|
|
24054
24309
|
generation++;
|
|
24055
|
-
|
|
24056
|
-
ready = false;
|
|
24057
|
-
cursor = void 0;
|
|
24058
|
-
pending = /* @__PURE__ */ new Set();
|
|
24310
|
+
invalidateReads();
|
|
24059
24311
|
};
|
|
24060
24312
|
}
|
|
24061
24313
|
};
|