@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.mjs
CHANGED
|
@@ -12423,6 +12423,360 @@ async function migrateChatsToRemote(options) {
|
|
|
12423
12423
|
return passes(false);
|
|
12424
12424
|
}
|
|
12425
12425
|
|
|
12426
|
+
// src/lib/chatStore/vaultAttachments.ts
|
|
12427
|
+
var frameVersion = 1;
|
|
12428
|
+
var ivBytes = 12;
|
|
12429
|
+
var tagBytes = 16;
|
|
12430
|
+
var frameOverhead = 1 + ivBytes + tagBytes;
|
|
12431
|
+
var maxCiphertextBytes = 50 * 1024 * 1024;
|
|
12432
|
+
var expirySkewMs = 3e4;
|
|
12433
|
+
var maxRetryAfterMs = 3e4;
|
|
12434
|
+
var maxRefWrites = 5;
|
|
12435
|
+
var uploadWindowMs = 16 * 6e4;
|
|
12436
|
+
var attachmentIdPattern2 = /^[0-9a-f]{32}$/;
|
|
12437
|
+
var maxVaultAttachmentBytes = maxCiphertextBytes - frameOverhead;
|
|
12438
|
+
function additionalData(attachmentId) {
|
|
12439
|
+
return new TextEncoder().encode(`anuma-chat-attachment-v1:${attachmentId}`);
|
|
12440
|
+
}
|
|
12441
|
+
function invalidAttachment() {
|
|
12442
|
+
throw new ChatStoreError("Attachment does not decrypt under this key", 0, "invalid_attachment");
|
|
12443
|
+
}
|
|
12444
|
+
function sendableHeaders(headers) {
|
|
12445
|
+
return Object.fromEntries(
|
|
12446
|
+
Object.entries(headers).filter(([name]) => name.toLowerCase() !== "content-length")
|
|
12447
|
+
);
|
|
12448
|
+
}
|
|
12449
|
+
function transientStatus(status) {
|
|
12450
|
+
return status === 429 || status >= 500;
|
|
12451
|
+
}
|
|
12452
|
+
async function discardBody(response) {
|
|
12453
|
+
await response.body?.cancel().catch(() => void 0);
|
|
12454
|
+
}
|
|
12455
|
+
function createVaultAttachments(options) {
|
|
12456
|
+
const { store, keyRing, cache } = options;
|
|
12457
|
+
const fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
12458
|
+
const retries = options.retries ?? 3;
|
|
12459
|
+
const retryDelayMs = options.retryDelayMs ?? 500;
|
|
12460
|
+
const now = options.now ?? Date.now;
|
|
12461
|
+
const sleep3 = (ms2, signal) => new Promise((resolve, reject) => {
|
|
12462
|
+
signal?.throwIfAborted();
|
|
12463
|
+
const timer = setTimeout(() => {
|
|
12464
|
+
signal?.removeEventListener("abort", onAbort);
|
|
12465
|
+
resolve();
|
|
12466
|
+
}, ms2);
|
|
12467
|
+
const onAbort = () => {
|
|
12468
|
+
clearTimeout(timer);
|
|
12469
|
+
reject(signal?.reason);
|
|
12470
|
+
};
|
|
12471
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
12472
|
+
});
|
|
12473
|
+
const pause = (attempt, signal, atLeast = 0) => sleep3(Math.max(atLeast, retryDelayMs * 2 ** attempt), signal);
|
|
12474
|
+
const withRetry = async (call, signal) => {
|
|
12475
|
+
for (let attempt = 0; ; attempt++) {
|
|
12476
|
+
try {
|
|
12477
|
+
return await call();
|
|
12478
|
+
} catch (error) {
|
|
12479
|
+
if (!(error instanceof ChatStoreError) || !transientStatus(error.status) || attempt >= retries || (error.retryAfterMs ?? 0) > maxRetryAfterMs)
|
|
12480
|
+
throw error;
|
|
12481
|
+
await pause(attempt, signal, error.retryAfterMs);
|
|
12482
|
+
}
|
|
12483
|
+
}
|
|
12484
|
+
};
|
|
12485
|
+
const expired = (url) => now() >= Date.parse(url.expiresAt) - expirySkewMs;
|
|
12486
|
+
const seal = async (bytes4, attachmentId) => {
|
|
12487
|
+
const iv = crypto.getRandomValues(new Uint8Array(ivBytes));
|
|
12488
|
+
const sealed2 = new Uint8Array(
|
|
12489
|
+
await crypto.subtle.encrypt(
|
|
12490
|
+
{ name: "AES-GCM", iv, additionalData: additionalData(attachmentId) },
|
|
12491
|
+
keyRing.v3,
|
|
12492
|
+
bytes4
|
|
12493
|
+
)
|
|
12494
|
+
);
|
|
12495
|
+
const frame = new Uint8Array(1 + ivBytes + sealed2.length);
|
|
12496
|
+
frame[0] = frameVersion;
|
|
12497
|
+
frame.set(iv, 1);
|
|
12498
|
+
frame.set(sealed2, 1 + ivBytes);
|
|
12499
|
+
return frame;
|
|
12500
|
+
};
|
|
12501
|
+
const open = async (frame, attachmentId) => {
|
|
12502
|
+
if (frame.length < frameOverhead || frame[0] !== frameVersion) invalidAttachment();
|
|
12503
|
+
try {
|
|
12504
|
+
return new Uint8Array(
|
|
12505
|
+
await crypto.subtle.decrypt(
|
|
12506
|
+
{
|
|
12507
|
+
name: "AES-GCM",
|
|
12508
|
+
iv: frame.slice(1, 1 + ivBytes),
|
|
12509
|
+
additionalData: additionalData(attachmentId)
|
|
12510
|
+
},
|
|
12511
|
+
keyRing.v3,
|
|
12512
|
+
frame.slice(1 + ivBytes)
|
|
12513
|
+
)
|
|
12514
|
+
);
|
|
12515
|
+
} catch {
|
|
12516
|
+
return invalidAttachment();
|
|
12517
|
+
}
|
|
12518
|
+
};
|
|
12519
|
+
const put = async (upload, body, signal) => {
|
|
12520
|
+
for (let attempt = 0; ; attempt++) {
|
|
12521
|
+
if (expired(upload)) return "expired";
|
|
12522
|
+
let response;
|
|
12523
|
+
try {
|
|
12524
|
+
response = await fetcher(upload.url, {
|
|
12525
|
+
method: upload.method,
|
|
12526
|
+
headers: sendableHeaders(upload.headers),
|
|
12527
|
+
body,
|
|
12528
|
+
signal
|
|
12529
|
+
});
|
|
12530
|
+
} catch (error) {
|
|
12531
|
+
if (signal?.aborted || attempt >= retries) throw error;
|
|
12532
|
+
await pause(attempt, signal);
|
|
12533
|
+
continue;
|
|
12534
|
+
}
|
|
12535
|
+
await discardBody(response);
|
|
12536
|
+
if (response.ok) return "stored";
|
|
12537
|
+
if (response.status === 403) return "expired";
|
|
12538
|
+
if (!transientStatus(response.status) || attempt >= retries)
|
|
12539
|
+
throw new ChatStoreError(
|
|
12540
|
+
`Attachment upload failed with ${response.status}`,
|
|
12541
|
+
response.status,
|
|
12542
|
+
"attachment_upload_failed"
|
|
12543
|
+
);
|
|
12544
|
+
await pause(attempt, signal);
|
|
12545
|
+
}
|
|
12546
|
+
};
|
|
12547
|
+
const download = async (url, signal) => {
|
|
12548
|
+
for (let attempt = 0; ; attempt++) {
|
|
12549
|
+
if (expired(url)) return "expired";
|
|
12550
|
+
let response;
|
|
12551
|
+
try {
|
|
12552
|
+
response = await fetcher(url.url, {
|
|
12553
|
+
method: url.method,
|
|
12554
|
+
headers: sendableHeaders(url.headers),
|
|
12555
|
+
signal
|
|
12556
|
+
});
|
|
12557
|
+
if (response.ok) return new Uint8Array(await response.arrayBuffer());
|
|
12558
|
+
} catch (error) {
|
|
12559
|
+
if (signal?.aborted || attempt >= retries) throw error;
|
|
12560
|
+
await pause(attempt, signal);
|
|
12561
|
+
continue;
|
|
12562
|
+
}
|
|
12563
|
+
await discardBody(response);
|
|
12564
|
+
if (response.status === 403) return "expired";
|
|
12565
|
+
if (response.status === 404) return "missing";
|
|
12566
|
+
if (!transientStatus(response.status) || attempt >= retries)
|
|
12567
|
+
throw new ChatStoreError(
|
|
12568
|
+
`Attachment download failed with ${response.status}`,
|
|
12569
|
+
response.status,
|
|
12570
|
+
"attachment_download_failed"
|
|
12571
|
+
);
|
|
12572
|
+
await pause(attempt, signal);
|
|
12573
|
+
}
|
|
12574
|
+
};
|
|
12575
|
+
const remove = async (attachmentId, signal) => {
|
|
12576
|
+
try {
|
|
12577
|
+
await withRetry(() => store.attachments.delete(attachmentId, signal), signal);
|
|
12578
|
+
} catch (error) {
|
|
12579
|
+
if (!(error instanceof ChatStoreError) || error.status !== 404) throw error;
|
|
12580
|
+
}
|
|
12581
|
+
await cache?.delete(attachmentId).catch(() => void 0);
|
|
12582
|
+
};
|
|
12583
|
+
const discardPending = async (attachmentId) => {
|
|
12584
|
+
const found = await store.attachments.get(attachmentId);
|
|
12585
|
+
if (found?.attachment.state === "pending") await remove(attachmentId);
|
|
12586
|
+
};
|
|
12587
|
+
return {
|
|
12588
|
+
async upload(bytes4, uploadOptions) {
|
|
12589
|
+
const signal = uploadOptions?.signal;
|
|
12590
|
+
if (!(bytes4 instanceof Uint8Array) || bytes4.length > maxVaultAttachmentBytes)
|
|
12591
|
+
throw new ChatStoreError(
|
|
12592
|
+
"Attachment is larger than vault accepts",
|
|
12593
|
+
413,
|
|
12594
|
+
"attachment_too_large"
|
|
12595
|
+
);
|
|
12596
|
+
const size = bytes4.length + frameOverhead;
|
|
12597
|
+
for (let attempt = 0; ; attempt++) {
|
|
12598
|
+
const { attachment: attachment2, upload } = await withRetry(
|
|
12599
|
+
() => store.attachments.create(size, signal),
|
|
12600
|
+
signal
|
|
12601
|
+
);
|
|
12602
|
+
try {
|
|
12603
|
+
await uploadOptions?.onReserved?.(attachment2.id);
|
|
12604
|
+
const frame = await seal(bytes4, attachment2.id);
|
|
12605
|
+
if (await put(upload, frame, signal) === "stored") return attachment2.id;
|
|
12606
|
+
} catch (error) {
|
|
12607
|
+
await discardPending(attachment2.id).catch(() => void 0);
|
|
12608
|
+
throw error;
|
|
12609
|
+
}
|
|
12610
|
+
await remove(attachment2.id).catch(() => void 0);
|
|
12611
|
+
if (attempt >= retries)
|
|
12612
|
+
throw new ChatStoreError(
|
|
12613
|
+
"Attachment storage rejected the upload URL",
|
|
12614
|
+
403,
|
|
12615
|
+
"attachment_upload_rejected"
|
|
12616
|
+
);
|
|
12617
|
+
}
|
|
12618
|
+
},
|
|
12619
|
+
commit(attachmentId, owner, signal) {
|
|
12620
|
+
return withRetry(() => store.attachments.commit(attachmentId, owner, signal), signal);
|
|
12621
|
+
},
|
|
12622
|
+
async read(attachmentId, signal) {
|
|
12623
|
+
if (!attachmentIdPattern2.test(attachmentId)) invalidAttachment();
|
|
12624
|
+
const cached = await cache?.get(attachmentId).catch(() => null);
|
|
12625
|
+
if (cached) return cached;
|
|
12626
|
+
for (let attempt = 0; ; attempt++) {
|
|
12627
|
+
const found = await withRetry(() => store.attachments.get(attachmentId, signal), signal);
|
|
12628
|
+
if (!found?.download) return null;
|
|
12629
|
+
const frame = await download(found.download, signal);
|
|
12630
|
+
if (frame === "missing") return null;
|
|
12631
|
+
if (frame === "expired") {
|
|
12632
|
+
if (attempt >= retries)
|
|
12633
|
+
throw new ChatStoreError(
|
|
12634
|
+
"Attachment storage rejected the download URL",
|
|
12635
|
+
403,
|
|
12636
|
+
"attachment_download_rejected"
|
|
12637
|
+
);
|
|
12638
|
+
continue;
|
|
12639
|
+
}
|
|
12640
|
+
if (frame.length !== found.attachment.sizeBytes) invalidAttachment();
|
|
12641
|
+
const bytes4 = await open(frame, attachmentId);
|
|
12642
|
+
await cache?.set(attachmentId, bytes4).catch(() => void 0);
|
|
12643
|
+
return bytes4;
|
|
12644
|
+
}
|
|
12645
|
+
},
|
|
12646
|
+
delete: remove
|
|
12647
|
+
};
|
|
12648
|
+
}
|
|
12649
|
+
function validRef(value) {
|
|
12650
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
12651
|
+
const ref3 = value;
|
|
12652
|
+
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;
|
|
12653
|
+
}
|
|
12654
|
+
function vaultAttachmentRefs(record2) {
|
|
12655
|
+
const refs = record2.data.vaultAttachments;
|
|
12656
|
+
return Array.isArray(refs) ? refs.filter(validRef) : [];
|
|
12657
|
+
}
|
|
12658
|
+
function journalKey(messageId, fileId) {
|
|
12659
|
+
return JSON.stringify([messageId, fileId]);
|
|
12660
|
+
}
|
|
12661
|
+
async function migrateMessageAttachments(options) {
|
|
12662
|
+
const { store, attachments, journal, messageId, signal } = options;
|
|
12663
|
+
const now = options.now ?? Date.now;
|
|
12664
|
+
const owner = { kind: "message", id: messageId };
|
|
12665
|
+
const ownerGone = () => new ChatStoreError("Message is not in vault", 409, "attachment_owner_not_found");
|
|
12666
|
+
let snapshot = await store.get("message", messageId, signal);
|
|
12667
|
+
if (!snapshot || snapshot.record.isDeleted) throw ownerGone();
|
|
12668
|
+
const present = new Map(vaultAttachmentRefs(snapshot.record).map((r) => [r.fileId, r]));
|
|
12669
|
+
const uploadable = (attachment2) => attachment2.state === "pending" && now() < Date.parse(attachment2.createdAt) + uploadWindowMs;
|
|
12670
|
+
const lookup = async (attachmentId) => attachmentId && attachmentIdPattern2.test(attachmentId) ? (await store.attachments.get(attachmentId, signal))?.attachment ?? null : null;
|
|
12671
|
+
const bind = async (found) => {
|
|
12672
|
+
if (!found) return null;
|
|
12673
|
+
if (found.state === "committed")
|
|
12674
|
+
return found.ownerKind === owner.kind && found.ownerId === owner.id ? found : null;
|
|
12675
|
+
try {
|
|
12676
|
+
return await attachments.commit(found.id, owner, signal);
|
|
12677
|
+
} catch (error) {
|
|
12678
|
+
if (!(error instanceof ChatStoreError) || error.code !== "attachment_not_uploaded")
|
|
12679
|
+
throw error;
|
|
12680
|
+
if (uploadable(found)) return "busy";
|
|
12681
|
+
await attachments.delete(found.id, signal);
|
|
12682
|
+
return null;
|
|
12683
|
+
}
|
|
12684
|
+
};
|
|
12685
|
+
const added = [];
|
|
12686
|
+
const settled = [];
|
|
12687
|
+
const missing2 = [];
|
|
12688
|
+
const oversized = [];
|
|
12689
|
+
const deferred = [];
|
|
12690
|
+
const stale = /* @__PURE__ */ new Set();
|
|
12691
|
+
let uploaded = 0;
|
|
12692
|
+
for (const file of options.files) {
|
|
12693
|
+
signal?.throwIfAborted();
|
|
12694
|
+
const key3 = journalKey(messageId, file.fileId);
|
|
12695
|
+
const recorded = present.get(file.fileId);
|
|
12696
|
+
if (recorded) {
|
|
12697
|
+
const bound = await bind(await lookup(recorded.attachmentId));
|
|
12698
|
+
if (bound === "busy") {
|
|
12699
|
+
deferred.push(file.fileId);
|
|
12700
|
+
continue;
|
|
12701
|
+
}
|
|
12702
|
+
if (bound) {
|
|
12703
|
+
const stray = await lookup(await journal.get(key3));
|
|
12704
|
+
if (stray && stray.id !== recorded.attachmentId) {
|
|
12705
|
+
if (uploadable(stray)) continue;
|
|
12706
|
+
await attachments.delete(stray.id, signal);
|
|
12707
|
+
}
|
|
12708
|
+
settled.push(key3);
|
|
12709
|
+
continue;
|
|
12710
|
+
}
|
|
12711
|
+
stale.add(recorded.attachmentId);
|
|
12712
|
+
}
|
|
12713
|
+
const meta = { fileId: file.fileId, name: file.name, type: file.type };
|
|
12714
|
+
const resumed = await bind(await lookup(await journal.get(key3)));
|
|
12715
|
+
if (resumed === "busy") {
|
|
12716
|
+
deferred.push(file.fileId);
|
|
12717
|
+
continue;
|
|
12718
|
+
}
|
|
12719
|
+
if (resumed) {
|
|
12720
|
+
added.push({ attachmentId: resumed.id, ...meta, size: resumed.sizeBytes - frameOverhead });
|
|
12721
|
+
settled.push(key3);
|
|
12722
|
+
continue;
|
|
12723
|
+
}
|
|
12724
|
+
const bytes4 = await file.read();
|
|
12725
|
+
if (!bytes4) {
|
|
12726
|
+
missing2.push(file.fileId);
|
|
12727
|
+
continue;
|
|
12728
|
+
}
|
|
12729
|
+
if (bytes4.length > maxVaultAttachmentBytes) {
|
|
12730
|
+
oversized.push(file.fileId);
|
|
12731
|
+
continue;
|
|
12732
|
+
}
|
|
12733
|
+
const attachmentId = await attachments.upload(bytes4, {
|
|
12734
|
+
signal,
|
|
12735
|
+
onReserved: (id2) => journal.set(key3, id2)
|
|
12736
|
+
});
|
|
12737
|
+
uploaded++;
|
|
12738
|
+
await attachments.commit(attachmentId, owner, signal);
|
|
12739
|
+
added.push({ attachmentId, ...meta, size: bytes4.length });
|
|
12740
|
+
settled.push(key3);
|
|
12741
|
+
}
|
|
12742
|
+
const superseded = [];
|
|
12743
|
+
for (let attempt = 0; added.length > 0; attempt++) {
|
|
12744
|
+
const refs = new Map(vaultAttachmentRefs(snapshot.record).map((r) => [r.fileId, r]));
|
|
12745
|
+
superseded.length = 0;
|
|
12746
|
+
for (const ref3 of added) {
|
|
12747
|
+
const prior = refs.get(ref3.fileId);
|
|
12748
|
+
if (prior && prior.attachmentId !== ref3.attachmentId && !stale.has(prior.attachmentId))
|
|
12749
|
+
superseded.push(ref3.attachmentId);
|
|
12750
|
+
else refs.set(ref3.fileId, ref3);
|
|
12751
|
+
}
|
|
12752
|
+
if (superseded.length === added.length) break;
|
|
12753
|
+
try {
|
|
12754
|
+
[snapshot] = await store.putMany(
|
|
12755
|
+
[
|
|
12756
|
+
{
|
|
12757
|
+
record: {
|
|
12758
|
+
...snapshot.record,
|
|
12759
|
+
data: { ...snapshot.record.data, ...plain({ vaultAttachments: [...refs.values()] }) }
|
|
12760
|
+
},
|
|
12761
|
+
expectedVersion: snapshot.version
|
|
12762
|
+
}
|
|
12763
|
+
],
|
|
12764
|
+
signal
|
|
12765
|
+
);
|
|
12766
|
+
break;
|
|
12767
|
+
} catch (error) {
|
|
12768
|
+
if (!(error instanceof ChatStoreError) || error.code !== "version_conflict" || attempt + 1 >= maxRefWrites)
|
|
12769
|
+
throw error;
|
|
12770
|
+
const latest = await store.get("message", messageId, signal);
|
|
12771
|
+
if (!latest || latest.record.isDeleted) throw ownerGone();
|
|
12772
|
+
snapshot = latest;
|
|
12773
|
+
}
|
|
12774
|
+
}
|
|
12775
|
+
for (const id2 of superseded) await attachments.delete(id2, signal);
|
|
12776
|
+
for (const key3 of settled) await journal.set(key3, null);
|
|
12777
|
+
return { refs: vaultAttachmentRefs(snapshot.record), uploaded, missing: missing2, oversized, deferred };
|
|
12778
|
+
}
|
|
12779
|
+
|
|
12426
12780
|
// src/lib/chatStore/vaultBackend.ts
|
|
12427
12781
|
import { v7 as uuidv73 } from "uuid";
|
|
12428
12782
|
|
|
@@ -12562,6 +12916,7 @@ var resumableFields = [
|
|
|
12562
12916
|
"imageModel",
|
|
12563
12917
|
"files",
|
|
12564
12918
|
"fileIds",
|
|
12919
|
+
"vaultAttachments",
|
|
12565
12920
|
"usage",
|
|
12566
12921
|
"sources",
|
|
12567
12922
|
"responseDuration",
|
|
@@ -26353,7 +26708,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26353
26708
|
};
|
|
26354
26709
|
const mutate = (id2, change, edit, writeOptions) => serialized(id2, () => mutateLocked(id2, change, edit, writeOptions));
|
|
26355
26710
|
const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id2) => () => serialized(id2, inner), task)();
|
|
26356
|
-
const mutateMany = async (ids, change, edit, leaseToken, signal) => {
|
|
26711
|
+
const mutateMany = async (ids, change, edit, leaseToken, signal, includeEmbeddings = false) => {
|
|
26357
26712
|
const saved = /* @__PURE__ */ new Map();
|
|
26358
26713
|
const failed = /* @__PURE__ */ new Map();
|
|
26359
26714
|
for (const slice of chunks2([...new Set(ids)], MAX_BATCH)) {
|
|
@@ -26362,7 +26717,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26362
26717
|
const writes = [];
|
|
26363
26718
|
let read;
|
|
26364
26719
|
try {
|
|
26365
|
-
read = await readEveryState(slice, signal);
|
|
26720
|
+
read = await readEveryState(slice, signal, includeEmbeddings);
|
|
26366
26721
|
} catch (error) {
|
|
26367
26722
|
signal?.throwIfAborted();
|
|
26368
26723
|
for (const id2 of slice) failed.set(id2, error);
|
|
@@ -26421,21 +26776,55 @@ function createRemoteMemoryStore(options) {
|
|
|
26421
26776
|
}
|
|
26422
26777
|
return { saved, failed };
|
|
26423
26778
|
};
|
|
26424
|
-
const
|
|
26425
|
-
|
|
26426
|
-
|
|
26427
|
-
|
|
26428
|
-
|
|
26429
|
-
|
|
26430
|
-
const
|
|
26431
|
-
|
|
26432
|
-
|
|
26433
|
-
|
|
26434
|
-
|
|
26435
|
-
|
|
26436
|
-
|
|
26437
|
-
|
|
26438
|
-
|
|
26779
|
+
const pendingEmbeddings = /* @__PURE__ */ new Map();
|
|
26780
|
+
let embeddingActive = false;
|
|
26781
|
+
const drainEmbeddings = async () => {
|
|
26782
|
+
try {
|
|
26783
|
+
while (pendingEmbeddings.size) {
|
|
26784
|
+
const batch = /* @__PURE__ */ new Map();
|
|
26785
|
+
for (const [id2, content] of pendingEmbeddings) {
|
|
26786
|
+
pendingEmbeddings.delete(id2);
|
|
26787
|
+
batch.set(id2, content);
|
|
26788
|
+
if (batch.size === MAX_BATCH) break;
|
|
26789
|
+
}
|
|
26790
|
+
try {
|
|
26791
|
+
const vectors = await generateEmbeddings([...batch.values()], embeddingOptions);
|
|
26792
|
+
const embeddings2 = /* @__PURE__ */ new Map();
|
|
26793
|
+
[...batch.keys()].forEach((id2, i) => {
|
|
26794
|
+
try {
|
|
26795
|
+
embeddings2.set(id2, storedVector(vectors[i]));
|
|
26796
|
+
} catch (error) {
|
|
26797
|
+
getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
|
|
26798
|
+
}
|
|
26799
|
+
});
|
|
26800
|
+
if (!embeddings2.size) continue;
|
|
26801
|
+
const { failed } = await mutateMany(
|
|
26802
|
+
[...embeddings2.keys()],
|
|
26803
|
+
() => "embedding",
|
|
26804
|
+
(memory) => memory.content !== batch.get(memory.memory_id) || memory.embedding?.length ? null : {
|
|
26805
|
+
...memory,
|
|
26806
|
+
embedding: embeddings2.get(memory.memory_id),
|
|
26807
|
+
embedding_model: model
|
|
26808
|
+
},
|
|
26809
|
+
void 0,
|
|
26810
|
+
void 0,
|
|
26811
|
+
true
|
|
26812
|
+
);
|
|
26813
|
+
for (const error of failed.values())
|
|
26814
|
+
getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
|
|
26815
|
+
} catch (error) {
|
|
26816
|
+
getLogger().warn("[memory/remote-store] Failed to embed memories:", error);
|
|
26817
|
+
}
|
|
26818
|
+
}
|
|
26819
|
+
} finally {
|
|
26820
|
+
embeddingActive = false;
|
|
26821
|
+
}
|
|
26822
|
+
};
|
|
26823
|
+
const embedInBackground = (records) => {
|
|
26824
|
+
for (const { memory } of records) pendingEmbeddings.set(memory.memory_id, memory.content);
|
|
26825
|
+
if (embeddingActive || !pendingEmbeddings.size) return;
|
|
26826
|
+
embeddingActive = true;
|
|
26827
|
+
void drainEmbeddings();
|
|
26439
26828
|
};
|
|
26440
26829
|
const newRow = (input) => {
|
|
26441
26830
|
const now = Date.now();
|
|
@@ -26469,9 +26858,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26469
26858
|
};
|
|
26470
26859
|
};
|
|
26471
26860
|
const created = (records, inputs) => {
|
|
26472
|
-
records.
|
|
26473
|
-
if (inputs[i].embedding === void 0) embedInBackground(record2);
|
|
26474
|
-
});
|
|
26861
|
+
embedInBackground(records.filter((_, i) => inputs[i].embedding === void 0));
|
|
26475
26862
|
notify("membership", records);
|
|
26476
26863
|
return records.map((record2) => stored(record2.memory));
|
|
26477
26864
|
};
|
|
@@ -26501,7 +26888,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26501
26888
|
};
|
|
26502
26889
|
};
|
|
26503
26890
|
const withKnownKinds = async (topics) => topics.map(await knownKinds(topics));
|
|
26504
|
-
const readEveryState = async (ids, signal) => {
|
|
26891
|
+
const readEveryState = async (ids, signal, includeEmbeddings = false) => {
|
|
26505
26892
|
const records = /* @__PURE__ */ new Map();
|
|
26506
26893
|
const unreadable = /* @__PURE__ */ new Set();
|
|
26507
26894
|
for (const memory_ids of chunks2(ids, MAX_QUERY_IDS)) {
|
|
@@ -26513,6 +26900,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26513
26900
|
include_archived: true,
|
|
26514
26901
|
include_quarantined: true,
|
|
26515
26902
|
include_superseded: true,
|
|
26903
|
+
...includeEmbeddings && { include_embeddings: true },
|
|
26516
26904
|
limit: 200,
|
|
26517
26905
|
...signal && { signal },
|
|
26518
26906
|
...cursor2 && { cursor: cursor2 }
|
|
@@ -27175,7 +27563,7 @@ function createRemoteMemoryStore(options) {
|
|
|
27175
27563
|
}
|
|
27176
27564
|
return memory;
|
|
27177
27565
|
});
|
|
27178
|
-
if (saved && patch.embedding === void 0) embedInBackground(saved);
|
|
27566
|
+
if (saved && patch.embedding === void 0) embedInBackground([saved]);
|
|
27179
27567
|
return asStored(saved);
|
|
27180
27568
|
},
|
|
27181
27569
|
delete: async (id2) => !!await mutate(id2, "membership", (memory) => ({ ...memory, is_deleted: true })),
|
|
@@ -40212,6 +40600,7 @@ export {
|
|
|
40212
40600
|
createSelectPaymentWalletTool,
|
|
40213
40601
|
createServerToolsFilter,
|
|
40214
40602
|
createStockPricePreProcessor,
|
|
40603
|
+
createVaultAttachments,
|
|
40215
40604
|
createVaultChatBackend,
|
|
40216
40605
|
createVaultEmbeddingCache,
|
|
40217
40606
|
createVaultFolderOp,
|
|
@@ -40361,11 +40750,13 @@ export {
|
|
|
40361
40750
|
linkMemoryEntitiesOp,
|
|
40362
40751
|
localChatBackend,
|
|
40363
40752
|
maskScopedEmbeddingCache,
|
|
40753
|
+
maxVaultAttachmentBytes,
|
|
40364
40754
|
mediaToStored,
|
|
40365
40755
|
memoryCipher,
|
|
40366
40756
|
migrateChatsToRemote,
|
|
40367
40757
|
migrateDisplayResult,
|
|
40368
40758
|
migrateMemoriesToRemote,
|
|
40759
|
+
migrateMessageAttachments,
|
|
40369
40760
|
migrateNotionClientRegistration,
|
|
40370
40761
|
migrateNotionToken,
|
|
40371
40762
|
moveMemoriesToFolderOp,
|
|
@@ -40474,6 +40865,7 @@ export {
|
|
|
40474
40865
|
useVoice,
|
|
40475
40866
|
useWalletBinding,
|
|
40476
40867
|
userPreferencesStorageSchema,
|
|
40868
|
+
vaultAttachmentRefs,
|
|
40477
40869
|
vaultChatBackend,
|
|
40478
40870
|
verifyMemoriesForPublish,
|
|
40479
40871
|
walk,
|
package/dist/server/index.d.mts
CHANGED
|
@@ -7389,6 +7389,14 @@ interface FileMetadata {
|
|
|
7389
7389
|
*/
|
|
7390
7390
|
sourceUrl?: string;
|
|
7391
7391
|
}
|
|
7392
|
+
/** Points a message's local file (`FileMetadata.id` or a `fileIds` media id) at its encrypted copy in vault, so any device can fetch it. */
|
|
7393
|
+
interface VaultAttachmentRef {
|
|
7394
|
+
attachmentId: string;
|
|
7395
|
+
fileId: string;
|
|
7396
|
+
name: string;
|
|
7397
|
+
type: string;
|
|
7398
|
+
size: number;
|
|
7399
|
+
}
|
|
7392
7400
|
interface ChatCompletionUsage {
|
|
7393
7401
|
promptTokens?: number;
|
|
7394
7402
|
completionTokens?: number;
|
|
@@ -7492,6 +7500,7 @@ interface StoredMessage {
|
|
|
7492
7500
|
files?: FileMetadata[];
|
|
7493
7501
|
/** Array of media_id references for direct lookup in media table */
|
|
7494
7502
|
fileIds?: string[];
|
|
7503
|
+
vaultAttachments?: VaultAttachmentRef[];
|
|
7495
7504
|
createdAt: Date;
|
|
7496
7505
|
updatedAt: Date;
|
|
7497
7506
|
vector?: number[];
|
|
@@ -7668,6 +7677,7 @@ interface CreateMessageOptions {
|
|
|
7668
7677
|
files?: FileMetadata[];
|
|
7669
7678
|
/** Array of media_id references for direct lookup in media table */
|
|
7670
7679
|
fileIds?: string[];
|
|
7680
|
+
vaultAttachments?: VaultAttachmentRef[];
|
|
7671
7681
|
usage?: ChatCompletionUsage;
|
|
7672
7682
|
sources?: SearchSource[];
|
|
7673
7683
|
responseDuration?: number;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -7389,6 +7389,14 @@ interface FileMetadata {
|
|
|
7389
7389
|
*/
|
|
7390
7390
|
sourceUrl?: string;
|
|
7391
7391
|
}
|
|
7392
|
+
/** Points a message's local file (`FileMetadata.id` or a `fileIds` media id) at its encrypted copy in vault, so any device can fetch it. */
|
|
7393
|
+
interface VaultAttachmentRef {
|
|
7394
|
+
attachmentId: string;
|
|
7395
|
+
fileId: string;
|
|
7396
|
+
name: string;
|
|
7397
|
+
type: string;
|
|
7398
|
+
size: number;
|
|
7399
|
+
}
|
|
7392
7400
|
interface ChatCompletionUsage {
|
|
7393
7401
|
promptTokens?: number;
|
|
7394
7402
|
completionTokens?: number;
|
|
@@ -7492,6 +7500,7 @@ interface StoredMessage {
|
|
|
7492
7500
|
files?: FileMetadata[];
|
|
7493
7501
|
/** Array of media_id references for direct lookup in media table */
|
|
7494
7502
|
fileIds?: string[];
|
|
7503
|
+
vaultAttachments?: VaultAttachmentRef[];
|
|
7495
7504
|
createdAt: Date;
|
|
7496
7505
|
updatedAt: Date;
|
|
7497
7506
|
vector?: number[];
|
|
@@ -7668,6 +7677,7 @@ interface CreateMessageOptions {
|
|
|
7668
7677
|
files?: FileMetadata[];
|
|
7669
7678
|
/** Array of media_id references for direct lookup in media table */
|
|
7670
7679
|
fileIds?: string[];
|
|
7680
|
+
vaultAttachments?: VaultAttachmentRef[];
|
|
7671
7681
|
usage?: ChatCompletionUsage;
|
|
7672
7682
|
sources?: SearchSource[];
|
|
7673
7683
|
responseDuration?: number;
|