@anuma/sdk 10.3.0 → 10.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/index.cjs +418 -22
- package/dist/expo/index.d.mts +610 -527
- package/dist/expo/index.d.ts +610 -527
- package/dist/expo/index.mjs +414 -22
- package/dist/index.d.mts +154 -154
- package/dist/index.d.ts +154 -154
- package/dist/react/index.cjs +418 -22
- package/dist/react/index.d.mts +1055 -972
- package/dist/react/index.d.ts +1055 -972
- package/dist/react/index.mjs +414 -22
- package/dist/server/index.d.mts +10 -0
- package/dist/server/index.d.ts +10 -0
- package/package.json +1 -1
package/dist/react/index.cjs
CHANGED
|
@@ -1588,6 +1588,7 @@ __export(index_exports, {
|
|
|
1588
1588
|
createSelectPaymentWalletTool: () => createSelectPaymentWalletTool,
|
|
1589
1589
|
createServerToolsFilter: () => createServerToolsFilter,
|
|
1590
1590
|
createStockPricePreProcessor: () => createStockPricePreProcessor,
|
|
1591
|
+
createVaultAttachments: () => createVaultAttachments,
|
|
1591
1592
|
createVaultChatBackend: () => createVaultChatBackend,
|
|
1592
1593
|
createVaultEmbeddingCache: () => createVaultEmbeddingCache,
|
|
1593
1594
|
createVaultFolderOp: () => createVaultFolderOp,
|
|
@@ -1737,11 +1738,13 @@ __export(index_exports, {
|
|
|
1737
1738
|
linkMemoryEntitiesOp: () => linkMemoryEntitiesOp,
|
|
1738
1739
|
localChatBackend: () => localChatBackend,
|
|
1739
1740
|
maskScopedEmbeddingCache: () => maskScopedEmbeddingCache,
|
|
1741
|
+
maxVaultAttachmentBytes: () => maxVaultAttachmentBytes,
|
|
1740
1742
|
mediaToStored: () => mediaToStored,
|
|
1741
1743
|
memoryCipher: () => memoryCipher,
|
|
1742
1744
|
migrateChatsToRemote: () => migrateChatsToRemote,
|
|
1743
1745
|
migrateDisplayResult: () => migrateDisplayResult,
|
|
1744
1746
|
migrateMemoriesToRemote: () => migrateMemoriesToRemote,
|
|
1747
|
+
migrateMessageAttachments: () => migrateMessageAttachments,
|
|
1745
1748
|
migrateNotionClientRegistration: () => migrateNotionClientRegistration,
|
|
1746
1749
|
migrateNotionToken: () => migrateNotionToken,
|
|
1747
1750
|
moveMemoriesToFolderOp: () => moveMemoriesToFolderOp,
|
|
@@ -1850,6 +1853,7 @@ __export(index_exports, {
|
|
|
1850
1853
|
useVoice: () => useVoice,
|
|
1851
1854
|
useWalletBinding: () => useWalletBinding,
|
|
1852
1855
|
userPreferencesStorageSchema: () => userPreferencesStorageSchema,
|
|
1856
|
+
vaultAttachmentRefs: () => vaultAttachmentRefs,
|
|
1853
1857
|
vaultChatBackend: () => vaultChatBackend,
|
|
1854
1858
|
verifyMemoriesForPublish: () => verifyMemoriesForPublish,
|
|
1855
1859
|
walk: () => walk,
|
|
@@ -14291,6 +14295,360 @@ async function migrateChatsToRemote(options) {
|
|
|
14291
14295
|
return passes(false);
|
|
14292
14296
|
}
|
|
14293
14297
|
|
|
14298
|
+
// src/lib/chatStore/vaultAttachments.ts
|
|
14299
|
+
var frameVersion = 1;
|
|
14300
|
+
var ivBytes = 12;
|
|
14301
|
+
var tagBytes = 16;
|
|
14302
|
+
var frameOverhead = 1 + ivBytes + tagBytes;
|
|
14303
|
+
var maxCiphertextBytes = 50 * 1024 * 1024;
|
|
14304
|
+
var expirySkewMs = 3e4;
|
|
14305
|
+
var maxRetryAfterMs = 3e4;
|
|
14306
|
+
var maxRefWrites = 5;
|
|
14307
|
+
var uploadWindowMs = 16 * 6e4;
|
|
14308
|
+
var attachmentIdPattern2 = /^[0-9a-f]{32}$/;
|
|
14309
|
+
var maxVaultAttachmentBytes = maxCiphertextBytes - frameOverhead;
|
|
14310
|
+
function additionalData(attachmentId) {
|
|
14311
|
+
return new TextEncoder().encode(`anuma-chat-attachment-v1:${attachmentId}`);
|
|
14312
|
+
}
|
|
14313
|
+
function invalidAttachment() {
|
|
14314
|
+
throw new ChatStoreError("Attachment does not decrypt under this key", 0, "invalid_attachment");
|
|
14315
|
+
}
|
|
14316
|
+
function sendableHeaders(headers) {
|
|
14317
|
+
return Object.fromEntries(
|
|
14318
|
+
Object.entries(headers).filter(([name]) => name.toLowerCase() !== "content-length")
|
|
14319
|
+
);
|
|
14320
|
+
}
|
|
14321
|
+
function transientStatus(status) {
|
|
14322
|
+
return status === 429 || status >= 500;
|
|
14323
|
+
}
|
|
14324
|
+
async function discardBody(response) {
|
|
14325
|
+
await response.body?.cancel().catch(() => void 0);
|
|
14326
|
+
}
|
|
14327
|
+
function createVaultAttachments(options) {
|
|
14328
|
+
const { store, keyRing, cache } = options;
|
|
14329
|
+
const fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
14330
|
+
const retries = options.retries ?? 3;
|
|
14331
|
+
const retryDelayMs = options.retryDelayMs ?? 500;
|
|
14332
|
+
const now = options.now ?? Date.now;
|
|
14333
|
+
const sleep4 = (ms2, signal) => new Promise((resolve, reject) => {
|
|
14334
|
+
signal?.throwIfAborted();
|
|
14335
|
+
const timer = setTimeout(() => {
|
|
14336
|
+
signal?.removeEventListener("abort", onAbort);
|
|
14337
|
+
resolve();
|
|
14338
|
+
}, ms2);
|
|
14339
|
+
const onAbort = () => {
|
|
14340
|
+
clearTimeout(timer);
|
|
14341
|
+
reject(signal?.reason);
|
|
14342
|
+
};
|
|
14343
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
14344
|
+
});
|
|
14345
|
+
const pause = (attempt, signal, atLeast = 0) => sleep4(Math.max(atLeast, retryDelayMs * 2 ** attempt), signal);
|
|
14346
|
+
const withRetry = async (call, signal) => {
|
|
14347
|
+
for (let attempt = 0; ; attempt++) {
|
|
14348
|
+
try {
|
|
14349
|
+
return await call();
|
|
14350
|
+
} catch (error) {
|
|
14351
|
+
if (!(error instanceof ChatStoreError) || !transientStatus(error.status) || attempt >= retries || (error.retryAfterMs ?? 0) > maxRetryAfterMs)
|
|
14352
|
+
throw error;
|
|
14353
|
+
await pause(attempt, signal, error.retryAfterMs);
|
|
14354
|
+
}
|
|
14355
|
+
}
|
|
14356
|
+
};
|
|
14357
|
+
const expired = (url) => now() >= Date.parse(url.expiresAt) - expirySkewMs;
|
|
14358
|
+
const seal = async (bytes4, attachmentId) => {
|
|
14359
|
+
const iv = crypto.getRandomValues(new Uint8Array(ivBytes));
|
|
14360
|
+
const sealed2 = new Uint8Array(
|
|
14361
|
+
await crypto.subtle.encrypt(
|
|
14362
|
+
{ name: "AES-GCM", iv, additionalData: additionalData(attachmentId) },
|
|
14363
|
+
keyRing.v3,
|
|
14364
|
+
bytes4
|
|
14365
|
+
)
|
|
14366
|
+
);
|
|
14367
|
+
const frame = new Uint8Array(1 + ivBytes + sealed2.length);
|
|
14368
|
+
frame[0] = frameVersion;
|
|
14369
|
+
frame.set(iv, 1);
|
|
14370
|
+
frame.set(sealed2, 1 + ivBytes);
|
|
14371
|
+
return frame;
|
|
14372
|
+
};
|
|
14373
|
+
const open = async (frame, attachmentId) => {
|
|
14374
|
+
if (frame.length < frameOverhead || frame[0] !== frameVersion) invalidAttachment();
|
|
14375
|
+
try {
|
|
14376
|
+
return new Uint8Array(
|
|
14377
|
+
await crypto.subtle.decrypt(
|
|
14378
|
+
{
|
|
14379
|
+
name: "AES-GCM",
|
|
14380
|
+
iv: frame.slice(1, 1 + ivBytes),
|
|
14381
|
+
additionalData: additionalData(attachmentId)
|
|
14382
|
+
},
|
|
14383
|
+
keyRing.v3,
|
|
14384
|
+
frame.slice(1 + ivBytes)
|
|
14385
|
+
)
|
|
14386
|
+
);
|
|
14387
|
+
} catch {
|
|
14388
|
+
return invalidAttachment();
|
|
14389
|
+
}
|
|
14390
|
+
};
|
|
14391
|
+
const put = async (upload, body, signal) => {
|
|
14392
|
+
for (let attempt = 0; ; attempt++) {
|
|
14393
|
+
if (expired(upload)) return "expired";
|
|
14394
|
+
let response;
|
|
14395
|
+
try {
|
|
14396
|
+
response = await fetcher(upload.url, {
|
|
14397
|
+
method: upload.method,
|
|
14398
|
+
headers: sendableHeaders(upload.headers),
|
|
14399
|
+
body,
|
|
14400
|
+
signal
|
|
14401
|
+
});
|
|
14402
|
+
} catch (error) {
|
|
14403
|
+
if (signal?.aborted || attempt >= retries) throw error;
|
|
14404
|
+
await pause(attempt, signal);
|
|
14405
|
+
continue;
|
|
14406
|
+
}
|
|
14407
|
+
await discardBody(response);
|
|
14408
|
+
if (response.ok) return "stored";
|
|
14409
|
+
if (response.status === 403) return "expired";
|
|
14410
|
+
if (!transientStatus(response.status) || attempt >= retries)
|
|
14411
|
+
throw new ChatStoreError(
|
|
14412
|
+
`Attachment upload failed with ${response.status}`,
|
|
14413
|
+
response.status,
|
|
14414
|
+
"attachment_upload_failed"
|
|
14415
|
+
);
|
|
14416
|
+
await pause(attempt, signal);
|
|
14417
|
+
}
|
|
14418
|
+
};
|
|
14419
|
+
const download = async (url, signal) => {
|
|
14420
|
+
for (let attempt = 0; ; attempt++) {
|
|
14421
|
+
if (expired(url)) return "expired";
|
|
14422
|
+
let response;
|
|
14423
|
+
try {
|
|
14424
|
+
response = await fetcher(url.url, {
|
|
14425
|
+
method: url.method,
|
|
14426
|
+
headers: sendableHeaders(url.headers),
|
|
14427
|
+
signal
|
|
14428
|
+
});
|
|
14429
|
+
if (response.ok) return new Uint8Array(await response.arrayBuffer());
|
|
14430
|
+
} catch (error) {
|
|
14431
|
+
if (signal?.aborted || attempt >= retries) throw error;
|
|
14432
|
+
await pause(attempt, signal);
|
|
14433
|
+
continue;
|
|
14434
|
+
}
|
|
14435
|
+
await discardBody(response);
|
|
14436
|
+
if (response.status === 403) return "expired";
|
|
14437
|
+
if (response.status === 404) return "missing";
|
|
14438
|
+
if (!transientStatus(response.status) || attempt >= retries)
|
|
14439
|
+
throw new ChatStoreError(
|
|
14440
|
+
`Attachment download failed with ${response.status}`,
|
|
14441
|
+
response.status,
|
|
14442
|
+
"attachment_download_failed"
|
|
14443
|
+
);
|
|
14444
|
+
await pause(attempt, signal);
|
|
14445
|
+
}
|
|
14446
|
+
};
|
|
14447
|
+
const remove = async (attachmentId, signal) => {
|
|
14448
|
+
try {
|
|
14449
|
+
await withRetry(() => store.attachments.delete(attachmentId, signal), signal);
|
|
14450
|
+
} catch (error) {
|
|
14451
|
+
if (!(error instanceof ChatStoreError) || error.status !== 404) throw error;
|
|
14452
|
+
}
|
|
14453
|
+
await cache?.delete(attachmentId).catch(() => void 0);
|
|
14454
|
+
};
|
|
14455
|
+
const discardPending = async (attachmentId) => {
|
|
14456
|
+
const found = await store.attachments.get(attachmentId);
|
|
14457
|
+
if (found?.attachment.state === "pending") await remove(attachmentId);
|
|
14458
|
+
};
|
|
14459
|
+
return {
|
|
14460
|
+
async upload(bytes4, uploadOptions) {
|
|
14461
|
+
const signal = uploadOptions?.signal;
|
|
14462
|
+
if (!(bytes4 instanceof Uint8Array) || bytes4.length > maxVaultAttachmentBytes)
|
|
14463
|
+
throw new ChatStoreError(
|
|
14464
|
+
"Attachment is larger than vault accepts",
|
|
14465
|
+
413,
|
|
14466
|
+
"attachment_too_large"
|
|
14467
|
+
);
|
|
14468
|
+
const size = bytes4.length + frameOverhead;
|
|
14469
|
+
for (let attempt = 0; ; attempt++) {
|
|
14470
|
+
const { attachment: attachment2, upload } = await withRetry(
|
|
14471
|
+
() => store.attachments.create(size, signal),
|
|
14472
|
+
signal
|
|
14473
|
+
);
|
|
14474
|
+
try {
|
|
14475
|
+
await uploadOptions?.onReserved?.(attachment2.id);
|
|
14476
|
+
const frame = await seal(bytes4, attachment2.id);
|
|
14477
|
+
if (await put(upload, frame, signal) === "stored") return attachment2.id;
|
|
14478
|
+
} catch (error) {
|
|
14479
|
+
await discardPending(attachment2.id).catch(() => void 0);
|
|
14480
|
+
throw error;
|
|
14481
|
+
}
|
|
14482
|
+
await remove(attachment2.id).catch(() => void 0);
|
|
14483
|
+
if (attempt >= retries)
|
|
14484
|
+
throw new ChatStoreError(
|
|
14485
|
+
"Attachment storage rejected the upload URL",
|
|
14486
|
+
403,
|
|
14487
|
+
"attachment_upload_rejected"
|
|
14488
|
+
);
|
|
14489
|
+
}
|
|
14490
|
+
},
|
|
14491
|
+
commit(attachmentId, owner, signal) {
|
|
14492
|
+
return withRetry(() => store.attachments.commit(attachmentId, owner, signal), signal);
|
|
14493
|
+
},
|
|
14494
|
+
async read(attachmentId, signal) {
|
|
14495
|
+
if (!attachmentIdPattern2.test(attachmentId)) invalidAttachment();
|
|
14496
|
+
const cached = await cache?.get(attachmentId).catch(() => null);
|
|
14497
|
+
if (cached) return cached;
|
|
14498
|
+
for (let attempt = 0; ; attempt++) {
|
|
14499
|
+
const found = await withRetry(() => store.attachments.get(attachmentId, signal), signal);
|
|
14500
|
+
if (!found?.download) return null;
|
|
14501
|
+
const frame = await download(found.download, signal);
|
|
14502
|
+
if (frame === "missing") return null;
|
|
14503
|
+
if (frame === "expired") {
|
|
14504
|
+
if (attempt >= retries)
|
|
14505
|
+
throw new ChatStoreError(
|
|
14506
|
+
"Attachment storage rejected the download URL",
|
|
14507
|
+
403,
|
|
14508
|
+
"attachment_download_rejected"
|
|
14509
|
+
);
|
|
14510
|
+
continue;
|
|
14511
|
+
}
|
|
14512
|
+
if (frame.length !== found.attachment.sizeBytes) invalidAttachment();
|
|
14513
|
+
const bytes4 = await open(frame, attachmentId);
|
|
14514
|
+
await cache?.set(attachmentId, bytes4).catch(() => void 0);
|
|
14515
|
+
return bytes4;
|
|
14516
|
+
}
|
|
14517
|
+
},
|
|
14518
|
+
delete: remove
|
|
14519
|
+
};
|
|
14520
|
+
}
|
|
14521
|
+
function validRef(value) {
|
|
14522
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
14523
|
+
const ref3 = value;
|
|
14524
|
+
return typeof ref3.attachmentId === "string" && attachmentIdPattern2.test(ref3.attachmentId) && typeof ref3.fileId === "string" && ref3.fileId.length > 0 && typeof ref3.name === "string" && typeof ref3.type === "string" && Number.isSafeInteger(ref3.size) && ref3.size >= 0;
|
|
14525
|
+
}
|
|
14526
|
+
function vaultAttachmentRefs(record2) {
|
|
14527
|
+
const refs = record2.data.vaultAttachments;
|
|
14528
|
+
return Array.isArray(refs) ? refs.filter(validRef) : [];
|
|
14529
|
+
}
|
|
14530
|
+
function journalKey(messageId, fileId) {
|
|
14531
|
+
return JSON.stringify([messageId, fileId]);
|
|
14532
|
+
}
|
|
14533
|
+
async function migrateMessageAttachments(options) {
|
|
14534
|
+
const { store, attachments, journal, messageId, signal } = options;
|
|
14535
|
+
const now = options.now ?? Date.now;
|
|
14536
|
+
const owner = { kind: "message", id: messageId };
|
|
14537
|
+
const ownerGone = () => new ChatStoreError("Message is not in vault", 409, "attachment_owner_not_found");
|
|
14538
|
+
let snapshot = await store.get("message", messageId, signal);
|
|
14539
|
+
if (!snapshot || snapshot.record.isDeleted) throw ownerGone();
|
|
14540
|
+
const present = new Map(vaultAttachmentRefs(snapshot.record).map((r) => [r.fileId, r]));
|
|
14541
|
+
const uploadable = (attachment2) => attachment2.state === "pending" && now() < Date.parse(attachment2.createdAt) + uploadWindowMs;
|
|
14542
|
+
const lookup = async (attachmentId) => attachmentId && attachmentIdPattern2.test(attachmentId) ? (await store.attachments.get(attachmentId, signal))?.attachment ?? null : null;
|
|
14543
|
+
const bind = async (found) => {
|
|
14544
|
+
if (!found) return null;
|
|
14545
|
+
if (found.state === "committed")
|
|
14546
|
+
return found.ownerKind === owner.kind && found.ownerId === owner.id ? found : null;
|
|
14547
|
+
try {
|
|
14548
|
+
return await attachments.commit(found.id, owner, signal);
|
|
14549
|
+
} catch (error) {
|
|
14550
|
+
if (!(error instanceof ChatStoreError) || error.code !== "attachment_not_uploaded")
|
|
14551
|
+
throw error;
|
|
14552
|
+
if (uploadable(found)) return "busy";
|
|
14553
|
+
await attachments.delete(found.id, signal);
|
|
14554
|
+
return null;
|
|
14555
|
+
}
|
|
14556
|
+
};
|
|
14557
|
+
const added = [];
|
|
14558
|
+
const settled = [];
|
|
14559
|
+
const missing2 = [];
|
|
14560
|
+
const oversized = [];
|
|
14561
|
+
const deferred = [];
|
|
14562
|
+
const stale = /* @__PURE__ */ new Set();
|
|
14563
|
+
let uploaded = 0;
|
|
14564
|
+
for (const file of options.files) {
|
|
14565
|
+
signal?.throwIfAborted();
|
|
14566
|
+
const key3 = journalKey(messageId, file.fileId);
|
|
14567
|
+
const recorded = present.get(file.fileId);
|
|
14568
|
+
if (recorded) {
|
|
14569
|
+
const bound = await bind(await lookup(recorded.attachmentId));
|
|
14570
|
+
if (bound === "busy") {
|
|
14571
|
+
deferred.push(file.fileId);
|
|
14572
|
+
continue;
|
|
14573
|
+
}
|
|
14574
|
+
if (bound) {
|
|
14575
|
+
const stray = await lookup(await journal.get(key3));
|
|
14576
|
+
if (stray && stray.id !== recorded.attachmentId) {
|
|
14577
|
+
if (uploadable(stray)) continue;
|
|
14578
|
+
await attachments.delete(stray.id, signal);
|
|
14579
|
+
}
|
|
14580
|
+
settled.push(key3);
|
|
14581
|
+
continue;
|
|
14582
|
+
}
|
|
14583
|
+
stale.add(recorded.attachmentId);
|
|
14584
|
+
}
|
|
14585
|
+
const meta = { fileId: file.fileId, name: file.name, type: file.type };
|
|
14586
|
+
const resumed = await bind(await lookup(await journal.get(key3)));
|
|
14587
|
+
if (resumed === "busy") {
|
|
14588
|
+
deferred.push(file.fileId);
|
|
14589
|
+
continue;
|
|
14590
|
+
}
|
|
14591
|
+
if (resumed) {
|
|
14592
|
+
added.push({ attachmentId: resumed.id, ...meta, size: resumed.sizeBytes - frameOverhead });
|
|
14593
|
+
settled.push(key3);
|
|
14594
|
+
continue;
|
|
14595
|
+
}
|
|
14596
|
+
const bytes4 = await file.read();
|
|
14597
|
+
if (!bytes4) {
|
|
14598
|
+
missing2.push(file.fileId);
|
|
14599
|
+
continue;
|
|
14600
|
+
}
|
|
14601
|
+
if (bytes4.length > maxVaultAttachmentBytes) {
|
|
14602
|
+
oversized.push(file.fileId);
|
|
14603
|
+
continue;
|
|
14604
|
+
}
|
|
14605
|
+
const attachmentId = await attachments.upload(bytes4, {
|
|
14606
|
+
signal,
|
|
14607
|
+
onReserved: (id2) => journal.set(key3, id2)
|
|
14608
|
+
});
|
|
14609
|
+
uploaded++;
|
|
14610
|
+
await attachments.commit(attachmentId, owner, signal);
|
|
14611
|
+
added.push({ attachmentId, ...meta, size: bytes4.length });
|
|
14612
|
+
settled.push(key3);
|
|
14613
|
+
}
|
|
14614
|
+
const superseded = [];
|
|
14615
|
+
for (let attempt = 0; added.length > 0; attempt++) {
|
|
14616
|
+
const refs = new Map(vaultAttachmentRefs(snapshot.record).map((r) => [r.fileId, r]));
|
|
14617
|
+
superseded.length = 0;
|
|
14618
|
+
for (const ref3 of added) {
|
|
14619
|
+
const prior = refs.get(ref3.fileId);
|
|
14620
|
+
if (prior && prior.attachmentId !== ref3.attachmentId && !stale.has(prior.attachmentId))
|
|
14621
|
+
superseded.push(ref3.attachmentId);
|
|
14622
|
+
else refs.set(ref3.fileId, ref3);
|
|
14623
|
+
}
|
|
14624
|
+
if (superseded.length === added.length) break;
|
|
14625
|
+
try {
|
|
14626
|
+
[snapshot] = await store.putMany(
|
|
14627
|
+
[
|
|
14628
|
+
{
|
|
14629
|
+
record: {
|
|
14630
|
+
...snapshot.record,
|
|
14631
|
+
data: { ...snapshot.record.data, ...plain({ vaultAttachments: [...refs.values()] }) }
|
|
14632
|
+
},
|
|
14633
|
+
expectedVersion: snapshot.version
|
|
14634
|
+
}
|
|
14635
|
+
],
|
|
14636
|
+
signal
|
|
14637
|
+
);
|
|
14638
|
+
break;
|
|
14639
|
+
} catch (error) {
|
|
14640
|
+
if (!(error instanceof ChatStoreError) || error.code !== "version_conflict" || attempt + 1 >= maxRefWrites)
|
|
14641
|
+
throw error;
|
|
14642
|
+
const latest = await store.get("message", messageId, signal);
|
|
14643
|
+
if (!latest || latest.record.isDeleted) throw ownerGone();
|
|
14644
|
+
snapshot = latest;
|
|
14645
|
+
}
|
|
14646
|
+
}
|
|
14647
|
+
for (const id2 of superseded) await attachments.delete(id2, signal);
|
|
14648
|
+
for (const key3 of settled) await journal.set(key3, null);
|
|
14649
|
+
return { refs: vaultAttachmentRefs(snapshot.record), uploaded, missing: missing2, oversized, deferred };
|
|
14650
|
+
}
|
|
14651
|
+
|
|
14294
14652
|
// src/lib/chatStore/vaultBackend.ts
|
|
14295
14653
|
var import_uuid3 = require("uuid");
|
|
14296
14654
|
|
|
@@ -14430,6 +14788,7 @@ var resumableFields = [
|
|
|
14430
14788
|
"imageModel",
|
|
14431
14789
|
"files",
|
|
14432
14790
|
"fileIds",
|
|
14791
|
+
"vaultAttachments",
|
|
14433
14792
|
"usage",
|
|
14434
14793
|
"sources",
|
|
14435
14794
|
"responseDuration",
|
|
@@ -28274,7 +28633,7 @@ function createRemoteMemoryStore(options) {
|
|
|
28274
28633
|
};
|
|
28275
28634
|
const mutate = (id2, change, edit, writeOptions) => serialized(id2, () => mutateLocked(id2, change, edit, writeOptions));
|
|
28276
28635
|
const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id2) => () => serialized(id2, inner), task)();
|
|
28277
|
-
const mutateMany = async (ids, change, edit, leaseToken, signal) => {
|
|
28636
|
+
const mutateMany = async (ids, change, edit, leaseToken, signal, includeEmbeddings = false) => {
|
|
28278
28637
|
const saved = /* @__PURE__ */ new Map();
|
|
28279
28638
|
const failed = /* @__PURE__ */ new Map();
|
|
28280
28639
|
for (const slice of chunks2([...new Set(ids)], MAX_BATCH)) {
|
|
@@ -28283,7 +28642,7 @@ function createRemoteMemoryStore(options) {
|
|
|
28283
28642
|
const writes = [];
|
|
28284
28643
|
let read;
|
|
28285
28644
|
try {
|
|
28286
|
-
read = await readEveryState(slice, signal);
|
|
28645
|
+
read = await readEveryState(slice, signal, includeEmbeddings);
|
|
28287
28646
|
} catch (error) {
|
|
28288
28647
|
signal?.throwIfAborted();
|
|
28289
28648
|
for (const id2 of slice) failed.set(id2, error);
|
|
@@ -28342,21 +28701,55 @@ function createRemoteMemoryStore(options) {
|
|
|
28342
28701
|
}
|
|
28343
28702
|
return { saved, failed };
|
|
28344
28703
|
};
|
|
28345
|
-
const
|
|
28346
|
-
|
|
28347
|
-
|
|
28348
|
-
|
|
28349
|
-
|
|
28350
|
-
|
|
28351
|
-
const
|
|
28352
|
-
|
|
28353
|
-
|
|
28354
|
-
|
|
28355
|
-
|
|
28356
|
-
|
|
28357
|
-
|
|
28358
|
-
|
|
28359
|
-
|
|
28704
|
+
const pendingEmbeddings = /* @__PURE__ */ new Map();
|
|
28705
|
+
let embeddingActive = false;
|
|
28706
|
+
const drainEmbeddings = async () => {
|
|
28707
|
+
try {
|
|
28708
|
+
while (pendingEmbeddings.size) {
|
|
28709
|
+
const batch = /* @__PURE__ */ new Map();
|
|
28710
|
+
for (const [id2, content] of pendingEmbeddings) {
|
|
28711
|
+
pendingEmbeddings.delete(id2);
|
|
28712
|
+
batch.set(id2, content);
|
|
28713
|
+
if (batch.size === MAX_BATCH) break;
|
|
28714
|
+
}
|
|
28715
|
+
try {
|
|
28716
|
+
const vectors = await generateEmbeddings([...batch.values()], embeddingOptions);
|
|
28717
|
+
const embeddings2 = /* @__PURE__ */ new Map();
|
|
28718
|
+
[...batch.keys()].forEach((id2, i) => {
|
|
28719
|
+
try {
|
|
28720
|
+
embeddings2.set(id2, storedVector(vectors[i]));
|
|
28721
|
+
} catch (error) {
|
|
28722
|
+
getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
|
|
28723
|
+
}
|
|
28724
|
+
});
|
|
28725
|
+
if (!embeddings2.size) continue;
|
|
28726
|
+
const { failed } = await mutateMany(
|
|
28727
|
+
[...embeddings2.keys()],
|
|
28728
|
+
() => "embedding",
|
|
28729
|
+
(memory) => memory.content !== batch.get(memory.memory_id) || memory.embedding?.length ? null : {
|
|
28730
|
+
...memory,
|
|
28731
|
+
embedding: embeddings2.get(memory.memory_id),
|
|
28732
|
+
embedding_model: model
|
|
28733
|
+
},
|
|
28734
|
+
void 0,
|
|
28735
|
+
void 0,
|
|
28736
|
+
true
|
|
28737
|
+
);
|
|
28738
|
+
for (const error of failed.values())
|
|
28739
|
+
getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
|
|
28740
|
+
} catch (error) {
|
|
28741
|
+
getLogger().warn("[memory/remote-store] Failed to embed memories:", error);
|
|
28742
|
+
}
|
|
28743
|
+
}
|
|
28744
|
+
} finally {
|
|
28745
|
+
embeddingActive = false;
|
|
28746
|
+
}
|
|
28747
|
+
};
|
|
28748
|
+
const embedInBackground = (records) => {
|
|
28749
|
+
for (const { memory } of records) pendingEmbeddings.set(memory.memory_id, memory.content);
|
|
28750
|
+
if (embeddingActive || !pendingEmbeddings.size) return;
|
|
28751
|
+
embeddingActive = true;
|
|
28752
|
+
void drainEmbeddings();
|
|
28360
28753
|
};
|
|
28361
28754
|
const newRow = (input) => {
|
|
28362
28755
|
const now = Date.now();
|
|
@@ -28390,9 +28783,7 @@ function createRemoteMemoryStore(options) {
|
|
|
28390
28783
|
};
|
|
28391
28784
|
};
|
|
28392
28785
|
const created = (records, inputs) => {
|
|
28393
|
-
records.
|
|
28394
|
-
if (inputs[i].embedding === void 0) embedInBackground(record2);
|
|
28395
|
-
});
|
|
28786
|
+
embedInBackground(records.filter((_, i) => inputs[i].embedding === void 0));
|
|
28396
28787
|
notify("membership", records);
|
|
28397
28788
|
return records.map((record2) => stored(record2.memory));
|
|
28398
28789
|
};
|
|
@@ -28422,7 +28813,7 @@ function createRemoteMemoryStore(options) {
|
|
|
28422
28813
|
};
|
|
28423
28814
|
};
|
|
28424
28815
|
const withKnownKinds = async (topics) => topics.map(await knownKinds(topics));
|
|
28425
|
-
const readEveryState = async (ids, signal) => {
|
|
28816
|
+
const readEveryState = async (ids, signal, includeEmbeddings = false) => {
|
|
28426
28817
|
const records = /* @__PURE__ */ new Map();
|
|
28427
28818
|
const unreadable = /* @__PURE__ */ new Set();
|
|
28428
28819
|
for (const memory_ids of chunks2(ids, MAX_QUERY_IDS)) {
|
|
@@ -28434,6 +28825,7 @@ function createRemoteMemoryStore(options) {
|
|
|
28434
28825
|
include_archived: true,
|
|
28435
28826
|
include_quarantined: true,
|
|
28436
28827
|
include_superseded: true,
|
|
28828
|
+
...includeEmbeddings && { include_embeddings: true },
|
|
28437
28829
|
limit: 200,
|
|
28438
28830
|
...signal && { signal },
|
|
28439
28831
|
...cursor2 && { cursor: cursor2 }
|
|
@@ -29096,7 +29488,7 @@ function createRemoteMemoryStore(options) {
|
|
|
29096
29488
|
}
|
|
29097
29489
|
return memory;
|
|
29098
29490
|
});
|
|
29099
|
-
if (saved && patch.embedding === void 0) embedInBackground(saved);
|
|
29491
|
+
if (saved && patch.embedding === void 0) embedInBackground([saved]);
|
|
29100
29492
|
return asStored(saved);
|
|
29101
29493
|
},
|
|
29102
29494
|
delete: async (id2) => !!await mutate(id2, "membership", (memory) => ({ ...memory, is_deleted: true })),
|
|
@@ -42141,6 +42533,7 @@ function useWalletBinding(options = {}) {
|
|
|
42141
42533
|
createSelectPaymentWalletTool,
|
|
42142
42534
|
createServerToolsFilter,
|
|
42143
42535
|
createStockPricePreProcessor,
|
|
42536
|
+
createVaultAttachments,
|
|
42144
42537
|
createVaultChatBackend,
|
|
42145
42538
|
createVaultEmbeddingCache,
|
|
42146
42539
|
createVaultFolderOp,
|
|
@@ -42290,11 +42683,13 @@ function useWalletBinding(options = {}) {
|
|
|
42290
42683
|
linkMemoryEntitiesOp,
|
|
42291
42684
|
localChatBackend,
|
|
42292
42685
|
maskScopedEmbeddingCache,
|
|
42686
|
+
maxVaultAttachmentBytes,
|
|
42293
42687
|
mediaToStored,
|
|
42294
42688
|
memoryCipher,
|
|
42295
42689
|
migrateChatsToRemote,
|
|
42296
42690
|
migrateDisplayResult,
|
|
42297
42691
|
migrateMemoriesToRemote,
|
|
42692
|
+
migrateMessageAttachments,
|
|
42298
42693
|
migrateNotionClientRegistration,
|
|
42299
42694
|
migrateNotionToken,
|
|
42300
42695
|
moveMemoriesToFolderOp,
|
|
@@ -42403,6 +42798,7 @@ function useWalletBinding(options = {}) {
|
|
|
42403
42798
|
useVoice,
|
|
42404
42799
|
useWalletBinding,
|
|
42405
42800
|
userPreferencesStorageSchema,
|
|
42801
|
+
vaultAttachmentRefs,
|
|
42406
42802
|
vaultChatBackend,
|
|
42407
42803
|
verifyMemoriesForPublish,
|
|
42408
42804
|
walk,
|