@anuma/sdk 7.0.7 → 7.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/README.md +10 -0
- package/dist/expo/index.cjs +224 -68
- package/dist/expo/index.d.mts +24 -4
- package/dist/expo/index.d.ts +24 -4
- package/dist/expo/index.mjs +224 -68
- package/dist/memory/context.d.mts +1 -0
- package/dist/memory/context.d.ts +1 -0
- package/dist/react/index.cjs +266 -84
- package/dist/react/index.d.mts +27 -4
- package/dist/react/index.d.ts +27 -4
- package/dist/react/index.mjs +266 -84
- package/dist/server/index.cjs +144 -28
- package/dist/server/index.d.mts +22 -2
- package/dist/server/index.d.ts +22 -2
- package/dist/server/index.mjs +144 -28
- package/package.json +1 -1
package/dist/react/index.cjs
CHANGED
|
@@ -12292,6 +12292,11 @@ function parseTopics(value) {
|
|
|
12292
12292
|
}
|
|
12293
12293
|
|
|
12294
12294
|
// src/lib/db/entities/operations.ts
|
|
12295
|
+
async function assertCanWrite(ctx) {
|
|
12296
|
+
if (ctx.canWrite && !await ctx.canWrite()) {
|
|
12297
|
+
throw new Error("Memory source is no longer eligible");
|
|
12298
|
+
}
|
|
12299
|
+
}
|
|
12295
12300
|
function entityToStored(e) {
|
|
12296
12301
|
return {
|
|
12297
12302
|
uniqueId: e.id,
|
|
@@ -12432,6 +12437,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
12432
12437
|
let skipped = false;
|
|
12433
12438
|
let entities = [];
|
|
12434
12439
|
await ctx.database.write(async () => {
|
|
12440
|
+
await assertCanWrite(ctx);
|
|
12435
12441
|
const {
|
|
12436
12442
|
entities: byName,
|
|
12437
12443
|
operations: entityOps,
|
|
@@ -12507,6 +12513,7 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
12507
12513
|
let skipped = false;
|
|
12508
12514
|
let entities = [];
|
|
12509
12515
|
await ctx.database.write(async () => {
|
|
12516
|
+
await assertCanWrite(ctx);
|
|
12510
12517
|
const vaultRow = await findVaultRowInWrite(ctx, memoryId);
|
|
12511
12518
|
if (options.guarded && autoLinkBlocked(vaultRow)) {
|
|
12512
12519
|
skipped = true;
|
|
@@ -12567,6 +12574,7 @@ async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
|
|
|
12567
12574
|
const links = await ctx.memoryEntityCollection.query(import_watermelondb11.Q.where("memory_id", import_watermelondb11.Q.oneOf(Array.from(memoryIds)))).fetch();
|
|
12568
12575
|
if (links.length === 0) return;
|
|
12569
12576
|
await ctx.database.write(async () => {
|
|
12577
|
+
await assertCanWrite(ctx);
|
|
12570
12578
|
await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
|
|
12571
12579
|
});
|
|
12572
12580
|
}
|
|
@@ -12575,6 +12583,7 @@ async function unlinkAllMemoryEntitiesForUserOp(ctx, userId) {
|
|
|
12575
12583
|
const links = await ctx.memoryEntityCollection.query(import_watermelondb11.Q.where("user_id", userId)).fetch();
|
|
12576
12584
|
if (links.length === 0) return;
|
|
12577
12585
|
await ctx.database.write(async () => {
|
|
12586
|
+
await assertCanWrite(ctx);
|
|
12578
12587
|
await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
|
|
12579
12588
|
});
|
|
12580
12589
|
}
|
|
@@ -12594,6 +12603,7 @@ async function backfillMemoryEntityUserIdsOp(ctx, vaultMemoryCollection) {
|
|
|
12594
12603
|
}
|
|
12595
12604
|
if (toUpdate.length === 0) return 0;
|
|
12596
12605
|
await ctx.database.write(async () => {
|
|
12606
|
+
await assertCanWrite(ctx);
|
|
12597
12607
|
await ctx.database.batch(
|
|
12598
12608
|
...toUpdate.map(({ link, userId }) => link.prepareUpdate((r) => r._setRaw("user_id", userId)))
|
|
12599
12609
|
);
|
|
@@ -14998,6 +15008,11 @@ function visibilityConditions(requested) {
|
|
|
14998
15008
|
function isKinded(record2) {
|
|
14999
15009
|
return record2.kind !== null && record2.kind !== void 0;
|
|
15000
15010
|
}
|
|
15011
|
+
async function assertCanWrite2(ctx) {
|
|
15012
|
+
if (ctx.canWrite && !await ctx.canWrite()) {
|
|
15013
|
+
throw new Error("Memory source is no longer eligible");
|
|
15014
|
+
}
|
|
15015
|
+
}
|
|
15001
15016
|
function assertValidKindLevel(kind, level) {
|
|
15002
15017
|
const hasKind = kind !== null && kind !== void 0;
|
|
15003
15018
|
if (hasKind && !MEMORY_KINDS.includes(kind)) {
|
|
@@ -15178,8 +15193,7 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
15178
15193
|
ctx.embeddedWalletSigner
|
|
15179
15194
|
) : opts.content;
|
|
15180
15195
|
const created = await ctx.database.write(async () => {
|
|
15181
|
-
|
|
15182
|
-
throw new Error("Memory source is no longer eligible");
|
|
15196
|
+
await assertCanWrite2(ctx);
|
|
15183
15197
|
return ctx.vaultMemoryCollection.create(
|
|
15184
15198
|
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
|
|
15185
15199
|
);
|
|
@@ -15198,8 +15212,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
15198
15212
|
) : opts.content;
|
|
15199
15213
|
let createdRecord = null;
|
|
15200
15214
|
await ctx.database.write(async () => {
|
|
15201
|
-
|
|
15202
|
-
throw new Error("Memory source is no longer eligible");
|
|
15215
|
+
await assertCanWrite2(ctx);
|
|
15203
15216
|
let target;
|
|
15204
15217
|
try {
|
|
15205
15218
|
target = await ctx.vaultMemoryCollection.find(targetId);
|
|
@@ -15291,8 +15304,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
15291
15304
|
})
|
|
15292
15305
|
);
|
|
15293
15306
|
const created = await ctx.database.write(async () => {
|
|
15294
|
-
|
|
15295
|
-
throw new Error("Memory source is no longer eligible");
|
|
15307
|
+
await assertCanWrite2(ctx);
|
|
15296
15308
|
const prepared = optionsArray.map(
|
|
15297
15309
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
15298
15310
|
(record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
|
|
@@ -15597,8 +15609,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
15597
15609
|
const record2 = probe;
|
|
15598
15610
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
15599
15611
|
await ctx.database.write(async () => {
|
|
15600
|
-
|
|
15601
|
-
throw new Error("Memory source is no longer eligible");
|
|
15612
|
+
await assertCanWrite2(ctx);
|
|
15602
15613
|
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
|
|
15603
15614
|
stale = true;
|
|
15604
15615
|
return;
|
|
@@ -15709,6 +15720,7 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
15709
15720
|
let stale = false;
|
|
15710
15721
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
15711
15722
|
await ctx.database.write(async (writer) => {
|
|
15723
|
+
await assertCanWrite2(ctx);
|
|
15712
15724
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
15713
15725
|
stale = true;
|
|
15714
15726
|
return;
|
|
@@ -15750,6 +15762,7 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
15750
15762
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
15751
15763
|
let cleared = false;
|
|
15752
15764
|
await ctx.database.write(async () => {
|
|
15765
|
+
await assertCanWrite2(ctx);
|
|
15753
15766
|
if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
|
|
15754
15767
|
cleared = true;
|
|
15755
15768
|
await record2.update((r) => {
|
|
@@ -15773,6 +15786,7 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
|
|
|
15773
15786
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
|
|
15774
15787
|
let stale = false;
|
|
15775
15788
|
await ctx.database.write(async () => {
|
|
15789
|
+
await assertCanWrite2(ctx);
|
|
15776
15790
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
15777
15791
|
stale = true;
|
|
15778
15792
|
return;
|
|
@@ -15801,6 +15815,7 @@ async function deleteVaultMemoryOp(ctx, id) {
|
|
|
15801
15815
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
15802
15816
|
let stale = false;
|
|
15803
15817
|
await ctx.database.write(async () => {
|
|
15818
|
+
await assertCanWrite2(ctx);
|
|
15804
15819
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
15805
15820
|
stale = true;
|
|
15806
15821
|
return;
|
|
@@ -15838,8 +15853,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
|
|
|
15838
15853
|
}
|
|
15839
15854
|
let stale = false;
|
|
15840
15855
|
await ctx.database.write(async () => {
|
|
15841
|
-
|
|
15842
|
-
throw new Error("Memory source is no longer eligible");
|
|
15856
|
+
await assertCanWrite2(ctx);
|
|
15843
15857
|
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
|
|
15844
15858
|
stale = true;
|
|
15845
15859
|
return;
|
|
@@ -16001,6 +16015,7 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
16001
16015
|
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
16002
16016
|
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
16003
16017
|
await ctx.database.write(async () => {
|
|
16018
|
+
await assertCanWrite2(ctx);
|
|
16004
16019
|
const records = [];
|
|
16005
16020
|
for (const id of chunkIds) {
|
|
16006
16021
|
try {
|
|
@@ -16034,6 +16049,7 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
16034
16049
|
for (const id of Array.from(new Set(memoryIds))) {
|
|
16035
16050
|
try {
|
|
16036
16051
|
await ctx.database.write(async (writer) => {
|
|
16052
|
+
await assertCanWrite2(ctx);
|
|
16037
16053
|
let record2;
|
|
16038
16054
|
try {
|
|
16039
16055
|
record2 = await ctx.vaultMemoryCollection.find(id);
|
|
@@ -16064,6 +16080,7 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
16064
16080
|
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
16065
16081
|
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
16066
16082
|
await ctx.database.write(async () => {
|
|
16083
|
+
await assertCanWrite2(ctx);
|
|
16067
16084
|
const writes = [];
|
|
16068
16085
|
for (const id of chunkIds) {
|
|
16069
16086
|
let record2;
|
|
@@ -16096,6 +16113,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
16096
16113
|
const records = await ctx.vaultMemoryCollection.query(import_watermelondb23.Q.where("user_id", userId), import_watermelondb23.Q.where("is_deleted", false)).fetch();
|
|
16097
16114
|
if (records.length === 0) return 0;
|
|
16098
16115
|
await ctx.database.write(async () => {
|
|
16116
|
+
await assertCanWrite2(ctx);
|
|
16099
16117
|
const prepared = records.map(
|
|
16100
16118
|
(record2) => record2.prepareUpdate((r) => {
|
|
16101
16119
|
r._setRaw("is_deleted", true);
|
|
@@ -16150,6 +16168,7 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
|
|
|
16150
16168
|
let stale = false;
|
|
16151
16169
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
16152
16170
|
await ctx.database.write(async () => {
|
|
16171
|
+
await assertCanWrite2(ctx);
|
|
16153
16172
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
|
|
16154
16173
|
stale = true;
|
|
16155
16174
|
return;
|
|
@@ -16173,6 +16192,7 @@ async function restoreVaultMemoryOp(ctx, id) {
|
|
|
16173
16192
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
|
|
16174
16193
|
let stale = false;
|
|
16175
16194
|
await ctx.database.write(async () => {
|
|
16195
|
+
await assertCanWrite2(ctx);
|
|
16176
16196
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
|
|
16177
16197
|
stale = true;
|
|
16178
16198
|
return;
|
|
@@ -16193,6 +16213,7 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
16193
16213
|
const now = opts.now ?? Date.now();
|
|
16194
16214
|
let stale = false;
|
|
16195
16215
|
await ctx.database.write(async () => {
|
|
16216
|
+
await assertCanWrite2(ctx);
|
|
16196
16217
|
const archivedAt = record2.archivedAt;
|
|
16197
16218
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
16198
16219
|
stale = true;
|
|
@@ -16232,6 +16253,7 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding2, embeddingModel,
|
|
|
16232
16253
|
}
|
|
16233
16254
|
let written = false;
|
|
16234
16255
|
await ctx.database.write(async () => {
|
|
16256
|
+
await assertCanWrite2(ctx);
|
|
16235
16257
|
if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
|
|
16236
16258
|
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
16237
16259
|
if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
|
|
@@ -20228,6 +20250,13 @@ function restoreCandidates(candidates, redactor, ownNames) {
|
|
|
20228
20250
|
).map((c) => c.candidate);
|
|
20229
20251
|
}
|
|
20230
20252
|
async function extractAndRetain(messages, retainCtx, options) {
|
|
20253
|
+
const { memoryStore, signal } = options;
|
|
20254
|
+
if (memoryStore === null) throw new Error("Memory store is not ready");
|
|
20255
|
+
if (memoryStore && options.folderId !== void 0 && options.folderId !== null)
|
|
20256
|
+
throw new Error("Remote memory extraction does not support folders");
|
|
20257
|
+
if (memoryStore && options.extract.piiRedaction && !memoryStore.masksEmbeddingInput)
|
|
20258
|
+
throw new Error("PII-redacted extraction requires a memory store that masks embedding inputs");
|
|
20259
|
+
signal?.throwIfAborted();
|
|
20231
20260
|
const minConfidence = options.minConfidence ?? DEFAULT_MIN_CONFIDENCE;
|
|
20232
20261
|
const resolvedConsolidatePii = options.consolidateOptions?.piiRedaction ?? options.extract.piiRedaction;
|
|
20233
20262
|
const consolidateOptions = options.consolidateOptions !== void 0 ? {
|
|
@@ -20261,6 +20290,7 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
20261
20290
|
}
|
|
20262
20291
|
});
|
|
20263
20292
|
const extractMs = Date.now() - tExtract;
|
|
20293
|
+
signal?.throwIfAborted();
|
|
20264
20294
|
const filtered = candidates.filter((c) => c.confidence >= minConfidence);
|
|
20265
20295
|
const log = getLogger();
|
|
20266
20296
|
const screened = screenCandidatesForInjection(filtered);
|
|
@@ -20308,16 +20338,33 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
20308
20338
|
const results = [];
|
|
20309
20339
|
const quarantinedInfo = [];
|
|
20310
20340
|
let failedWrites = 0;
|
|
20341
|
+
let auditRows;
|
|
20311
20342
|
const tRetain = Date.now();
|
|
20312
20343
|
for (const { candidate, isQuarantined, reason, signature } of toRetain) {
|
|
20313
20344
|
try {
|
|
20345
|
+
signal?.throwIfAborted();
|
|
20314
20346
|
if (isQuarantined) {
|
|
20315
|
-
|
|
20316
|
-
|
|
20317
|
-
|
|
20318
|
-
|
|
20319
|
-
|
|
20320
|
-
|
|
20347
|
+
let existingId;
|
|
20348
|
+
if (memoryStore) {
|
|
20349
|
+
auditRows ?? (auditRows = memoryStore.list({
|
|
20350
|
+
scopes: [options.scope ?? "private"],
|
|
20351
|
+
includeArchived: true,
|
|
20352
|
+
includeQuarantined: true,
|
|
20353
|
+
includeSuperseded: true
|
|
20354
|
+
}));
|
|
20355
|
+
const sourceKey = [...new Set(candidate.sourceMessageIds)].sort().join("\0");
|
|
20356
|
+
const normalize = (value) => value.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
20357
|
+
existingId = (await auditRows).find(
|
|
20358
|
+
(row) => row.trustTier === "quarantined" && row.scope === (options.scope ?? "private") && [...new Set(row.sourceChunkIds ?? [])].sort().join("\0") === sourceKey && normalize(row.content) === normalize(candidate.content)
|
|
20359
|
+
)?.uniqueId ?? null;
|
|
20360
|
+
} else {
|
|
20361
|
+
existingId = await findQuarantinedDuplicateOp(
|
|
20362
|
+
retainCtx.vaultCtx,
|
|
20363
|
+
candidate.content,
|
|
20364
|
+
candidate.sourceMessageIds,
|
|
20365
|
+
{ scope: options.scope ?? "private", folderId: options.folderId ?? null }
|
|
20366
|
+
).catch(() => null);
|
|
20367
|
+
}
|
|
20321
20368
|
if (existingId) {
|
|
20322
20369
|
quarantinedInfo.push({
|
|
20323
20370
|
candidate,
|
|
@@ -20328,18 +20375,26 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
20328
20375
|
continue;
|
|
20329
20376
|
}
|
|
20330
20377
|
}
|
|
20331
|
-
const
|
|
20378
|
+
const retainOptions = {
|
|
20332
20379
|
source: "auto-extracted",
|
|
20333
20380
|
sourceChunkIds: candidate.sourceMessageIds,
|
|
20334
20381
|
respectTombstones: true,
|
|
20335
20382
|
...options.scope !== void 0 && { scope: options.scope },
|
|
20336
|
-
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
20337
20383
|
...consolidateOptions !== void 0 && { consolidateOptions },
|
|
20338
20384
|
...candidate.eventTime !== null && { eventTime: candidate.eventTime },
|
|
20339
20385
|
factType: candidate.type,
|
|
20340
20386
|
...isQuarantined && { trustTier: "quarantined", enableAutoMerge: false }
|
|
20387
|
+
};
|
|
20388
|
+
const result = memoryStore ? await memoryStore.retain(candidate.content, {
|
|
20389
|
+
...retainOptions,
|
|
20390
|
+
canWrite: retainCtx.vaultCtx.canWrite,
|
|
20391
|
+
signal
|
|
20392
|
+
}) : await retain(candidate.content, retainCtx, {
|
|
20393
|
+
...retainOptions,
|
|
20394
|
+
...options.folderId !== void 0 && { folderId: options.folderId }
|
|
20341
20395
|
});
|
|
20342
20396
|
if (isQuarantined) {
|
|
20397
|
+
auditRows = void 0;
|
|
20343
20398
|
const info = {
|
|
20344
20399
|
candidate,
|
|
20345
20400
|
memoryId: result.memoryId,
|
|
@@ -20358,9 +20413,16 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
20358
20413
|
}
|
|
20359
20414
|
succeededCandidates.push(candidate);
|
|
20360
20415
|
results.push(result);
|
|
20361
|
-
if (result.action !== "suppressed" &&
|
|
20416
|
+
if (result.action !== "suppressed" && candidate.entities.length > 0) {
|
|
20362
20417
|
try {
|
|
20363
|
-
|
|
20418
|
+
signal?.throwIfAborted();
|
|
20419
|
+
if (memoryStore) {
|
|
20420
|
+
await memoryStore.addTopics(result.memoryId, candidate.entities, {
|
|
20421
|
+
unlessUserManaged: true,
|
|
20422
|
+
canWrite: retainCtx.vaultCtx.canWrite,
|
|
20423
|
+
signal
|
|
20424
|
+
});
|
|
20425
|
+
} else if (options.entityCtx && !await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
|
|
20364
20426
|
await linkMemoryEntitiesOp(options.entityCtx, result.memoryId, candidate.entities, {
|
|
20365
20427
|
unlessTopicsUserManaged: true
|
|
20366
20428
|
});
|
|
@@ -20610,7 +20672,7 @@ function createAutoExtractor(options) {
|
|
|
20610
20672
|
};
|
|
20611
20673
|
const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
|
|
20612
20674
|
const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
|
|
20613
|
-
if (options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
|
|
20675
|
+
if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
|
|
20614
20676
|
getLogger().warn(
|
|
20615
20677
|
"[memory/extract] retainCtx.vaultCtx.entityCtx is set but extractor was created without `entityCtx` \u2014 W5 graph lane will receive no writes"
|
|
20616
20678
|
);
|
|
@@ -20655,6 +20717,8 @@ function createAutoExtractor(options) {
|
|
|
20655
20717
|
try {
|
|
20656
20718
|
const { candidates, results, failedCount, outcome: outcome2, failure, funnel, timings, model } = await extractAndRetain(window2, retainCtx, {
|
|
20657
20719
|
extract,
|
|
20720
|
+
memoryStore: options.memoryStore,
|
|
20721
|
+
signal: options.signal,
|
|
20658
20722
|
...options.minConfidence !== void 0 && { minConfidence: options.minConfidence },
|
|
20659
20723
|
...options.entityCtx !== void 0 && { entityCtx: options.entityCtx },
|
|
20660
20724
|
...options.scope !== void 0 && { scope: options.scope },
|
|
@@ -22786,6 +22850,7 @@ function createLocalMemoryStore(options) {
|
|
|
22786
22850
|
database,
|
|
22787
22851
|
entityCollection: database.get("entity"),
|
|
22788
22852
|
memoryEntityCollection: database.get("memory_entity"),
|
|
22853
|
+
canWrite: options.canWrite,
|
|
22789
22854
|
...userId !== void 0 && { userId },
|
|
22790
22855
|
...options.allowUnscopedRows !== void 0 && {
|
|
22791
22856
|
allowUnscopedRows: options.allowUnscopedRows
|
|
@@ -22797,10 +22862,21 @@ function createLocalMemoryStore(options) {
|
|
|
22797
22862
|
walletAddress: options.walletAddress,
|
|
22798
22863
|
signMessage: options.signMessage,
|
|
22799
22864
|
embeddedWalletSigner: options.embeddedWalletSigner,
|
|
22865
|
+
canWrite: options.canWrite,
|
|
22800
22866
|
...userId !== void 0 && { userId },
|
|
22801
22867
|
...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
|
|
22802
22868
|
entityCtx
|
|
22803
22869
|
};
|
|
22870
|
+
const assertWrite = async (writeOptions) => {
|
|
22871
|
+
writeOptions?.signal?.throwIfAborted();
|
|
22872
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite()) {
|
|
22873
|
+
throw new Error("Memory source is no longer eligible");
|
|
22874
|
+
}
|
|
22875
|
+
if (options.canWrite && !await options.canWrite()) {
|
|
22876
|
+
throw new Error("Memory source is no longer eligible");
|
|
22877
|
+
}
|
|
22878
|
+
writeOptions?.signal?.throwIfAborted();
|
|
22879
|
+
};
|
|
22804
22880
|
const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
|
|
22805
22881
|
const ownedBy = userId !== void 0 ? [import_watermelondb32.Q.where("user_id", userId)] : [];
|
|
22806
22882
|
const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [import_watermelondb32.Q.or(import_watermelondb32.Q.where("user_id", userId), import_watermelondb32.Q.where("user_id", null))] : [import_watermelondb32.Q.where("user_id", userId)];
|
|
@@ -22912,9 +22988,25 @@ function createLocalMemoryStore(options) {
|
|
|
22912
22988
|
archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
|
|
22913
22989
|
restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
|
|
22914
22990
|
setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
|
|
22915
|
-
addTopics: (memoryId, topics) => database.write(async (writer) => {
|
|
22991
|
+
addTopics: (memoryId, topics, writeOptions) => database.write(async (writer) => {
|
|
22992
|
+
await assertWrite(writeOptions);
|
|
22916
22993
|
const owned = await vaultCtx.vaultMemoryCollection.query(import_watermelondb32.Q.where("id", memoryId), import_watermelondb32.Q.where("is_deleted", false), ...ownedBy).fetchCount();
|
|
22917
|
-
return owned > 0 ? writer.callWriter(
|
|
22994
|
+
return owned > 0 ? writer.callWriter(
|
|
22995
|
+
() => linkMemoryEntitiesOp(
|
|
22996
|
+
{
|
|
22997
|
+
...entityCtx,
|
|
22998
|
+
canWrite: async () => {
|
|
22999
|
+
await assertWrite(writeOptions);
|
|
23000
|
+
return true;
|
|
23001
|
+
}
|
|
23002
|
+
},
|
|
23003
|
+
memoryId,
|
|
23004
|
+
topics,
|
|
23005
|
+
{
|
|
23006
|
+
unlessTopicsUserManaged: writeOptions?.unlessUserManaged
|
|
23007
|
+
}
|
|
23008
|
+
)
|
|
23009
|
+
) : [];
|
|
22918
23010
|
}),
|
|
22919
23011
|
setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
|
|
22920
23012
|
recall: (query, recallOptions) => recall(
|
|
@@ -22924,7 +23016,17 @@ function createLocalMemoryStore(options) {
|
|
|
22924
23016
|
),
|
|
22925
23017
|
retain: (content, retainOptions) => retain(
|
|
22926
23018
|
content,
|
|
22927
|
-
{
|
|
23019
|
+
{
|
|
23020
|
+
vaultCtx: {
|
|
23021
|
+
...vaultCtx,
|
|
23022
|
+
canWrite: async () => {
|
|
23023
|
+
await assertWrite(retainOptions);
|
|
23024
|
+
return true;
|
|
23025
|
+
}
|
|
23026
|
+
},
|
|
23027
|
+
embeddingOptions: options.embeddingOptions,
|
|
23028
|
+
vaultCache
|
|
23029
|
+
},
|
|
22928
23030
|
retainOptions
|
|
22929
23031
|
),
|
|
22930
23032
|
factSource: {
|
|
@@ -23579,7 +23681,14 @@ function stored(row) {
|
|
|
23579
23681
|
function createRemoteMemoryPipeline(options) {
|
|
23580
23682
|
const { persistence, embeddingOptions } = options;
|
|
23581
23683
|
const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
23582
|
-
const operation = (mode, queryOptions = embeddingOptions) => {
|
|
23684
|
+
const operation = (mode, queryOptions = embeddingOptions, writeOptions) => {
|
|
23685
|
+
const signal = writeOptions?.signal;
|
|
23686
|
+
const assertWrite = async () => {
|
|
23687
|
+
signal?.throwIfAborted();
|
|
23688
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
23689
|
+
throw new Error("Memory source is no longer eligible");
|
|
23690
|
+
signal?.throwIfAborted();
|
|
23691
|
+
};
|
|
23583
23692
|
const rejectUndecryptable = (failed) => {
|
|
23584
23693
|
if (!failed.length) return;
|
|
23585
23694
|
if (mode === "retain")
|
|
@@ -23597,7 +23706,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
23597
23706
|
return items.map((item) => stored(item.memory));
|
|
23598
23707
|
};
|
|
23599
23708
|
const get = async (id) => {
|
|
23600
|
-
const snapshot = snapshots.get(id) ?? await persistence.get(id);
|
|
23709
|
+
const snapshot = snapshots.get(id) ?? await (signal ? persistence.get(id, signal) : persistence.get(id));
|
|
23601
23710
|
if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
|
|
23602
23711
|
snapshots.set(id, snapshot);
|
|
23603
23712
|
return stored(snapshot.memory);
|
|
@@ -23647,7 +23756,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
23647
23756
|
if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
|
|
23648
23757
|
}
|
|
23649
23758
|
const forceIds = [...forced];
|
|
23650
|
-
const windowOptions = (i,
|
|
23759
|
+
const windowOptions = (i, signal2) => ({
|
|
23651
23760
|
limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
|
|
23652
23761
|
force_ids: i === 0 ? forceIds : [],
|
|
23653
23762
|
...search.scopes && { scopes: search.scopes },
|
|
@@ -23655,13 +23764,15 @@ function createRemoteMemoryPipeline(options) {
|
|
|
23655
23764
|
...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
|
|
23656
23765
|
include_archived: search.includeArchived,
|
|
23657
23766
|
embedding_model: model,
|
|
23658
|
-
...
|
|
23767
|
+
...signal2 && { signal: signal2 }
|
|
23659
23768
|
});
|
|
23660
23769
|
const vectors = [queryEmbedding, ...facetEmbeddings];
|
|
23661
23770
|
let windows;
|
|
23662
23771
|
if (mode === "retain") {
|
|
23663
23772
|
windows = await Promise.all(
|
|
23664
|
-
vectors.map(
|
|
23773
|
+
vectors.map(
|
|
23774
|
+
(embedding2, i) => persistence.candidateSet(embedding2, windowOptions(i, signal))
|
|
23775
|
+
)
|
|
23665
23776
|
);
|
|
23666
23777
|
} else {
|
|
23667
23778
|
const deadline = new AbortController();
|
|
@@ -23749,12 +23860,15 @@ function createRemoteMemoryPipeline(options) {
|
|
|
23749
23860
|
twin_opt_in: false
|
|
23750
23861
|
};
|
|
23751
23862
|
};
|
|
23752
|
-
const write = async (memory, snapshot) =>
|
|
23863
|
+
const write = async (memory, snapshot) => {
|
|
23864
|
+
await assertWrite();
|
|
23865
|
+
return remember([await persistence.put(memory, snapshot, signal)])[0];
|
|
23866
|
+
};
|
|
23753
23867
|
const port = {
|
|
23754
23868
|
prepare,
|
|
23755
23869
|
get,
|
|
23756
23870
|
getFresh: async (id) => {
|
|
23757
|
-
const current = await persistence.get(id);
|
|
23871
|
+
const current = await (signal ? persistence.get(id, signal) : persistence.get(id));
|
|
23758
23872
|
return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
|
|
23759
23873
|
},
|
|
23760
23874
|
tombstones: async (embedding2, embeddingModel, scope, folderId) => {
|
|
@@ -23765,7 +23879,8 @@ function createRemoteMemoryPipeline(options) {
|
|
|
23765
23879
|
embedding_model: embeddingModel,
|
|
23766
23880
|
strict_model: true,
|
|
23767
23881
|
include_deleted: true,
|
|
23768
|
-
deleted_only: true
|
|
23882
|
+
deleted_only: true,
|
|
23883
|
+
signal
|
|
23769
23884
|
});
|
|
23770
23885
|
rejectUndecryptable(window2.failed);
|
|
23771
23886
|
return remember(window2.items);
|
|
@@ -23821,14 +23936,18 @@ function createRemoteMemoryPipeline(options) {
|
|
|
23821
23936
|
if (!target || !newer || id === successor) return false;
|
|
23822
23937
|
const old = snapshots.get(id);
|
|
23823
23938
|
const next = snapshots.get(successor);
|
|
23939
|
+
await assertWrite();
|
|
23824
23940
|
remember(
|
|
23825
|
-
await persistence.putMany(
|
|
23826
|
-
|
|
23827
|
-
|
|
23828
|
-
|
|
23829
|
-
|
|
23830
|
-
|
|
23831
|
-
|
|
23941
|
+
await persistence.putMany(
|
|
23942
|
+
[
|
|
23943
|
+
{
|
|
23944
|
+
memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
|
|
23945
|
+
expectedVersion: old
|
|
23946
|
+
},
|
|
23947
|
+
{ memory: next.memory, expectedVersion: next }
|
|
23948
|
+
],
|
|
23949
|
+
signal
|
|
23950
|
+
)
|
|
23832
23951
|
);
|
|
23833
23952
|
return true;
|
|
23834
23953
|
},
|
|
@@ -23837,18 +23956,22 @@ function createRemoteMemoryPipeline(options) {
|
|
|
23837
23956
|
if (!target) return { created: null, retired: false };
|
|
23838
23957
|
const snapshot = snapshots.get(targetId);
|
|
23839
23958
|
const successor = createRow(input);
|
|
23959
|
+
await assertWrite();
|
|
23840
23960
|
const rows = remember(
|
|
23841
|
-
await persistence.putMany(
|
|
23842
|
-
|
|
23843
|
-
|
|
23844
|
-
|
|
23845
|
-
|
|
23846
|
-
|
|
23847
|
-
|
|
23848
|
-
|
|
23849
|
-
|
|
23850
|
-
|
|
23851
|
-
|
|
23961
|
+
await persistence.putMany(
|
|
23962
|
+
[
|
|
23963
|
+
{ memory: successor, expectedVersion: 0 },
|
|
23964
|
+
{
|
|
23965
|
+
memory: {
|
|
23966
|
+
...snapshot.memory,
|
|
23967
|
+
superseded_by: successor.memory_id,
|
|
23968
|
+
superseded_at: Date.now()
|
|
23969
|
+
},
|
|
23970
|
+
expectedVersion: snapshot
|
|
23971
|
+
}
|
|
23972
|
+
],
|
|
23973
|
+
signal
|
|
23974
|
+
)
|
|
23852
23975
|
);
|
|
23853
23976
|
return { created: rows[0], retired: true };
|
|
23854
23977
|
}
|
|
@@ -23883,7 +24006,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
23883
24006
|
factSource,
|
|
23884
24007
|
recall: async (query, recallOptions = {}) => recall(query, { embeddingOptions, factSource }, { ...recallOptions, types: ["fact"] }),
|
|
23885
24008
|
retain: async (content, retainOptions) => {
|
|
23886
|
-
const { port } = operation("retain");
|
|
24009
|
+
const { port } = operation("retain", embeddingOptions, retainOptions);
|
|
23887
24010
|
return retainWithPersistence(
|
|
23888
24011
|
content,
|
|
23889
24012
|
{
|
|
@@ -24545,16 +24668,21 @@ function createRemoteMemoryStore(options) {
|
|
|
24545
24668
|
const record2 = await persistence.get(id);
|
|
24546
24669
|
return record2 && !record2.memory.is_deleted ? record2 : null;
|
|
24547
24670
|
};
|
|
24548
|
-
const mutateLocked = async (id, change, edit) => {
|
|
24549
|
-
|
|
24671
|
+
const mutateLocked = async (id, change, edit, writeOptions) => {
|
|
24672
|
+
writeOptions?.signal?.throwIfAborted();
|
|
24673
|
+
const record2 = writeOptions?.signal ? await persistence.get(id, writeOptions.signal) : await live(id);
|
|
24550
24674
|
if (!record2) return null;
|
|
24675
|
+
if (record2.memory.is_deleted) return null;
|
|
24676
|
+
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
24677
|
+
throw new Error("Memory source is no longer eligible");
|
|
24678
|
+
writeOptions?.signal?.throwIfAborted();
|
|
24551
24679
|
const next = edit(structuredClone(record2.memory));
|
|
24552
24680
|
if (!next) return null;
|
|
24553
|
-
const saved = await persistence.put(next, record2);
|
|
24681
|
+
const saved = writeOptions?.signal ? await persistence.put(next, record2, writeOptions.signal) : await persistence.put(next, record2);
|
|
24554
24682
|
notify(typeof change === "function" ? change(record2.memory) : change, [saved]);
|
|
24555
24683
|
return saved;
|
|
24556
24684
|
};
|
|
24557
|
-
const mutate = (id, change, edit) => serialized(id, () => mutateLocked(id, change, edit));
|
|
24685
|
+
const mutate = (id, change, edit, writeOptions) => serialized(id, () => mutateLocked(id, change, edit, writeOptions));
|
|
24558
24686
|
const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id) => () => serialized(id, inner), task)();
|
|
24559
24687
|
const mutateMany = async (ids, change, edit) => {
|
|
24560
24688
|
const saved = /* @__PURE__ */ new Map();
|
|
@@ -25067,13 +25195,21 @@ function createRemoteMemoryStore(options) {
|
|
|
25067
25195
|
}))
|
|
25068
25196
|
);
|
|
25069
25197
|
},
|
|
25070
|
-
addTopics: async (memoryId, topics) => {
|
|
25198
|
+
addTopics: async (memoryId, topics, writeOptions) => {
|
|
25071
25199
|
const added = await withKnownKinds(topicInputs(topics, "auto"));
|
|
25072
|
-
const saved = await mutate(
|
|
25073
|
-
|
|
25074
|
-
|
|
25075
|
-
|
|
25076
|
-
|
|
25200
|
+
const saved = await mutate(
|
|
25201
|
+
memoryId,
|
|
25202
|
+
"edit",
|
|
25203
|
+
(memory) => {
|
|
25204
|
+
if (writeOptions?.unlessUserManaged && memory.topics_user_managed) return null;
|
|
25205
|
+
return {
|
|
25206
|
+
...memory,
|
|
25207
|
+
topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
|
|
25208
|
+
topics_updated_at: Date.now()
|
|
25209
|
+
};
|
|
25210
|
+
},
|
|
25211
|
+
writeOptions
|
|
25212
|
+
);
|
|
25077
25213
|
if (!saved) return [];
|
|
25078
25214
|
const now = /* @__PURE__ */ new Date();
|
|
25079
25215
|
return mergeTopics([], added).map(
|
|
@@ -25926,6 +26062,7 @@ function createDurableAutoExtractor(options) {
|
|
|
25926
26062
|
};
|
|
25927
26063
|
const folderId = options.folderId ?? null;
|
|
25928
26064
|
let disposed = false;
|
|
26065
|
+
let activeBatch = null;
|
|
25929
26066
|
let running = false;
|
|
25930
26067
|
let wakeRequested = false;
|
|
25931
26068
|
let timer;
|
|
@@ -25962,14 +26099,18 @@ function createDurableAutoExtractor(options) {
|
|
|
25962
26099
|
}, delay);
|
|
25963
26100
|
}
|
|
25964
26101
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
26102
|
+
if (disposed) throw new Error("Extraction session was disposed");
|
|
25965
26103
|
let watchdog;
|
|
25966
26104
|
let cancelled = false;
|
|
26105
|
+
const controller = new AbortController();
|
|
26106
|
+
activeBatch = controller;
|
|
25967
26107
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
25968
26108
|
try {
|
|
25969
26109
|
return await Promise.race([
|
|
25970
26110
|
new Promise((resolve, reject) => {
|
|
25971
26111
|
const worker = createAutoExtractor({
|
|
25972
26112
|
...options,
|
|
26113
|
+
signal: controller.signal,
|
|
25973
26114
|
retainCtx: {
|
|
25974
26115
|
...options.retainCtx,
|
|
25975
26116
|
vaultCtx: {
|
|
@@ -25998,6 +26139,8 @@ function createDurableAutoExtractor(options) {
|
|
|
25998
26139
|
]);
|
|
25999
26140
|
} finally {
|
|
26000
26141
|
cancelled = true;
|
|
26142
|
+
controller.abort();
|
|
26143
|
+
if (activeBatch === controller) activeBatch = null;
|
|
26001
26144
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
26002
26145
|
}
|
|
26003
26146
|
}
|
|
@@ -26009,6 +26152,7 @@ function createDurableAutoExtractor(options) {
|
|
|
26009
26152
|
for (const message of loaded)
|
|
26010
26153
|
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
26011
26154
|
await database.write(async () => {
|
|
26155
|
+
if (disposed) return;
|
|
26012
26156
|
const current = idsOf(job);
|
|
26013
26157
|
const acknowledged = ids.filter((id) => current.includes(id));
|
|
26014
26158
|
if (!acknowledged.length) return;
|
|
@@ -26181,6 +26325,7 @@ function createDurableAutoExtractor(options) {
|
|
|
26181
26325
|
jobScope,
|
|
26182
26326
|
jobFolderId
|
|
26183
26327
|
);
|
|
26328
|
+
if (disposed) throw new Error("Extraction session was disposed");
|
|
26184
26329
|
options.onTurnComplete?.(result);
|
|
26185
26330
|
return result;
|
|
26186
26331
|
};
|
|
@@ -26217,6 +26362,7 @@ function createDurableAutoExtractor(options) {
|
|
|
26217
26362
|
);
|
|
26218
26363
|
scheduleAfterSuccess = true;
|
|
26219
26364
|
} catch (error) {
|
|
26365
|
+
if (disposed) break;
|
|
26220
26366
|
attempts.set(job.id, attempted + 1);
|
|
26221
26367
|
retry = true;
|
|
26222
26368
|
reportError(error, conversationId);
|
|
@@ -26239,6 +26385,14 @@ function createDurableAutoExtractor(options) {
|
|
|
26239
26385
|
schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
|
|
26240
26386
|
}
|
|
26241
26387
|
}
|
|
26388
|
+
function dispose() {
|
|
26389
|
+
disposed = true;
|
|
26390
|
+
activeBatch?.abort(options.signal?.reason);
|
|
26391
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
26392
|
+
options.signal?.removeEventListener("abort", dispose);
|
|
26393
|
+
}
|
|
26394
|
+
if (options.signal?.aborted) dispose();
|
|
26395
|
+
else options.signal?.addEventListener("abort", dispose, { once: true });
|
|
26242
26396
|
schedule(0);
|
|
26243
26397
|
return {
|
|
26244
26398
|
processTurn(messages, conversationId) {
|
|
@@ -26318,10 +26472,7 @@ function createDurableAutoExtractor(options) {
|
|
|
26318
26472
|
return true;
|
|
26319
26473
|
},
|
|
26320
26474
|
isProcessing: () => running,
|
|
26321
|
-
dispose
|
|
26322
|
-
disposed = true;
|
|
26323
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
26324
|
-
}
|
|
26475
|
+
dispose
|
|
26325
26476
|
};
|
|
26326
26477
|
}
|
|
26327
26478
|
|
|
@@ -30817,7 +30968,7 @@ async function requestICloudSignIn() {
|
|
|
30817
30968
|
}
|
|
30818
30969
|
return container.whenUserSignsIn();
|
|
30819
30970
|
}
|
|
30820
|
-
async function uploadFileToICloud(filename, content) {
|
|
30971
|
+
async function uploadFileToICloud(filename, content, backupRevision) {
|
|
30821
30972
|
const container = await getContainer();
|
|
30822
30973
|
const database = container.privateCloudDatabase;
|
|
30823
30974
|
const recordName = `backup_${filename.replace(/[^a-zA-Z0-9]/g, "_")}`;
|
|
@@ -30830,7 +30981,8 @@ async function uploadFileToICloud(filename, content) {
|
|
|
30830
30981
|
filename: { value: filename },
|
|
30831
30982
|
data: { value: base64Data },
|
|
30832
30983
|
size: { value: content.size },
|
|
30833
|
-
contentType: { value: content.type || "application/json" }
|
|
30984
|
+
contentType: { value: content.type || "application/json" },
|
|
30985
|
+
...backupRevision ? { backupRevision: { value: backupRevision } } : {}
|
|
30834
30986
|
}
|
|
30835
30987
|
};
|
|
30836
30988
|
const response = await database.saveRecords(record2);
|
|
@@ -30842,7 +30994,8 @@ async function uploadFileToICloud(filename, content) {
|
|
|
30842
30994
|
recordName: savedRecord.recordName,
|
|
30843
30995
|
filename,
|
|
30844
30996
|
modifiedAt: new Date(savedRecord.modified?.timestamp ?? Date.now()),
|
|
30845
|
-
size: content.size
|
|
30997
|
+
size: content.size,
|
|
30998
|
+
backupRevision: savedRecord.fields.backupRevision?.value
|
|
30846
30999
|
};
|
|
30847
31000
|
}
|
|
30848
31001
|
async function listICloudFiles() {
|
|
@@ -30863,6 +31016,7 @@ async function listICloudFiles() {
|
|
|
30863
31016
|
recordName: record2.recordName,
|
|
30864
31017
|
filename: record2.fields.filename?.value ?? "",
|
|
30865
31018
|
modifiedAt: new Date(record2.modified?.timestamp ?? Date.now()),
|
|
31019
|
+
backupRevision: record2.fields.backupRevision?.value,
|
|
30866
31020
|
size: typeof record2.fields.data?.value === "object" && record2.fields.data?.value !== null ? record2.fields.data.value.size : 0
|
|
30867
31021
|
}));
|
|
30868
31022
|
return files.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
|
|
@@ -30916,35 +31070,53 @@ async function findICloudFile(filename) {
|
|
|
30916
31070
|
recordName: record2.recordName,
|
|
30917
31071
|
filename: record2.fields.filename?.value ?? "",
|
|
30918
31072
|
modifiedAt: new Date(record2.modified?.timestamp ?? Date.now()),
|
|
31073
|
+
backupRevision: record2.fields.backupRevision?.value,
|
|
30919
31074
|
size: typeof record2.fields.data?.value === "object" && record2.fields.data?.value !== null ? record2.fields.data.value.size : 0
|
|
30920
31075
|
};
|
|
30921
31076
|
}
|
|
30922
31077
|
|
|
30923
31078
|
// src/lib/backup/icloud/backup.ts
|
|
30924
31079
|
var isAuthError = (err) => err instanceof Error && (err.message.includes("AUTHENTICATION") || err.message.includes("NOT_AUTHENTICATED") || err.message.includes("sign in"));
|
|
31080
|
+
var UNREVISIONED_COLUMNS = /* @__PURE__ */ new Set([
|
|
31081
|
+
"updated_at",
|
|
31082
|
+
"vector",
|
|
31083
|
+
"embedding_model",
|
|
31084
|
+
"chunks",
|
|
31085
|
+
"origin"
|
|
31086
|
+
]);
|
|
31087
|
+
async function getBackupRevision(database, conversationId) {
|
|
31088
|
+
const serialized = await database.read(async () => {
|
|
31089
|
+
const { Q: Q20 } = await import("@nozbe/watermelondb");
|
|
31090
|
+
const tables = await Promise.all(
|
|
31091
|
+
["conversations", "history"].map(
|
|
31092
|
+
(table) => database.get(table).query(Q20.where("conversation_id", conversationId), Q20.sortBy("id", Q20.asc)).unsafeFetchRaw()
|
|
31093
|
+
)
|
|
31094
|
+
);
|
|
31095
|
+
return JSON.stringify(
|
|
31096
|
+
tables.map(
|
|
31097
|
+
(rows) => rows.map(
|
|
31098
|
+
(row) => Object.entries(row).filter(([key]) => !key.startsWith("_") && !UNREVISIONED_COLUMNS.has(key)).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
|
|
31099
|
+
)
|
|
31100
|
+
)
|
|
31101
|
+
);
|
|
31102
|
+
});
|
|
31103
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(serialized));
|
|
31104
|
+
return "v1:" + Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
31105
|
+
}
|
|
30925
31106
|
async function pushConversationToICloud(database, conversationId, userAddress, deps, _retried = false) {
|
|
30926
31107
|
try {
|
|
30927
31108
|
await deps.requestEncryptionKey(userAddress);
|
|
30928
31109
|
const filename = `${conversationId}.json`;
|
|
30929
31110
|
const existingFile = await findICloudFile(filename);
|
|
30930
|
-
|
|
30931
|
-
|
|
30932
|
-
|
|
30933
|
-
const records = await conversationsCollection.query(Q20.where("conversation_id", conversationId)).fetch();
|
|
30934
|
-
if (records.length > 0) {
|
|
30935
|
-
const conversation = conversationToStoredRaw(records[0]);
|
|
30936
|
-
const localUpdated = conversation.updatedAt.getTime();
|
|
30937
|
-
const remoteModified = existingFile.modifiedAt.getTime();
|
|
30938
|
-
if (localUpdated <= remoteModified) {
|
|
30939
|
-
return "skipped";
|
|
30940
|
-
}
|
|
30941
|
-
}
|
|
31111
|
+
const backupRevision = await getBackupRevision(database, conversationId);
|
|
31112
|
+
if (existingFile?.backupRevision === backupRevision) {
|
|
31113
|
+
return "skipped";
|
|
30942
31114
|
}
|
|
30943
31115
|
const exportResult = await deps.exportConversation(conversationId, userAddress);
|
|
30944
31116
|
if (!exportResult.success || !exportResult.blob) {
|
|
30945
31117
|
return "failed";
|
|
30946
31118
|
}
|
|
30947
|
-
await uploadFileToICloud(filename, exportResult.blob);
|
|
31119
|
+
await uploadFileToICloud(filename, exportResult.blob, backupRevision);
|
|
30948
31120
|
return "uploaded";
|
|
30949
31121
|
} catch (err) {
|
|
30950
31122
|
if (isAuthError(err) && !_retried) {
|
|
@@ -32592,6 +32764,7 @@ var CONVERSATION_REDACTOR_LIMIT = 50;
|
|
|
32592
32764
|
var NO_CONVERSATION_KEY = "__no_conversation__";
|
|
32593
32765
|
var NO_STORE_FOLDERS = "Folders are not supported with a memoryStore";
|
|
32594
32766
|
var NO_STORE_MASK = "piiRedaction needs a memoryStore built with embeddingOptions.maskInput";
|
|
32767
|
+
var MEMORY_STORE_NOT_READY = "Memory store is not ready";
|
|
32595
32768
|
var conversationRedactors = /* @__PURE__ */ new Map();
|
|
32596
32769
|
function getConversationRedactor(conversationId, nerDetector) {
|
|
32597
32770
|
const key = conversationId ?? NO_CONVERSATION_KEY;
|
|
@@ -32682,7 +32855,7 @@ function useChatStorage(options) {
|
|
|
32682
32855
|
() => ({ getToken, baseUrl, model: embeddingModel, maskInput: maskEmbeddingInput }),
|
|
32683
32856
|
[getToken, baseUrl, embeddingModel, maskEmbeddingInput]
|
|
32684
32857
|
);
|
|
32685
|
-
const storeMaskMissing = memoryStore !== void 0 && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
|
|
32858
|
+
const storeMaskMissing = memoryStore !== void 0 && memoryStore !== null && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
|
|
32686
32859
|
const blobManagerRef = (0, import_react6.useRef)(new BlobUrlManager());
|
|
32687
32860
|
(0, import_react6.useEffect)(() => {
|
|
32688
32861
|
const manager = blobManagerRef.current;
|
|
@@ -32959,6 +33132,7 @@ function useChatStorage(options) {
|
|
|
32959
33132
|
);
|
|
32960
33133
|
const retainVaultMemory = (0, import_react6.useCallback)(
|
|
32961
33134
|
async (input) => {
|
|
33135
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
32962
33136
|
if (memoryStore) {
|
|
32963
33137
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
32964
33138
|
if (input.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
|
|
@@ -32990,6 +33164,7 @@ function useChatStorage(options) {
|
|
|
32990
33164
|
);
|
|
32991
33165
|
const createMemoryVaultTool2 = (0, import_react6.useCallback)(
|
|
32992
33166
|
(options2) => {
|
|
33167
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
32993
33168
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
32994
33169
|
const embOpts = getToken ? vaultEmbeddingOptions : void 0;
|
|
32995
33170
|
return createMemoryVaultTool(
|
|
@@ -33011,6 +33186,7 @@ function useChatStorage(options) {
|
|
|
33011
33186
|
);
|
|
33012
33187
|
const getVaultMemories = (0, import_react6.useCallback)(
|
|
33013
33188
|
(options2) => {
|
|
33189
|
+
if (memoryStore === null) return Promise.resolve([]);
|
|
33014
33190
|
if (!memoryStore) return getAllVaultMemoriesOp(vaultCtx, options2);
|
|
33015
33191
|
const { folderId, levels, kinds, ...listOptions } = options2 ?? {};
|
|
33016
33192
|
if (folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
|
|
@@ -33022,6 +33198,7 @@ function useChatStorage(options) {
|
|
|
33022
33198
|
);
|
|
33023
33199
|
const createVaultMemory = (0, import_react6.useCallback)(
|
|
33024
33200
|
async (content, scope) => {
|
|
33201
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
33025
33202
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
33026
33203
|
if (memoryStore) return memoryStore.create({ content, scope });
|
|
33027
33204
|
const result = await createVaultMemoryOp(vaultCtx, { content, scope });
|
|
@@ -33043,6 +33220,7 @@ function useChatStorage(options) {
|
|
|
33043
33220
|
);
|
|
33044
33221
|
const updateVaultMemory = (0, import_react6.useCallback)(
|
|
33045
33222
|
async (id, content, scope) => {
|
|
33223
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
33046
33224
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
33047
33225
|
if (memoryStore) return memoryStore.update(id, { content, scope });
|
|
33048
33226
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
@@ -33068,6 +33246,7 @@ function useChatStorage(options) {
|
|
|
33068
33246
|
);
|
|
33069
33247
|
const deleteVaultMemory = (0, import_react6.useCallback)(
|
|
33070
33248
|
async (id) => {
|
|
33249
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
33071
33250
|
if (memoryStore) return memoryStore.delete(id);
|
|
33072
33251
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
33073
33252
|
const result = await deleteVaultMemoryOp(vaultCtx, id);
|
|
@@ -33081,7 +33260,7 @@ function useChatStorage(options) {
|
|
|
33081
33260
|
const chunkVectorCacheRef = (0, import_react6.useRef)(createChunkVectorCache());
|
|
33082
33261
|
const clientToolEmbeddingsCacheRef = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
|
|
33083
33262
|
(0, import_react6.useEffect)(() => {
|
|
33084
|
-
if (!getToken || memoryStore) return;
|
|
33263
|
+
if (!getToken || memoryStore !== void 0) return;
|
|
33085
33264
|
void (async () => {
|
|
33086
33265
|
try {
|
|
33087
33266
|
await preEmbedVaultMemories(vaultCtx, vaultEmbeddingOptions, vaultEmbeddingCache);
|
|
@@ -33097,6 +33276,7 @@ function useChatStorage(options) {
|
|
|
33097
33276
|
}, [vaultEmbeddingCache]);
|
|
33098
33277
|
const createMemoryVaultSearchTool2 = (0, import_react6.useCallback)(
|
|
33099
33278
|
(searchOptions) => {
|
|
33279
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
33100
33280
|
if (!getToken && !memoryStore) {
|
|
33101
33281
|
throw new Error("getToken is required for memory vault search tool");
|
|
33102
33282
|
}
|
|
@@ -33112,6 +33292,7 @@ function useChatStorage(options) {
|
|
|
33112
33292
|
);
|
|
33113
33293
|
const createRecallTool2 = (0, import_react6.useCallback)(
|
|
33114
33294
|
(toolOptions, callbacks) => {
|
|
33295
|
+
if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
|
|
33115
33296
|
if (!getToken && !memoryStore) {
|
|
33116
33297
|
throw new Error("getToken is required for recall tool");
|
|
33117
33298
|
}
|
|
@@ -33151,6 +33332,7 @@ function useChatStorage(options) {
|
|
|
33151
33332
|
);
|
|
33152
33333
|
const searchVaultMemoriesFn = (0, import_react6.useCallback)(
|
|
33153
33334
|
async (query, searchOptions) => {
|
|
33335
|
+
if (memoryStore === null) return [];
|
|
33154
33336
|
if (storeMaskMissing) throw new Error(NO_STORE_MASK);
|
|
33155
33337
|
if (memoryStore) return (await memoryStore.factSource.search(query, searchOptions)).results;
|
|
33156
33338
|
if (!getToken) return [];
|
|
@@ -33166,7 +33348,7 @@ function useChatStorage(options) {
|
|
|
33166
33348
|
);
|
|
33167
33349
|
const recallFn = (0, import_react6.useCallback)(
|
|
33168
33350
|
async (query, options2) => {
|
|
33169
|
-
if (!getToken && !memoryStore) {
|
|
33351
|
+
if (memoryStore === null || !getToken && !memoryStore) {
|
|
33170
33352
|
return {
|
|
33171
33353
|
memories: [],
|
|
33172
33354
|
usedBudget: options2?.budget ?? "low",
|