@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/expo/index.cjs
CHANGED
|
@@ -1534,6 +1534,7 @@ __export(index_exports, {
|
|
|
1534
1534
|
createSelectPaymentWalletTool: () => createSelectPaymentWalletTool,
|
|
1535
1535
|
createStockPricePreProcessor: () => createStockPricePreProcessor,
|
|
1536
1536
|
createStreamingDeAnonymizer: () => createStreamingDeAnonymizer,
|
|
1537
|
+
createVaultAttachments: () => createVaultAttachments,
|
|
1537
1538
|
createVaultChatBackend: () => createVaultChatBackend,
|
|
1538
1539
|
createVaultEmbeddingCache: () => createVaultEmbeddingCache,
|
|
1539
1540
|
createVaultFolderOp: () => createVaultFolderOp,
|
|
@@ -1598,9 +1599,11 @@ __export(index_exports, {
|
|
|
1598
1599
|
isRerankerAvailable: () => isRerankerAvailable,
|
|
1599
1600
|
localChatBackend: () => localChatBackend,
|
|
1600
1601
|
maskScopedEmbeddingCache: () => maskScopedEmbeddingCache,
|
|
1602
|
+
maxVaultAttachmentBytes: () => maxVaultAttachmentBytes,
|
|
1601
1603
|
memoryCipher: () => memoryCipher,
|
|
1602
1604
|
migrateChatsToRemote: () => migrateChatsToRemote,
|
|
1603
1605
|
migrateMemoriesToRemote: () => migrateMemoriesToRemote,
|
|
1606
|
+
migrateMessageAttachments: () => migrateMessageAttachments,
|
|
1604
1607
|
moveMemoriesToFolderOp: () => moveMemoriesToFolderOp,
|
|
1605
1608
|
noopLogger: () => noopLogger,
|
|
1606
1609
|
onKeyAvailable: () => onKeyAvailable,
|
|
@@ -1654,6 +1657,7 @@ __export(index_exports, {
|
|
|
1654
1657
|
useCredits: () => useCredits,
|
|
1655
1658
|
useEncryption: () => useEncryption,
|
|
1656
1659
|
useModels: () => useModels,
|
|
1660
|
+
vaultAttachmentRefs: () => vaultAttachmentRefs,
|
|
1657
1661
|
vaultChatBackend: () => vaultChatBackend,
|
|
1658
1662
|
verifyMemoriesForPublish: () => verifyMemoriesForPublish,
|
|
1659
1663
|
xhrTransport: () => xhrTransport
|
|
@@ -13521,6 +13525,360 @@ async function migrateChatsToRemote(options) {
|
|
|
13521
13525
|
return passes(false);
|
|
13522
13526
|
}
|
|
13523
13527
|
|
|
13528
|
+
// src/lib/chatStore/vaultAttachments.ts
|
|
13529
|
+
var frameVersion = 1;
|
|
13530
|
+
var ivBytes = 12;
|
|
13531
|
+
var tagBytes = 16;
|
|
13532
|
+
var frameOverhead = 1 + ivBytes + tagBytes;
|
|
13533
|
+
var maxCiphertextBytes = 50 * 1024 * 1024;
|
|
13534
|
+
var expirySkewMs = 3e4;
|
|
13535
|
+
var maxRetryAfterMs = 3e4;
|
|
13536
|
+
var maxRefWrites = 5;
|
|
13537
|
+
var uploadWindowMs = 16 * 6e4;
|
|
13538
|
+
var attachmentIdPattern2 = /^[0-9a-f]{32}$/;
|
|
13539
|
+
var maxVaultAttachmentBytes = maxCiphertextBytes - frameOverhead;
|
|
13540
|
+
function additionalData(attachmentId) {
|
|
13541
|
+
return new TextEncoder().encode(`anuma-chat-attachment-v1:${attachmentId}`);
|
|
13542
|
+
}
|
|
13543
|
+
function invalidAttachment() {
|
|
13544
|
+
throw new ChatStoreError("Attachment does not decrypt under this key", 0, "invalid_attachment");
|
|
13545
|
+
}
|
|
13546
|
+
function sendableHeaders(headers) {
|
|
13547
|
+
return Object.fromEntries(
|
|
13548
|
+
Object.entries(headers).filter(([name]) => name.toLowerCase() !== "content-length")
|
|
13549
|
+
);
|
|
13550
|
+
}
|
|
13551
|
+
function transientStatus(status) {
|
|
13552
|
+
return status === 429 || status >= 500;
|
|
13553
|
+
}
|
|
13554
|
+
async function discardBody(response) {
|
|
13555
|
+
await response.body?.cancel().catch(() => void 0);
|
|
13556
|
+
}
|
|
13557
|
+
function createVaultAttachments(options) {
|
|
13558
|
+
const { store, keyRing, cache } = options;
|
|
13559
|
+
const fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
13560
|
+
const retries = options.retries ?? 3;
|
|
13561
|
+
const retryDelayMs = options.retryDelayMs ?? 500;
|
|
13562
|
+
const now = options.now ?? Date.now;
|
|
13563
|
+
const sleep4 = (ms2, signal) => new Promise((resolve, reject) => {
|
|
13564
|
+
signal?.throwIfAborted();
|
|
13565
|
+
const timer = setTimeout(() => {
|
|
13566
|
+
signal?.removeEventListener("abort", onAbort);
|
|
13567
|
+
resolve();
|
|
13568
|
+
}, ms2);
|
|
13569
|
+
const onAbort = () => {
|
|
13570
|
+
clearTimeout(timer);
|
|
13571
|
+
reject(signal?.reason);
|
|
13572
|
+
};
|
|
13573
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
13574
|
+
});
|
|
13575
|
+
const pause = (attempt, signal, atLeast = 0) => sleep4(Math.max(atLeast, retryDelayMs * 2 ** attempt), signal);
|
|
13576
|
+
const withRetry = async (call, signal) => {
|
|
13577
|
+
for (let attempt = 0; ; attempt++) {
|
|
13578
|
+
try {
|
|
13579
|
+
return await call();
|
|
13580
|
+
} catch (error) {
|
|
13581
|
+
if (!(error instanceof ChatStoreError) || !transientStatus(error.status) || attempt >= retries || (error.retryAfterMs ?? 0) > maxRetryAfterMs)
|
|
13582
|
+
throw error;
|
|
13583
|
+
await pause(attempt, signal, error.retryAfterMs);
|
|
13584
|
+
}
|
|
13585
|
+
}
|
|
13586
|
+
};
|
|
13587
|
+
const expired = (url) => now() >= Date.parse(url.expiresAt) - expirySkewMs;
|
|
13588
|
+
const seal = async (bytes4, attachmentId) => {
|
|
13589
|
+
const iv = crypto.getRandomValues(new Uint8Array(ivBytes));
|
|
13590
|
+
const sealed2 = new Uint8Array(
|
|
13591
|
+
await crypto.subtle.encrypt(
|
|
13592
|
+
{ name: "AES-GCM", iv, additionalData: additionalData(attachmentId) },
|
|
13593
|
+
keyRing.v3,
|
|
13594
|
+
bytes4
|
|
13595
|
+
)
|
|
13596
|
+
);
|
|
13597
|
+
const frame = new Uint8Array(1 + ivBytes + sealed2.length);
|
|
13598
|
+
frame[0] = frameVersion;
|
|
13599
|
+
frame.set(iv, 1);
|
|
13600
|
+
frame.set(sealed2, 1 + ivBytes);
|
|
13601
|
+
return frame;
|
|
13602
|
+
};
|
|
13603
|
+
const open = async (frame, attachmentId) => {
|
|
13604
|
+
if (frame.length < frameOverhead || frame[0] !== frameVersion) invalidAttachment();
|
|
13605
|
+
try {
|
|
13606
|
+
return new Uint8Array(
|
|
13607
|
+
await crypto.subtle.decrypt(
|
|
13608
|
+
{
|
|
13609
|
+
name: "AES-GCM",
|
|
13610
|
+
iv: frame.slice(1, 1 + ivBytes),
|
|
13611
|
+
additionalData: additionalData(attachmentId)
|
|
13612
|
+
},
|
|
13613
|
+
keyRing.v3,
|
|
13614
|
+
frame.slice(1 + ivBytes)
|
|
13615
|
+
)
|
|
13616
|
+
);
|
|
13617
|
+
} catch {
|
|
13618
|
+
return invalidAttachment();
|
|
13619
|
+
}
|
|
13620
|
+
};
|
|
13621
|
+
const put = async (upload, body, signal) => {
|
|
13622
|
+
for (let attempt = 0; ; attempt++) {
|
|
13623
|
+
if (expired(upload)) return "expired";
|
|
13624
|
+
let response;
|
|
13625
|
+
try {
|
|
13626
|
+
response = await fetcher(upload.url, {
|
|
13627
|
+
method: upload.method,
|
|
13628
|
+
headers: sendableHeaders(upload.headers),
|
|
13629
|
+
body,
|
|
13630
|
+
signal
|
|
13631
|
+
});
|
|
13632
|
+
} catch (error) {
|
|
13633
|
+
if (signal?.aborted || attempt >= retries) throw error;
|
|
13634
|
+
await pause(attempt, signal);
|
|
13635
|
+
continue;
|
|
13636
|
+
}
|
|
13637
|
+
await discardBody(response);
|
|
13638
|
+
if (response.ok) return "stored";
|
|
13639
|
+
if (response.status === 403) return "expired";
|
|
13640
|
+
if (!transientStatus(response.status) || attempt >= retries)
|
|
13641
|
+
throw new ChatStoreError(
|
|
13642
|
+
`Attachment upload failed with ${response.status}`,
|
|
13643
|
+
response.status,
|
|
13644
|
+
"attachment_upload_failed"
|
|
13645
|
+
);
|
|
13646
|
+
await pause(attempt, signal);
|
|
13647
|
+
}
|
|
13648
|
+
};
|
|
13649
|
+
const download = async (url, signal) => {
|
|
13650
|
+
for (let attempt = 0; ; attempt++) {
|
|
13651
|
+
if (expired(url)) return "expired";
|
|
13652
|
+
let response;
|
|
13653
|
+
try {
|
|
13654
|
+
response = await fetcher(url.url, {
|
|
13655
|
+
method: url.method,
|
|
13656
|
+
headers: sendableHeaders(url.headers),
|
|
13657
|
+
signal
|
|
13658
|
+
});
|
|
13659
|
+
if (response.ok) return new Uint8Array(await response.arrayBuffer());
|
|
13660
|
+
} catch (error) {
|
|
13661
|
+
if (signal?.aborted || attempt >= retries) throw error;
|
|
13662
|
+
await pause(attempt, signal);
|
|
13663
|
+
continue;
|
|
13664
|
+
}
|
|
13665
|
+
await discardBody(response);
|
|
13666
|
+
if (response.status === 403) return "expired";
|
|
13667
|
+
if (response.status === 404) return "missing";
|
|
13668
|
+
if (!transientStatus(response.status) || attempt >= retries)
|
|
13669
|
+
throw new ChatStoreError(
|
|
13670
|
+
`Attachment download failed with ${response.status}`,
|
|
13671
|
+
response.status,
|
|
13672
|
+
"attachment_download_failed"
|
|
13673
|
+
);
|
|
13674
|
+
await pause(attempt, signal);
|
|
13675
|
+
}
|
|
13676
|
+
};
|
|
13677
|
+
const remove = async (attachmentId, signal) => {
|
|
13678
|
+
try {
|
|
13679
|
+
await withRetry(() => store.attachments.delete(attachmentId, signal), signal);
|
|
13680
|
+
} catch (error) {
|
|
13681
|
+
if (!(error instanceof ChatStoreError) || error.status !== 404) throw error;
|
|
13682
|
+
}
|
|
13683
|
+
await cache?.delete(attachmentId).catch(() => void 0);
|
|
13684
|
+
};
|
|
13685
|
+
const discardPending = async (attachmentId) => {
|
|
13686
|
+
const found = await store.attachments.get(attachmentId);
|
|
13687
|
+
if (found?.attachment.state === "pending") await remove(attachmentId);
|
|
13688
|
+
};
|
|
13689
|
+
return {
|
|
13690
|
+
async upload(bytes4, uploadOptions) {
|
|
13691
|
+
const signal = uploadOptions?.signal;
|
|
13692
|
+
if (!(bytes4 instanceof Uint8Array) || bytes4.length > maxVaultAttachmentBytes)
|
|
13693
|
+
throw new ChatStoreError(
|
|
13694
|
+
"Attachment is larger than vault accepts",
|
|
13695
|
+
413,
|
|
13696
|
+
"attachment_too_large"
|
|
13697
|
+
);
|
|
13698
|
+
const size = bytes4.length + frameOverhead;
|
|
13699
|
+
for (let attempt = 0; ; attempt++) {
|
|
13700
|
+
const { attachment: attachment2, upload } = await withRetry(
|
|
13701
|
+
() => store.attachments.create(size, signal),
|
|
13702
|
+
signal
|
|
13703
|
+
);
|
|
13704
|
+
try {
|
|
13705
|
+
await uploadOptions?.onReserved?.(attachment2.id);
|
|
13706
|
+
const frame = await seal(bytes4, attachment2.id);
|
|
13707
|
+
if (await put(upload, frame, signal) === "stored") return attachment2.id;
|
|
13708
|
+
} catch (error) {
|
|
13709
|
+
await discardPending(attachment2.id).catch(() => void 0);
|
|
13710
|
+
throw error;
|
|
13711
|
+
}
|
|
13712
|
+
await remove(attachment2.id).catch(() => void 0);
|
|
13713
|
+
if (attempt >= retries)
|
|
13714
|
+
throw new ChatStoreError(
|
|
13715
|
+
"Attachment storage rejected the upload URL",
|
|
13716
|
+
403,
|
|
13717
|
+
"attachment_upload_rejected"
|
|
13718
|
+
);
|
|
13719
|
+
}
|
|
13720
|
+
},
|
|
13721
|
+
commit(attachmentId, owner, signal) {
|
|
13722
|
+
return withRetry(() => store.attachments.commit(attachmentId, owner, signal), signal);
|
|
13723
|
+
},
|
|
13724
|
+
async read(attachmentId, signal) {
|
|
13725
|
+
if (!attachmentIdPattern2.test(attachmentId)) invalidAttachment();
|
|
13726
|
+
const cached = await cache?.get(attachmentId).catch(() => null);
|
|
13727
|
+
if (cached) return cached;
|
|
13728
|
+
for (let attempt = 0; ; attempt++) {
|
|
13729
|
+
const found = await withRetry(() => store.attachments.get(attachmentId, signal), signal);
|
|
13730
|
+
if (!found?.download) return null;
|
|
13731
|
+
const frame = await download(found.download, signal);
|
|
13732
|
+
if (frame === "missing") return null;
|
|
13733
|
+
if (frame === "expired") {
|
|
13734
|
+
if (attempt >= retries)
|
|
13735
|
+
throw new ChatStoreError(
|
|
13736
|
+
"Attachment storage rejected the download URL",
|
|
13737
|
+
403,
|
|
13738
|
+
"attachment_download_rejected"
|
|
13739
|
+
);
|
|
13740
|
+
continue;
|
|
13741
|
+
}
|
|
13742
|
+
if (frame.length !== found.attachment.sizeBytes) invalidAttachment();
|
|
13743
|
+
const bytes4 = await open(frame, attachmentId);
|
|
13744
|
+
await cache?.set(attachmentId, bytes4).catch(() => void 0);
|
|
13745
|
+
return bytes4;
|
|
13746
|
+
}
|
|
13747
|
+
},
|
|
13748
|
+
delete: remove
|
|
13749
|
+
};
|
|
13750
|
+
}
|
|
13751
|
+
function validRef(value) {
|
|
13752
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
13753
|
+
const ref3 = value;
|
|
13754
|
+
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;
|
|
13755
|
+
}
|
|
13756
|
+
function vaultAttachmentRefs(record2) {
|
|
13757
|
+
const refs = record2.data.vaultAttachments;
|
|
13758
|
+
return Array.isArray(refs) ? refs.filter(validRef) : [];
|
|
13759
|
+
}
|
|
13760
|
+
function journalKey(messageId, fileId) {
|
|
13761
|
+
return JSON.stringify([messageId, fileId]);
|
|
13762
|
+
}
|
|
13763
|
+
async function migrateMessageAttachments(options) {
|
|
13764
|
+
const { store, attachments, journal, messageId, signal } = options;
|
|
13765
|
+
const now = options.now ?? Date.now;
|
|
13766
|
+
const owner = { kind: "message", id: messageId };
|
|
13767
|
+
const ownerGone = () => new ChatStoreError("Message is not in vault", 409, "attachment_owner_not_found");
|
|
13768
|
+
let snapshot = await store.get("message", messageId, signal);
|
|
13769
|
+
if (!snapshot || snapshot.record.isDeleted) throw ownerGone();
|
|
13770
|
+
const present = new Map(vaultAttachmentRefs(snapshot.record).map((r) => [r.fileId, r]));
|
|
13771
|
+
const uploadable = (attachment2) => attachment2.state === "pending" && now() < Date.parse(attachment2.createdAt) + uploadWindowMs;
|
|
13772
|
+
const lookup = async (attachmentId) => attachmentId && attachmentIdPattern2.test(attachmentId) ? (await store.attachments.get(attachmentId, signal))?.attachment ?? null : null;
|
|
13773
|
+
const bind = async (found) => {
|
|
13774
|
+
if (!found) return null;
|
|
13775
|
+
if (found.state === "committed")
|
|
13776
|
+
return found.ownerKind === owner.kind && found.ownerId === owner.id ? found : null;
|
|
13777
|
+
try {
|
|
13778
|
+
return await attachments.commit(found.id, owner, signal);
|
|
13779
|
+
} catch (error) {
|
|
13780
|
+
if (!(error instanceof ChatStoreError) || error.code !== "attachment_not_uploaded")
|
|
13781
|
+
throw error;
|
|
13782
|
+
if (uploadable(found)) return "busy";
|
|
13783
|
+
await attachments.delete(found.id, signal);
|
|
13784
|
+
return null;
|
|
13785
|
+
}
|
|
13786
|
+
};
|
|
13787
|
+
const added = [];
|
|
13788
|
+
const settled = [];
|
|
13789
|
+
const missing2 = [];
|
|
13790
|
+
const oversized = [];
|
|
13791
|
+
const deferred = [];
|
|
13792
|
+
const stale = /* @__PURE__ */ new Set();
|
|
13793
|
+
let uploaded = 0;
|
|
13794
|
+
for (const file of options.files) {
|
|
13795
|
+
signal?.throwIfAborted();
|
|
13796
|
+
const key3 = journalKey(messageId, file.fileId);
|
|
13797
|
+
const recorded = present.get(file.fileId);
|
|
13798
|
+
if (recorded) {
|
|
13799
|
+
const bound = await bind(await lookup(recorded.attachmentId));
|
|
13800
|
+
if (bound === "busy") {
|
|
13801
|
+
deferred.push(file.fileId);
|
|
13802
|
+
continue;
|
|
13803
|
+
}
|
|
13804
|
+
if (bound) {
|
|
13805
|
+
const stray = await lookup(await journal.get(key3));
|
|
13806
|
+
if (stray && stray.id !== recorded.attachmentId) {
|
|
13807
|
+
if (uploadable(stray)) continue;
|
|
13808
|
+
await attachments.delete(stray.id, signal);
|
|
13809
|
+
}
|
|
13810
|
+
settled.push(key3);
|
|
13811
|
+
continue;
|
|
13812
|
+
}
|
|
13813
|
+
stale.add(recorded.attachmentId);
|
|
13814
|
+
}
|
|
13815
|
+
const meta = { fileId: file.fileId, name: file.name, type: file.type };
|
|
13816
|
+
const resumed = await bind(await lookup(await journal.get(key3)));
|
|
13817
|
+
if (resumed === "busy") {
|
|
13818
|
+
deferred.push(file.fileId);
|
|
13819
|
+
continue;
|
|
13820
|
+
}
|
|
13821
|
+
if (resumed) {
|
|
13822
|
+
added.push({ attachmentId: resumed.id, ...meta, size: resumed.sizeBytes - frameOverhead });
|
|
13823
|
+
settled.push(key3);
|
|
13824
|
+
continue;
|
|
13825
|
+
}
|
|
13826
|
+
const bytes4 = await file.read();
|
|
13827
|
+
if (!bytes4) {
|
|
13828
|
+
missing2.push(file.fileId);
|
|
13829
|
+
continue;
|
|
13830
|
+
}
|
|
13831
|
+
if (bytes4.length > maxVaultAttachmentBytes) {
|
|
13832
|
+
oversized.push(file.fileId);
|
|
13833
|
+
continue;
|
|
13834
|
+
}
|
|
13835
|
+
const attachmentId = await attachments.upload(bytes4, {
|
|
13836
|
+
signal,
|
|
13837
|
+
onReserved: (id2) => journal.set(key3, id2)
|
|
13838
|
+
});
|
|
13839
|
+
uploaded++;
|
|
13840
|
+
await attachments.commit(attachmentId, owner, signal);
|
|
13841
|
+
added.push({ attachmentId, ...meta, size: bytes4.length });
|
|
13842
|
+
settled.push(key3);
|
|
13843
|
+
}
|
|
13844
|
+
const superseded = [];
|
|
13845
|
+
for (let attempt = 0; added.length > 0; attempt++) {
|
|
13846
|
+
const refs = new Map(vaultAttachmentRefs(snapshot.record).map((r) => [r.fileId, r]));
|
|
13847
|
+
superseded.length = 0;
|
|
13848
|
+
for (const ref3 of added) {
|
|
13849
|
+
const prior = refs.get(ref3.fileId);
|
|
13850
|
+
if (prior && prior.attachmentId !== ref3.attachmentId && !stale.has(prior.attachmentId))
|
|
13851
|
+
superseded.push(ref3.attachmentId);
|
|
13852
|
+
else refs.set(ref3.fileId, ref3);
|
|
13853
|
+
}
|
|
13854
|
+
if (superseded.length === added.length) break;
|
|
13855
|
+
try {
|
|
13856
|
+
[snapshot] = await store.putMany(
|
|
13857
|
+
[
|
|
13858
|
+
{
|
|
13859
|
+
record: {
|
|
13860
|
+
...snapshot.record,
|
|
13861
|
+
data: { ...snapshot.record.data, ...plain({ vaultAttachments: [...refs.values()] }) }
|
|
13862
|
+
},
|
|
13863
|
+
expectedVersion: snapshot.version
|
|
13864
|
+
}
|
|
13865
|
+
],
|
|
13866
|
+
signal
|
|
13867
|
+
);
|
|
13868
|
+
break;
|
|
13869
|
+
} catch (error) {
|
|
13870
|
+
if (!(error instanceof ChatStoreError) || error.code !== "version_conflict" || attempt + 1 >= maxRefWrites)
|
|
13871
|
+
throw error;
|
|
13872
|
+
const latest = await store.get("message", messageId, signal);
|
|
13873
|
+
if (!latest || latest.record.isDeleted) throw ownerGone();
|
|
13874
|
+
snapshot = latest;
|
|
13875
|
+
}
|
|
13876
|
+
}
|
|
13877
|
+
for (const id2 of superseded) await attachments.delete(id2, signal);
|
|
13878
|
+
for (const key3 of settled) await journal.set(key3, null);
|
|
13879
|
+
return { refs: vaultAttachmentRefs(snapshot.record), uploaded, missing: missing2, oversized, deferred };
|
|
13880
|
+
}
|
|
13881
|
+
|
|
13524
13882
|
// src/lib/chatStore/vaultBackend.ts
|
|
13525
13883
|
var import_uuid3 = require("uuid");
|
|
13526
13884
|
|
|
@@ -13660,6 +14018,7 @@ var resumableFields = [
|
|
|
13660
14018
|
"imageModel",
|
|
13661
14019
|
"files",
|
|
13662
14020
|
"fileIds",
|
|
14021
|
+
"vaultAttachments",
|
|
13663
14022
|
"usage",
|
|
13664
14023
|
"sources",
|
|
13665
14024
|
"responseDuration",
|
|
@@ -25944,7 +26303,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25944
26303
|
};
|
|
25945
26304
|
const mutate = (id2, change, edit, writeOptions) => serialized(id2, () => mutateLocked(id2, change, edit, writeOptions));
|
|
25946
26305
|
const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id2) => () => serialized(id2, inner), task)();
|
|
25947
|
-
const mutateMany = async (ids, change, edit, leaseToken, signal) => {
|
|
26306
|
+
const mutateMany = async (ids, change, edit, leaseToken, signal, includeEmbeddings = false) => {
|
|
25948
26307
|
const saved = /* @__PURE__ */ new Map();
|
|
25949
26308
|
const failed = /* @__PURE__ */ new Map();
|
|
25950
26309
|
for (const slice of chunks2([...new Set(ids)], MAX_BATCH)) {
|
|
@@ -25953,7 +26312,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25953
26312
|
const writes = [];
|
|
25954
26313
|
let read;
|
|
25955
26314
|
try {
|
|
25956
|
-
read = await readEveryState(slice, signal);
|
|
26315
|
+
read = await readEveryState(slice, signal, includeEmbeddings);
|
|
25957
26316
|
} catch (error) {
|
|
25958
26317
|
signal?.throwIfAborted();
|
|
25959
26318
|
for (const id2 of slice) failed.set(id2, error);
|
|
@@ -26012,21 +26371,55 @@ function createRemoteMemoryStore(options) {
|
|
|
26012
26371
|
}
|
|
26013
26372
|
return { saved, failed };
|
|
26014
26373
|
};
|
|
26015
|
-
const
|
|
26016
|
-
|
|
26017
|
-
|
|
26018
|
-
|
|
26019
|
-
|
|
26020
|
-
|
|
26021
|
-
const
|
|
26022
|
-
|
|
26023
|
-
|
|
26024
|
-
|
|
26025
|
-
|
|
26026
|
-
|
|
26027
|
-
|
|
26028
|
-
|
|
26029
|
-
|
|
26374
|
+
const pendingEmbeddings = /* @__PURE__ */ new Map();
|
|
26375
|
+
let embeddingActive = false;
|
|
26376
|
+
const drainEmbeddings = async () => {
|
|
26377
|
+
try {
|
|
26378
|
+
while (pendingEmbeddings.size) {
|
|
26379
|
+
const batch = /* @__PURE__ */ new Map();
|
|
26380
|
+
for (const [id2, content] of pendingEmbeddings) {
|
|
26381
|
+
pendingEmbeddings.delete(id2);
|
|
26382
|
+
batch.set(id2, content);
|
|
26383
|
+
if (batch.size === MAX_BATCH) break;
|
|
26384
|
+
}
|
|
26385
|
+
try {
|
|
26386
|
+
const vectors = await generateEmbeddings([...batch.values()], embeddingOptions);
|
|
26387
|
+
const embeddings2 = /* @__PURE__ */ new Map();
|
|
26388
|
+
[...batch.keys()].forEach((id2, i) => {
|
|
26389
|
+
try {
|
|
26390
|
+
embeddings2.set(id2, storedVector(vectors[i]));
|
|
26391
|
+
} catch (error) {
|
|
26392
|
+
getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
|
|
26393
|
+
}
|
|
26394
|
+
});
|
|
26395
|
+
if (!embeddings2.size) continue;
|
|
26396
|
+
const { failed } = await mutateMany(
|
|
26397
|
+
[...embeddings2.keys()],
|
|
26398
|
+
() => "embedding",
|
|
26399
|
+
(memory) => memory.content !== batch.get(memory.memory_id) || memory.embedding?.length ? null : {
|
|
26400
|
+
...memory,
|
|
26401
|
+
embedding: embeddings2.get(memory.memory_id),
|
|
26402
|
+
embedding_model: model
|
|
26403
|
+
},
|
|
26404
|
+
void 0,
|
|
26405
|
+
void 0,
|
|
26406
|
+
true
|
|
26407
|
+
);
|
|
26408
|
+
for (const error of failed.values())
|
|
26409
|
+
getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
|
|
26410
|
+
} catch (error) {
|
|
26411
|
+
getLogger().warn("[memory/remote-store] Failed to embed memories:", error);
|
|
26412
|
+
}
|
|
26413
|
+
}
|
|
26414
|
+
} finally {
|
|
26415
|
+
embeddingActive = false;
|
|
26416
|
+
}
|
|
26417
|
+
};
|
|
26418
|
+
const embedInBackground = (records) => {
|
|
26419
|
+
for (const { memory } of records) pendingEmbeddings.set(memory.memory_id, memory.content);
|
|
26420
|
+
if (embeddingActive || !pendingEmbeddings.size) return;
|
|
26421
|
+
embeddingActive = true;
|
|
26422
|
+
void drainEmbeddings();
|
|
26030
26423
|
};
|
|
26031
26424
|
const newRow = (input) => {
|
|
26032
26425
|
const now = Date.now();
|
|
@@ -26060,9 +26453,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26060
26453
|
};
|
|
26061
26454
|
};
|
|
26062
26455
|
const created = (records, inputs) => {
|
|
26063
|
-
records.
|
|
26064
|
-
if (inputs[i].embedding === void 0) embedInBackground(record2);
|
|
26065
|
-
});
|
|
26456
|
+
embedInBackground(records.filter((_, i) => inputs[i].embedding === void 0));
|
|
26066
26457
|
notify("membership", records);
|
|
26067
26458
|
return records.map((record2) => stored(record2.memory));
|
|
26068
26459
|
};
|
|
@@ -26092,7 +26483,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26092
26483
|
};
|
|
26093
26484
|
};
|
|
26094
26485
|
const withKnownKinds = async (topics) => topics.map(await knownKinds(topics));
|
|
26095
|
-
const readEveryState = async (ids, signal) => {
|
|
26486
|
+
const readEveryState = async (ids, signal, includeEmbeddings = false) => {
|
|
26096
26487
|
const records = /* @__PURE__ */ new Map();
|
|
26097
26488
|
const unreadable = /* @__PURE__ */ new Set();
|
|
26098
26489
|
for (const memory_ids of chunks2(ids, MAX_QUERY_IDS)) {
|
|
@@ -26104,6 +26495,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26104
26495
|
include_archived: true,
|
|
26105
26496
|
include_quarantined: true,
|
|
26106
26497
|
include_superseded: true,
|
|
26498
|
+
...includeEmbeddings && { include_embeddings: true },
|
|
26107
26499
|
limit: 200,
|
|
26108
26500
|
...signal && { signal },
|
|
26109
26501
|
...cursor2 && { cursor: cursor2 }
|
|
@@ -26766,7 +27158,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26766
27158
|
}
|
|
26767
27159
|
return memory;
|
|
26768
27160
|
});
|
|
26769
|
-
if (saved && patch.embedding === void 0) embedInBackground(saved);
|
|
27161
|
+
if (saved && patch.embedding === void 0) embedInBackground([saved]);
|
|
26770
27162
|
return asStored(saved);
|
|
26771
27163
|
},
|
|
26772
27164
|
delete: async (id2) => !!await mutate(id2, "membership", (memory) => ({ ...memory, is_deleted: true })),
|
|
@@ -34081,6 +34473,7 @@ function useChatStorage(options) {
|
|
|
34081
34473
|
createSelectPaymentWalletTool,
|
|
34082
34474
|
createStockPricePreProcessor,
|
|
34083
34475
|
createStreamingDeAnonymizer,
|
|
34476
|
+
createVaultAttachments,
|
|
34084
34477
|
createVaultChatBackend,
|
|
34085
34478
|
createVaultEmbeddingCache,
|
|
34086
34479
|
createVaultFolderOp,
|
|
@@ -34145,9 +34538,11 @@ function useChatStorage(options) {
|
|
|
34145
34538
|
isRerankerAvailable,
|
|
34146
34539
|
localChatBackend,
|
|
34147
34540
|
maskScopedEmbeddingCache,
|
|
34541
|
+
maxVaultAttachmentBytes,
|
|
34148
34542
|
memoryCipher,
|
|
34149
34543
|
migrateChatsToRemote,
|
|
34150
34544
|
migrateMemoriesToRemote,
|
|
34545
|
+
migrateMessageAttachments,
|
|
34151
34546
|
moveMemoriesToFolderOp,
|
|
34152
34547
|
noopLogger,
|
|
34153
34548
|
onKeyAvailable,
|
|
@@ -34201,6 +34596,7 @@ function useChatStorage(options) {
|
|
|
34201
34596
|
useCredits,
|
|
34202
34597
|
useEncryption,
|
|
34203
34598
|
useModels,
|
|
34599
|
+
vaultAttachmentRefs,
|
|
34204
34600
|
vaultChatBackend,
|
|
34205
34601
|
verifyMemoriesForPublish,
|
|
34206
34602
|
xhrTransport
|