@anuma/sdk 10.1.0 → 10.2.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 +612 -524
- package/dist/expo/index.d.mts +3706 -3698
- package/dist/expo/index.d.ts +3706 -3698
- package/dist/expo/index.mjs +612 -525
- package/dist/react/index.cjs +611 -523
- package/dist/react/index.d.mts +4114 -4106
- package/dist/react/index.d.ts +4114 -4106
- package/dist/react/index.mjs +611 -524
- package/dist/server/index.cjs +50 -13
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.mjs +49 -13
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -10348,17 +10348,18 @@ function createWebSearchPreProcessor(options = {}) {
|
|
|
10348
10348
|
|
|
10349
10349
|
// src/lib/db/chat/summaryOperations.ts
|
|
10350
10350
|
import { Q as Q3 } from "@nozbe/watermelondb";
|
|
10351
|
-
function createSummaryContext(database) {
|
|
10351
|
+
function createSummaryContext(database, encryption = {}) {
|
|
10352
10352
|
return {
|
|
10353
|
+
...encryption,
|
|
10353
10354
|
database,
|
|
10354
10355
|
summariesCollection: database.get("conversation_summaries")
|
|
10355
10356
|
};
|
|
10356
10357
|
}
|
|
10357
|
-
function modelToStored(record2) {
|
|
10358
|
+
function modelToStored(record2, summary) {
|
|
10358
10359
|
return {
|
|
10359
10360
|
uniqueId: record2.id,
|
|
10360
10361
|
conversationId: record2.conversationId,
|
|
10361
|
-
summary
|
|
10362
|
+
summary,
|
|
10362
10363
|
summarizedUpTo: record2.summarizedUpTo,
|
|
10363
10364
|
tokenCount: record2.tokenCount,
|
|
10364
10365
|
createdAt: record2.createdAt,
|
|
@@ -10368,28 +10369,62 @@ function modelToStored(record2) {
|
|
|
10368
10369
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
10369
10370
|
const results = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
|
|
10370
10371
|
if (results.length === 0) return null;
|
|
10371
|
-
|
|
10372
|
+
const record2 = results[0];
|
|
10373
|
+
const stored2 = modelToStored(record2, record2.summary);
|
|
10374
|
+
if (ctx.walletAddress && isEncrypted(stored2.summary)) {
|
|
10375
|
+
if (ctx.signMessage) {
|
|
10376
|
+
try {
|
|
10377
|
+
await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
10378
|
+
} catch (error) {
|
|
10379
|
+
getLogger().warn("Failed to request the encryption key for the summary:", error);
|
|
10380
|
+
}
|
|
10381
|
+
}
|
|
10382
|
+
stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
|
|
10383
|
+
} else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
|
|
10384
|
+
try {
|
|
10385
|
+
const encryptedSummary = await encryptField(
|
|
10386
|
+
stored2.summary,
|
|
10387
|
+
ctx.walletAddress,
|
|
10388
|
+
ctx.signMessage,
|
|
10389
|
+
ctx.embeddedWalletSigner
|
|
10390
|
+
);
|
|
10391
|
+
await ctx.database.write(async () => {
|
|
10392
|
+
const current = await ctx.summariesCollection.query(Q3.where("id", record2.id)).fetch();
|
|
10393
|
+
if (current[0]?.summary === stored2.summary) {
|
|
10394
|
+
await current[0].update((rec) => {
|
|
10395
|
+
rec.summary = encryptedSummary;
|
|
10396
|
+
});
|
|
10397
|
+
}
|
|
10398
|
+
});
|
|
10399
|
+
} catch (error) {
|
|
10400
|
+
getLogger().warn("Failed to encrypt the legacy summary:", error);
|
|
10401
|
+
}
|
|
10402
|
+
}
|
|
10403
|
+
return stored2;
|
|
10372
10404
|
}
|
|
10373
10405
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
10406
|
+
const revision2 = getConversationRevision(ctx.database, conversationId);
|
|
10374
10407
|
let record2;
|
|
10408
|
+
const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
|
|
10375
10409
|
await ctx.database.write(async () => {
|
|
10410
|
+
assertConversationRevision(ctx.database, conversationId, revision2);
|
|
10376
10411
|
const existing = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
|
|
10377
10412
|
if (existing.length > 0) {
|
|
10378
10413
|
record2 = await existing[0].update((rec) => {
|
|
10379
|
-
rec.summary =
|
|
10414
|
+
rec.summary = encryptedSummary;
|
|
10380
10415
|
rec.summarizedUpTo = summarizedUpTo;
|
|
10381
10416
|
rec.tokenCount = tokenCount;
|
|
10382
10417
|
});
|
|
10383
10418
|
} else {
|
|
10384
10419
|
record2 = await ctx.summariesCollection.create((rec) => {
|
|
10385
10420
|
rec.conversationId = conversationId;
|
|
10386
|
-
rec.summary =
|
|
10421
|
+
rec.summary = encryptedSummary;
|
|
10387
10422
|
rec.summarizedUpTo = summarizedUpTo;
|
|
10388
10423
|
rec.tokenCount = tokenCount;
|
|
10389
10424
|
});
|
|
10390
10425
|
}
|
|
10391
10426
|
});
|
|
10392
|
-
return modelToStored(record2);
|
|
10427
|
+
return modelToStored(record2, summary);
|
|
10393
10428
|
}
|
|
10394
10429
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
10395
10430
|
await ctx.database.write(async () => {
|
|
@@ -10511,95 +10546,364 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
|
|
|
10511
10546
|
});
|
|
10512
10547
|
}
|
|
10513
10548
|
|
|
10514
|
-
// src/lib/
|
|
10515
|
-
var
|
|
10516
|
-
|
|
10517
|
-
|
|
10518
|
-
|
|
10519
|
-
|
|
10520
|
-
|
|
10521
|
-
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
|
|
10525
|
-
function normalizeEntityName(name) {
|
|
10526
|
-
return name.trim().toLowerCase();
|
|
10549
|
+
// src/lib/chatStore/vaultRecords.ts
|
|
10550
|
+
var PINNED_SORT_BASE = 2 ** 51;
|
|
10551
|
+
var recordBudgetBytes = 104e4;
|
|
10552
|
+
var storedDims = 1536;
|
|
10553
|
+
var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
|
|
10554
|
+
var maxChunks = 16;
|
|
10555
|
+
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
10556
|
+
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
10557
|
+
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
10558
|
+
function plain(value) {
|
|
10559
|
+
return JSON.parse(JSON.stringify(value ?? {}));
|
|
10527
10560
|
}
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
return topic2.source === "user" ? 1 : topic2.weight ?? 1;
|
|
10561
|
+
function text4(value) {
|
|
10562
|
+
return typeof value === "string" ? value : void 0;
|
|
10531
10563
|
}
|
|
10532
|
-
function
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10564
|
+
function number(value) {
|
|
10565
|
+
return typeof value === "number" ? value : void 0;
|
|
10566
|
+
}
|
|
10567
|
+
function conversationSortKey(data, createdAt) {
|
|
10568
|
+
const pinnedAt = number(data.pinnedAt);
|
|
10569
|
+
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
10570
|
+
return number(data.lastActivityAt) ?? createdAt;
|
|
10571
|
+
}
|
|
10572
|
+
function toConversation(record2) {
|
|
10573
|
+
const pinnedAt = number(record2.data.pinnedAt);
|
|
10574
|
+
const projectId = text4(record2.data.projectId);
|
|
10575
|
+
return {
|
|
10576
|
+
uniqueId: record2.id,
|
|
10577
|
+
conversationId: record2.id,
|
|
10578
|
+
title: text4(record2.data.title) ?? "",
|
|
10579
|
+
...projectId ? { projectId } : {},
|
|
10580
|
+
createdAt: new Date(record2.createdAt),
|
|
10581
|
+
updatedAt: new Date(record2.updatedAt),
|
|
10582
|
+
isDeleted: record2.isDeleted,
|
|
10583
|
+
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
10584
|
+
};
|
|
10585
|
+
}
|
|
10586
|
+
function messageData(options) {
|
|
10587
|
+
return plain(
|
|
10588
|
+
Object.fromEntries(
|
|
10589
|
+
Object.entries(options).filter(
|
|
10590
|
+
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
10591
|
+
)
|
|
10592
|
+
)
|
|
10593
|
+
);
|
|
10594
|
+
}
|
|
10595
|
+
function toMessage(record2) {
|
|
10596
|
+
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
10597
|
+
return {
|
|
10598
|
+
...fields,
|
|
10599
|
+
uniqueId: record2.id,
|
|
10600
|
+
messageId: record2.sortKey,
|
|
10601
|
+
conversationId: record2.conversationId,
|
|
10602
|
+
createdAt: new Date(record2.createdAt),
|
|
10603
|
+
updatedAt: new Date(record2.updatedAt)
|
|
10604
|
+
};
|
|
10605
|
+
}
|
|
10606
|
+
function chunkOffsets(record2) {
|
|
10607
|
+
const offsets = record2.data.chunkOffsets;
|
|
10608
|
+
return Array.isArray(offsets) ? offsets : void 0;
|
|
10609
|
+
}
|
|
10610
|
+
function toSkeletons(records) {
|
|
10611
|
+
const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
|
|
10612
|
+
return records.map((r) => {
|
|
10613
|
+
const parentMessageId = text4(r.data.parentMessageId);
|
|
10614
|
+
const model = text4(r.data.model);
|
|
10615
|
+
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
10616
|
+
return {
|
|
10617
|
+
uniqueId: r.id,
|
|
10618
|
+
messageId: r.sortKey,
|
|
10619
|
+
conversationId: r.conversationId,
|
|
10620
|
+
role: text4(r.data.role) ?? "",
|
|
10621
|
+
createdAt: new Date(r.createdAt),
|
|
10622
|
+
...parentMessageId ? { parentMessageId } : {},
|
|
10623
|
+
...model ? { model } : {},
|
|
10624
|
+
...artifact ? { content: text4(r.data.content) ?? "" } : {}
|
|
10625
|
+
};
|
|
10626
|
+
});
|
|
10627
|
+
}
|
|
10628
|
+
function toSummary(record2) {
|
|
10629
|
+
return {
|
|
10630
|
+
uniqueId: record2.id,
|
|
10631
|
+
conversationId: record2.id,
|
|
10632
|
+
summary: text4(record2.data.summary) ?? "",
|
|
10633
|
+
summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
|
|
10634
|
+
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
10635
|
+
createdAt: new Date(record2.createdAt),
|
|
10636
|
+
updatedAt: new Date(record2.updatedAt)
|
|
10637
|
+
};
|
|
10638
|
+
}
|
|
10639
|
+
function links(data) {
|
|
10640
|
+
return Array.isArray(data.links) ? data.links : [];
|
|
10641
|
+
}
|
|
10642
|
+
function applyLinkOps(data, ops) {
|
|
10643
|
+
let current = links(data);
|
|
10644
|
+
for (const op of ops) {
|
|
10645
|
+
if ("clear" in op) {
|
|
10646
|
+
current = [];
|
|
10647
|
+
continue;
|
|
10648
|
+
}
|
|
10649
|
+
const byId = new Map(current.map((l) => [l.memoryId, l]));
|
|
10650
|
+
const turn = /* @__PURE__ */ new Set();
|
|
10651
|
+
op.add.forEach((item, i) => {
|
|
10652
|
+
if (!item.memoryId || turn.has(item.memoryId)) return;
|
|
10653
|
+
turn.add(item.memoryId);
|
|
10654
|
+
const known = byId.get(item.memoryId);
|
|
10655
|
+
if (known && known.createdAt >= op.at + i) return;
|
|
10656
|
+
byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
|
|
10657
|
+
});
|
|
10658
|
+
current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
|
|
10536
10659
|
}
|
|
10537
|
-
return
|
|
10660
|
+
return plain({ links: current });
|
|
10538
10661
|
}
|
|
10539
|
-
function
|
|
10540
|
-
return
|
|
10662
|
+
function toLinks(record2) {
|
|
10663
|
+
return links(record2.data).map((l) => ({
|
|
10664
|
+
uniqueId: `${record2.id}:${l.memoryId}`,
|
|
10665
|
+
conversationId: record2.id,
|
|
10666
|
+
memoryId: l.memoryId,
|
|
10667
|
+
score: l.score,
|
|
10668
|
+
createdAt: new Date(l.createdAt)
|
|
10669
|
+
}));
|
|
10541
10670
|
}
|
|
10542
|
-
function
|
|
10543
|
-
return JSON.stringify(
|
|
10671
|
+
function bytes(value) {
|
|
10672
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
10544
10673
|
}
|
|
10545
|
-
function
|
|
10546
|
-
if (
|
|
10547
|
-
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
|
|
10674
|
+
function fitRecord(record2) {
|
|
10675
|
+
if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
|
|
10676
|
+
const data = { ...record2.data };
|
|
10677
|
+
const truncated = [];
|
|
10678
|
+
for (const field10 of droppable) {
|
|
10679
|
+
if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
|
|
10680
|
+
if (data[field10] === void 0) continue;
|
|
10681
|
+
delete data[field10];
|
|
10682
|
+
truncated.push(field10);
|
|
10552
10683
|
}
|
|
10553
|
-
|
|
10684
|
+
const content = text4(data.content) ?? "";
|
|
10685
|
+
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
10686
|
+
if (over > 0) {
|
|
10687
|
+
const encoded = new TextEncoder().encode(content);
|
|
10688
|
+
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
10689
|
+
truncated.push("content");
|
|
10690
|
+
}
|
|
10691
|
+
return { ...record2, data: { ...data, truncated } };
|
|
10692
|
+
}
|
|
10693
|
+
function acceptedVector(vector2) {
|
|
10694
|
+
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
10695
|
+
if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims).some((x) => x !== 0))
|
|
10696
|
+
return void 0;
|
|
10697
|
+
return [...vector2];
|
|
10698
|
+
}
|
|
10699
|
+
function normalized(vector2) {
|
|
10700
|
+
const norm = Math.hypot(...vector2) || 1;
|
|
10701
|
+
return vector2.map((x) => x / norm);
|
|
10702
|
+
}
|
|
10703
|
+
function fitChunks(chunks3) {
|
|
10704
|
+
const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
|
|
10705
|
+
if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
|
|
10706
|
+
if (usable.length <= maxChunks) return usable;
|
|
10554
10707
|
const out = [];
|
|
10555
|
-
for (
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10708
|
+
for (let g = 0; g < maxChunks; g++) {
|
|
10709
|
+
const group = usable.slice(
|
|
10710
|
+
Math.floor(g * usable.length / maxChunks),
|
|
10711
|
+
Math.floor((g + 1) * usable.length / maxChunks)
|
|
10712
|
+
);
|
|
10713
|
+
const dims = group[0].vector.length;
|
|
10714
|
+
const mean = new Array(dims).fill(0);
|
|
10715
|
+
for (const c of group) {
|
|
10716
|
+
const unit = normalized(c.vector);
|
|
10717
|
+
for (let d = 0; d < dims; d++) mean[d] += unit[d];
|
|
10718
|
+
}
|
|
10560
10719
|
out.push({
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
10720
|
+
vector: normalized(mean),
|
|
10721
|
+
startOffset: group[0].startOffset,
|
|
10722
|
+
endOffset: group[group.length - 1].endOffset
|
|
10565
10723
|
});
|
|
10566
10724
|
}
|
|
10567
10725
|
return out;
|
|
10568
10726
|
}
|
|
10569
10727
|
|
|
10570
|
-
// src/lib/
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10728
|
+
// src/lib/chatStore/chatImports.ts
|
|
10729
|
+
var importBatch = 100;
|
|
10730
|
+
var importChunks = 200;
|
|
10731
|
+
var importPlaintextBytes = 39e5;
|
|
10732
|
+
function ms(date10, fallback = 1) {
|
|
10733
|
+
const value = date10?.getTime();
|
|
10734
|
+
return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
|
|
10576
10735
|
}
|
|
10577
|
-
function
|
|
10736
|
+
function bytes2(value) {
|
|
10737
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
10738
|
+
}
|
|
10739
|
+
function conversationRecord(conversation, messages) {
|
|
10740
|
+
const createdAt = ms(conversation.createdAt);
|
|
10741
|
+
const data = plain({
|
|
10742
|
+
title: conversation.title,
|
|
10743
|
+
projectId: conversation.projectId || void 0,
|
|
10744
|
+
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
10745
|
+
lastActivityAt: Math.max(
|
|
10746
|
+
ms(conversation.updatedAt, createdAt),
|
|
10747
|
+
...messages.map((m) => ms(m.createdAt))
|
|
10748
|
+
)
|
|
10749
|
+
});
|
|
10578
10750
|
return {
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
10583
|
-
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
|
|
10590
|
-
|
|
10591
|
-
|
|
10592
|
-
|
|
10593
|
-
|
|
10594
|
-
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
|
|
10751
|
+
record: {
|
|
10752
|
+
kind: "conversation",
|
|
10753
|
+
id: conversation.conversationId,
|
|
10754
|
+
conversationId: "",
|
|
10755
|
+
sortKey: conversationSortKey(data, createdAt),
|
|
10756
|
+
createdAt,
|
|
10757
|
+
updatedAt: ms(conversation.updatedAt, createdAt),
|
|
10758
|
+
isDeleted: false,
|
|
10759
|
+
data
|
|
10760
|
+
}
|
|
10761
|
+
};
|
|
10762
|
+
}
|
|
10763
|
+
function messageRecord(message) {
|
|
10764
|
+
const {
|
|
10765
|
+
uniqueId: _uniqueId,
|
|
10766
|
+
messageId: _messageId,
|
|
10767
|
+
createdAt: _createdAt,
|
|
10768
|
+
updatedAt: _updatedAt,
|
|
10769
|
+
decryptionStatus: _status,
|
|
10770
|
+
chunks: chunks3,
|
|
10771
|
+
vector: vector2,
|
|
10772
|
+
...fields
|
|
10773
|
+
} = message;
|
|
10774
|
+
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
10775
|
+
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
10776
|
+
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
10777
|
+
const record2 = fitRecord({
|
|
10778
|
+
kind: "message",
|
|
10779
|
+
id: message.uniqueId,
|
|
10780
|
+
conversationId: message.conversationId,
|
|
10781
|
+
sortKey: message.messageId,
|
|
10782
|
+
createdAt: ms(message.createdAt),
|
|
10783
|
+
updatedAt: ms(message.updatedAt, ms(message.createdAt)),
|
|
10784
|
+
isDeleted: false,
|
|
10785
|
+
data: {
|
|
10786
|
+
...messageData(fields),
|
|
10787
|
+
...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
|
|
10788
|
+
}
|
|
10789
|
+
});
|
|
10790
|
+
return {
|
|
10791
|
+
record: record2,
|
|
10792
|
+
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
10793
|
+
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
10794
|
+
};
|
|
10795
|
+
}
|
|
10796
|
+
function batches(records) {
|
|
10797
|
+
const out = [];
|
|
10798
|
+
let batch = [];
|
|
10799
|
+
let chunks3 = 0;
|
|
10800
|
+
let size = 0;
|
|
10801
|
+
for (const item of records) {
|
|
10802
|
+
const vectors = item.embeddings?.length ?? 0;
|
|
10803
|
+
const itemSize = bytes2(item.record);
|
|
10804
|
+
if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
|
|
10805
|
+
out.push(batch);
|
|
10806
|
+
batch = [];
|
|
10807
|
+
chunks3 = 0;
|
|
10808
|
+
size = 0;
|
|
10809
|
+
}
|
|
10810
|
+
batch.push(item);
|
|
10811
|
+
chunks3 += vectors;
|
|
10812
|
+
size += itemSize;
|
|
10813
|
+
}
|
|
10814
|
+
if (batch.length) out.push(batch);
|
|
10815
|
+
return out;
|
|
10816
|
+
}
|
|
10817
|
+
|
|
10818
|
+
// src/lib/db/entities/types.ts
|
|
10819
|
+
var ENTITY_KINDS = [
|
|
10820
|
+
"person",
|
|
10821
|
+
"organization",
|
|
10822
|
+
"place",
|
|
10823
|
+
"event",
|
|
10824
|
+
"product",
|
|
10825
|
+
"thing",
|
|
10826
|
+
"concept",
|
|
10827
|
+
"other"
|
|
10828
|
+
];
|
|
10829
|
+
function normalizeEntityName(name) {
|
|
10830
|
+
return name.trim().toLowerCase();
|
|
10831
|
+
}
|
|
10832
|
+
var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
|
|
10833
|
+
function topicWeight(topic2) {
|
|
10834
|
+
return topic2.source === "user" ? 1 : topic2.weight ?? 1;
|
|
10835
|
+
}
|
|
10836
|
+
function primaryTopic(topics) {
|
|
10837
|
+
let best = null;
|
|
10838
|
+
for (const topic2 of topics ?? []) {
|
|
10839
|
+
if (best === null || topicWeight(topic2) > topicWeight(best)) best = topic2;
|
|
10840
|
+
}
|
|
10841
|
+
return best;
|
|
10842
|
+
}
|
|
10843
|
+
function parseTopicWeight(value) {
|
|
10844
|
+
return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
|
|
10845
|
+
}
|
|
10846
|
+
function serializeTopics(topics) {
|
|
10847
|
+
return JSON.stringify(topics);
|
|
10848
|
+
}
|
|
10849
|
+
function parseTopics(value) {
|
|
10850
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
10851
|
+
let parsed;
|
|
10852
|
+
try {
|
|
10853
|
+
parsed = JSON.parse(value);
|
|
10854
|
+
} catch {
|
|
10855
|
+
return null;
|
|
10856
|
+
}
|
|
10857
|
+
if (!Array.isArray(parsed)) return null;
|
|
10858
|
+
const out = [];
|
|
10859
|
+
for (const raw of parsed) {
|
|
10860
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
10861
|
+
const { name, kind, source, weight } = raw;
|
|
10862
|
+
if (typeof name !== "string" || name.trim().length === 0) continue;
|
|
10863
|
+
const parsedWeight = parseTopicWeight(weight);
|
|
10864
|
+
out.push({
|
|
10865
|
+
name,
|
|
10866
|
+
...typeof kind === "string" && kind.length > 0 ? { kind } : {},
|
|
10867
|
+
source: source === "user" ? "user" : "auto",
|
|
10868
|
+
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
10869
|
+
});
|
|
10870
|
+
}
|
|
10871
|
+
return out;
|
|
10872
|
+
}
|
|
10873
|
+
|
|
10874
|
+
// src/lib/memory/store/remoteTopics.ts
|
|
10875
|
+
function topic(value) {
|
|
10876
|
+
const t = value;
|
|
10877
|
+
if (!t || typeof t.name !== "string" || !t.name || !Number.isSafeInteger(t.version) || t.version < 1 || typeof t.is_deleted !== "boolean" || typeof t.server_updated_at !== "string" || t.kind !== void 0 && typeof t.kind !== "string")
|
|
10878
|
+
throw new Error("Invalid nearby topic");
|
|
10879
|
+
return t;
|
|
10880
|
+
}
|
|
10881
|
+
function createRemoteTopicPersistence(request) {
|
|
10882
|
+
return {
|
|
10883
|
+
topics: async () => {
|
|
10884
|
+
const out = [];
|
|
10885
|
+
let cursor;
|
|
10886
|
+
do {
|
|
10887
|
+
const page = await request(
|
|
10888
|
+
"/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
|
|
10889
|
+
{}
|
|
10890
|
+
);
|
|
10891
|
+
if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
|
|
10892
|
+
throw new Error("Invalid nearby topic page");
|
|
10893
|
+
out.push(...page.items.map(topic));
|
|
10894
|
+
cursor = page.next_cursor;
|
|
10895
|
+
} while (cursor);
|
|
10896
|
+
return out;
|
|
10897
|
+
},
|
|
10898
|
+
putTopic: async (value, expectedVersion) => {
|
|
10899
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
10900
|
+
throw new Error("Expected topic version must be a nonnegative integer");
|
|
10901
|
+
return topic(
|
|
10902
|
+
await request("/topics", {
|
|
10903
|
+
method: "PUT",
|
|
10904
|
+
body: JSON.stringify({ topic: value, expected_version: expectedVersion })
|
|
10905
|
+
})
|
|
10906
|
+
);
|
|
10603
10907
|
},
|
|
10604
10908
|
importTopics: async (topics, signal) => {
|
|
10605
10909
|
for (let i = 0; i < topics.length; i += 50) {
|
|
@@ -11249,7 +11553,7 @@ var ChatStoreError = class extends Error {
|
|
|
11249
11553
|
var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
|
|
11250
11554
|
var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
|
|
11251
11555
|
var maxPayload = 2 * 1024 * 1024;
|
|
11252
|
-
var
|
|
11556
|
+
var storedDims2 = 1536;
|
|
11253
11557
|
var maxRequestCiphertext = 8 * 1024 * 1024;
|
|
11254
11558
|
var maxGetRefs = 50;
|
|
11255
11559
|
var maxImportRecords = 100;
|
|
@@ -11317,24 +11621,24 @@ function vector(v) {
|
|
|
11317
11621
|
for (let i = 0; i < v.length; i++) {
|
|
11318
11622
|
const x = v[i];
|
|
11319
11623
|
if (typeof x !== "number" || !Number.isFinite(x)) return false;
|
|
11320
|
-
if (i <
|
|
11624
|
+
if (i < storedDims2 && x !== 0) nonZero = true;
|
|
11321
11625
|
}
|
|
11322
11626
|
return nonZero;
|
|
11323
11627
|
}
|
|
11324
11628
|
function vectorFields(write) {
|
|
11325
11629
|
return {
|
|
11326
|
-
...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0,
|
|
11630
|
+
...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
|
|
11327
11631
|
...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
|
|
11328
11632
|
};
|
|
11329
11633
|
}
|
|
11330
|
-
function
|
|
11634
|
+
function text5(value) {
|
|
11331
11635
|
return typeof value === "string";
|
|
11332
11636
|
}
|
|
11333
11637
|
function timestamp(value) {
|
|
11334
11638
|
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
11335
11639
|
}
|
|
11336
11640
|
function presigned(value) {
|
|
11337
|
-
if (!object(value) || !
|
|
11641
|
+
if (!object(value) || !text5(value.url) || !/^https:\/\//.test(value.url) || !text5(value.method) || !object(value.headers) || !Object.values(value.headers).every(text5) || !timestamp(value.expires_at))
|
|
11338
11642
|
invalid();
|
|
11339
11643
|
return {
|
|
11340
11644
|
url: value.url,
|
|
@@ -11344,7 +11648,7 @@ function presigned(value) {
|
|
|
11344
11648
|
};
|
|
11345
11649
|
}
|
|
11346
11650
|
function attachment(value) {
|
|
11347
|
-
if (!object(value) || !
|
|
11651
|
+
if (!object(value) || !text5(value.attachment_id) || !attachmentIdPattern.test(value.attachment_id) || !integer(value.size_bytes, 1) || value.state !== "pending" && value.state !== "committed" || value.owner_kind !== void 0 && value.owner_kind !== "message" && value.owner_kind !== "summary" || value.owner_id !== void 0 && !id(value.owner_id) || !timestamp(value.created_at) || value.committed_at !== void 0 && !timestamp(value.committed_at))
|
|
11348
11652
|
invalid();
|
|
11349
11653
|
return {
|
|
11350
11654
|
id: value.attachment_id,
|
|
@@ -11357,7 +11661,7 @@ function attachment(value) {
|
|
|
11357
11661
|
};
|
|
11358
11662
|
}
|
|
11359
11663
|
function ref(value) {
|
|
11360
|
-
if (!object(value) || !
|
|
11664
|
+
if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
|
|
11361
11665
|
return { kind: value.kind, id: value.id };
|
|
11362
11666
|
}
|
|
11363
11667
|
function sameMetadata(a, b) {
|
|
@@ -11580,7 +11884,7 @@ async function createRemoteChatStore(options) {
|
|
|
11580
11884
|
},
|
|
11581
11885
|
async account(signal) {
|
|
11582
11886
|
const value = await request("/account", {}, signal);
|
|
11583
|
-
if (!object(value) || value.account_id !== accountId || !
|
|
11887
|
+
if (!object(value) || value.account_id !== accountId || !text5(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count) || value.changes_cursor !== void 0 && (!text5(value.changes_cursor) || value.changes_cursor.length > 2048))
|
|
11584
11888
|
invalid();
|
|
11585
11889
|
if (value.key_id && value.key_id !== keyId)
|
|
11586
11890
|
throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
|
|
@@ -11625,363 +11929,177 @@ async function createRemoteChatStore(options) {
|
|
|
11625
11929
|
return {
|
|
11626
11930
|
kind: checked.kind,
|
|
11627
11931
|
id: checked.id,
|
|
11628
|
-
updated_at: r.updatedAt,
|
|
11629
|
-
is_deleted: r.isDeleted
|
|
11630
|
-
};
|
|
11631
|
-
});
|
|
11632
|
-
if (wireRevisions.length === 0) return [];
|
|
11633
|
-
const value = await request(
|
|
11634
|
-
"/verify",
|
|
11635
|
-
{
|
|
11636
|
-
method: "POST",
|
|
11637
|
-
body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
|
|
11638
|
-
},
|
|
11639
|
-
signal
|
|
11640
|
-
);
|
|
11641
|
-
if (!object(value) || !Array.isArray(value.missing)) invalid();
|
|
11642
|
-
const missing2 = value.missing.map(ref);
|
|
11643
|
-
if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
|
|
11644
|
-
return missing2;
|
|
11645
|
-
},
|
|
11646
|
-
async activate(signal) {
|
|
11647
|
-
const value = await request(
|
|
11648
|
-
"/account",
|
|
11649
|
-
{ method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
|
|
11650
|
-
signal
|
|
11651
|
-
);
|
|
11652
|
-
if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
|
|
11653
|
-
invalid();
|
|
11654
|
-
return value.transitioned;
|
|
11655
|
-
},
|
|
11656
|
-
async changes(cursor, options2) {
|
|
11657
|
-
const limit = options2?.limit ?? 100;
|
|
11658
|
-
if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!
|
|
11659
|
-
invalid();
|
|
11660
|
-
const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
|
|
11661
|
-
if (cursor) params.set("cursor", cursor);
|
|
11662
|
-
const value = await request(`/changes?${params}`, {}, options2?.signal);
|
|
11663
|
-
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !
|
|
11664
|
-
invalid();
|
|
11665
|
-
const items = [];
|
|
11666
|
-
for (const item of value.items) items.push(await decode(item));
|
|
11667
|
-
options2?.signal?.throwIfAborted();
|
|
11668
|
-
return {
|
|
11669
|
-
items,
|
|
11670
|
-
...value.next_cursor ? { nextCursor: value.next_cursor } : {},
|
|
11671
|
-
changesCursor: value.changes_cursor ?? cursor ?? ""
|
|
11672
|
-
};
|
|
11673
|
-
},
|
|
11674
|
-
async search(embedding2, options2) {
|
|
11675
|
-
const limit = options2?.limit ?? 20;
|
|
11676
|
-
const kindsFilter = options2?.kinds;
|
|
11677
|
-
if (!Array.isArray(embedding2) || !embeddings({
|
|
11678
|
-
record: { ...emptyMessage, isDeleted: false },
|
|
11679
|
-
embeddings: [embedding2]
|
|
11680
|
-
}) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!
|
|
11681
|
-
invalid();
|
|
11682
|
-
const value = await request(
|
|
11683
|
-
"/search",
|
|
11684
|
-
{
|
|
11685
|
-
method: "POST",
|
|
11686
|
-
body: JSON.stringify({
|
|
11687
|
-
account_id: accountId,
|
|
11688
|
-
embedding: embedding2.slice(0,
|
|
11689
|
-
limit,
|
|
11690
|
-
...kindsFilter ? { kinds: kindsFilter } : {},
|
|
11691
|
-
...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
|
|
11692
|
-
...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
|
|
11693
|
-
...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
|
|
11694
|
-
})
|
|
11695
|
-
},
|
|
11696
|
-
options2?.signal
|
|
11697
|
-
);
|
|
11698
|
-
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
|
|
11699
|
-
const hits = [];
|
|
11700
|
-
for (const item of value.items) {
|
|
11701
|
-
if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
|
|
11702
|
-
invalid();
|
|
11703
|
-
const snapshot = await decode(item);
|
|
11704
|
-
if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId || snapshot.record.conversationId === options2?.excludeConversationId)
|
|
11705
|
-
invalid();
|
|
11706
|
-
hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
|
|
11707
|
-
}
|
|
11708
|
-
options2?.signal?.throwIfAborted();
|
|
11709
|
-
return hits;
|
|
11710
|
-
},
|
|
11711
|
-
async deleteAll(signal) {
|
|
11712
|
-
const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
|
|
11713
|
-
if (!object(value) || !integer(value.deleted)) invalid();
|
|
11714
|
-
return value.deleted;
|
|
11715
|
-
},
|
|
11716
|
-
attachments: {
|
|
11717
|
-
async create(sizeBytes, signal) {
|
|
11718
|
-
if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
|
|
11719
|
-
const value = await request(
|
|
11720
|
-
"/attachments",
|
|
11721
|
-
{
|
|
11722
|
-
method: "POST",
|
|
11723
|
-
body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
|
|
11724
|
-
},
|
|
11725
|
-
signal
|
|
11726
|
-
);
|
|
11727
|
-
if (!object(value)) invalid();
|
|
11728
|
-
const created = attachment(value.attachment);
|
|
11729
|
-
if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
|
|
11730
|
-
return { attachment: created, upload: presigned(value.upload) };
|
|
11731
|
-
},
|
|
11732
|
-
async commit(attachmentId, owner, signal) {
|
|
11733
|
-
if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
|
|
11734
|
-
invalid();
|
|
11735
|
-
const value = await request(
|
|
11736
|
-
`/attachments/${attachmentId}/commit`,
|
|
11737
|
-
{
|
|
11738
|
-
method: "POST",
|
|
11739
|
-
body: JSON.stringify({
|
|
11740
|
-
account_id: accountId,
|
|
11741
|
-
owner_kind: owner.kind,
|
|
11742
|
-
owner_id: owner.id
|
|
11743
|
-
})
|
|
11744
|
-
},
|
|
11745
|
-
signal
|
|
11746
|
-
);
|
|
11747
|
-
if (!object(value)) invalid();
|
|
11748
|
-
const committed = attachment(value.attachment);
|
|
11749
|
-
if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
|
|
11750
|
-
invalid();
|
|
11751
|
-
return committed;
|
|
11752
|
-
},
|
|
11753
|
-
async get(attachmentId, signal) {
|
|
11754
|
-
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
11755
|
-
let value;
|
|
11756
|
-
try {
|
|
11757
|
-
value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
|
|
11758
|
-
} catch (error) {
|
|
11759
|
-
if (error instanceof ChatStoreError && error.status === 404) return null;
|
|
11760
|
-
throw error;
|
|
11761
|
-
}
|
|
11762
|
-
if (!object(value)) invalid();
|
|
11763
|
-
const found = attachment(value.attachment);
|
|
11764
|
-
if (found.id !== attachmentId) invalid();
|
|
11765
|
-
return {
|
|
11766
|
-
attachment: found,
|
|
11767
|
-
...value.download !== void 0 ? { download: presigned(value.download) } : {}
|
|
11768
|
-
};
|
|
11769
|
-
},
|
|
11770
|
-
async delete(attachmentId, signal) {
|
|
11771
|
-
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
11772
|
-
await request(
|
|
11773
|
-
`/attachments/${attachmentId}?account_id=${accountId}`,
|
|
11774
|
-
{ method: "DELETE" },
|
|
11775
|
-
signal
|
|
11776
|
-
);
|
|
11777
|
-
}
|
|
11778
|
-
}
|
|
11779
|
-
};
|
|
11780
|
-
}
|
|
11781
|
-
var emptyMessage = {
|
|
11782
|
-
kind: "message",
|
|
11783
|
-
id: "query",
|
|
11784
|
-
conversationId: "query",
|
|
11785
|
-
sortKey: 0,
|
|
11786
|
-
createdAt: 1,
|
|
11787
|
-
updatedAt: 1,
|
|
11788
|
-
isDeleted: false,
|
|
11789
|
-
data: {}
|
|
11790
|
-
};
|
|
11791
|
-
|
|
11792
|
-
// src/lib/chatStore/vaultRecords.ts
|
|
11793
|
-
var PINNED_SORT_BASE = 2 ** 51;
|
|
11794
|
-
var recordBudgetBytes = 104e4;
|
|
11795
|
-
var storedDims2 = 1536;
|
|
11796
|
-
var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
|
|
11797
|
-
var maxChunks = 16;
|
|
11798
|
-
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
11799
|
-
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
11800
|
-
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
11801
|
-
function plain(value) {
|
|
11802
|
-
return JSON.parse(JSON.stringify(value ?? {}));
|
|
11803
|
-
}
|
|
11804
|
-
function text5(value) {
|
|
11805
|
-
return typeof value === "string" ? value : void 0;
|
|
11806
|
-
}
|
|
11807
|
-
function number(value) {
|
|
11808
|
-
return typeof value === "number" ? value : void 0;
|
|
11809
|
-
}
|
|
11810
|
-
function conversationSortKey(data, createdAt) {
|
|
11811
|
-
const pinnedAt = number(data.pinnedAt);
|
|
11812
|
-
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
11813
|
-
return number(data.lastActivityAt) ?? createdAt;
|
|
11814
|
-
}
|
|
11815
|
-
function toConversation(record2) {
|
|
11816
|
-
const pinnedAt = number(record2.data.pinnedAt);
|
|
11817
|
-
const projectId = text5(record2.data.projectId);
|
|
11818
|
-
return {
|
|
11819
|
-
uniqueId: record2.id,
|
|
11820
|
-
conversationId: record2.id,
|
|
11821
|
-
title: text5(record2.data.title) ?? "",
|
|
11822
|
-
...projectId ? { projectId } : {},
|
|
11823
|
-
createdAt: new Date(record2.createdAt),
|
|
11824
|
-
updatedAt: new Date(record2.updatedAt),
|
|
11825
|
-
isDeleted: record2.isDeleted,
|
|
11826
|
-
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
11827
|
-
};
|
|
11828
|
-
}
|
|
11829
|
-
function messageData(options) {
|
|
11830
|
-
return plain(
|
|
11831
|
-
Object.fromEntries(
|
|
11832
|
-
Object.entries(options).filter(
|
|
11833
|
-
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
11834
|
-
)
|
|
11835
|
-
)
|
|
11836
|
-
);
|
|
11837
|
-
}
|
|
11838
|
-
function toMessage(record2) {
|
|
11839
|
-
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
11840
|
-
return {
|
|
11841
|
-
...fields,
|
|
11842
|
-
uniqueId: record2.id,
|
|
11843
|
-
messageId: record2.sortKey,
|
|
11844
|
-
conversationId: record2.conversationId,
|
|
11845
|
-
createdAt: new Date(record2.createdAt),
|
|
11846
|
-
updatedAt: new Date(record2.updatedAt)
|
|
11847
|
-
};
|
|
11848
|
-
}
|
|
11849
|
-
function chunkOffsets(record2) {
|
|
11850
|
-
const offsets = record2.data.chunkOffsets;
|
|
11851
|
-
return Array.isArray(offsets) ? offsets : void 0;
|
|
11852
|
-
}
|
|
11853
|
-
function toSkeletons(records) {
|
|
11854
|
-
const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
|
|
11855
|
-
return records.map((r) => {
|
|
11856
|
-
const parentMessageId = text5(r.data.parentMessageId);
|
|
11857
|
-
const model = text5(r.data.model);
|
|
11858
|
-
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
11859
|
-
return {
|
|
11860
|
-
uniqueId: r.id,
|
|
11861
|
-
messageId: r.sortKey,
|
|
11862
|
-
conversationId: r.conversationId,
|
|
11863
|
-
role: text5(r.data.role) ?? "",
|
|
11864
|
-
createdAt: new Date(r.createdAt),
|
|
11865
|
-
...parentMessageId ? { parentMessageId } : {},
|
|
11866
|
-
...model ? { model } : {},
|
|
11867
|
-
...artifact ? { content: text5(r.data.content) ?? "" } : {}
|
|
11868
|
-
};
|
|
11869
|
-
});
|
|
11870
|
-
}
|
|
11871
|
-
function toSummary(record2) {
|
|
11872
|
-
return {
|
|
11873
|
-
uniqueId: record2.id,
|
|
11874
|
-
conversationId: record2.id,
|
|
11875
|
-
summary: text5(record2.data.summary) ?? "",
|
|
11876
|
-
summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
|
|
11877
|
-
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
11878
|
-
createdAt: new Date(record2.createdAt),
|
|
11879
|
-
updatedAt: new Date(record2.updatedAt)
|
|
11880
|
-
};
|
|
11881
|
-
}
|
|
11882
|
-
function links(data) {
|
|
11883
|
-
return Array.isArray(data.links) ? data.links : [];
|
|
11884
|
-
}
|
|
11885
|
-
function applyLinkOps(data, ops) {
|
|
11886
|
-
let current = links(data);
|
|
11887
|
-
for (const op of ops) {
|
|
11888
|
-
if ("clear" in op) {
|
|
11889
|
-
current = [];
|
|
11890
|
-
continue;
|
|
11891
|
-
}
|
|
11892
|
-
const byId = new Map(current.map((l) => [l.memoryId, l]));
|
|
11893
|
-
const turn = /* @__PURE__ */ new Set();
|
|
11894
|
-
op.add.forEach((item, i) => {
|
|
11895
|
-
if (!item.memoryId || turn.has(item.memoryId)) return;
|
|
11896
|
-
turn.add(item.memoryId);
|
|
11897
|
-
const known = byId.get(item.memoryId);
|
|
11898
|
-
if (known && known.createdAt >= op.at + i) return;
|
|
11899
|
-
byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
|
|
11900
|
-
});
|
|
11901
|
-
current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
|
|
11902
|
-
}
|
|
11903
|
-
return plain({ links: current });
|
|
11904
|
-
}
|
|
11905
|
-
function toLinks(record2) {
|
|
11906
|
-
return links(record2.data).map((l) => ({
|
|
11907
|
-
uniqueId: `${record2.id}:${l.memoryId}`,
|
|
11908
|
-
conversationId: record2.id,
|
|
11909
|
-
memoryId: l.memoryId,
|
|
11910
|
-
score: l.score,
|
|
11911
|
-
createdAt: new Date(l.createdAt)
|
|
11912
|
-
}));
|
|
11913
|
-
}
|
|
11914
|
-
function bytes(value) {
|
|
11915
|
-
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
11916
|
-
}
|
|
11917
|
-
function fitRecord(record2) {
|
|
11918
|
-
if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
|
|
11919
|
-
const data = { ...record2.data };
|
|
11920
|
-
const truncated = [];
|
|
11921
|
-
for (const field10 of droppable) {
|
|
11922
|
-
if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
|
|
11923
|
-
if (data[field10] === void 0) continue;
|
|
11924
|
-
delete data[field10];
|
|
11925
|
-
truncated.push(field10);
|
|
11926
|
-
}
|
|
11927
|
-
const content = text5(data.content) ?? "";
|
|
11928
|
-
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
11929
|
-
if (over > 0) {
|
|
11930
|
-
const encoded = new TextEncoder().encode(content);
|
|
11931
|
-
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
11932
|
-
truncated.push("content");
|
|
11933
|
-
}
|
|
11934
|
-
return { ...record2, data: { ...data, truncated } };
|
|
11935
|
-
}
|
|
11936
|
-
function acceptedVector(vector2) {
|
|
11937
|
-
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
11938
|
-
if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
|
|
11939
|
-
return void 0;
|
|
11940
|
-
return [...vector2];
|
|
11941
|
-
}
|
|
11942
|
-
function normalized(vector2) {
|
|
11943
|
-
const norm = Math.hypot(...vector2) || 1;
|
|
11944
|
-
return vector2.map((x) => x / norm);
|
|
11945
|
-
}
|
|
11946
|
-
function fitChunks(chunks3) {
|
|
11947
|
-
const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
|
|
11948
|
-
if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
|
|
11949
|
-
if (usable.length <= maxChunks) return usable;
|
|
11950
|
-
const out = [];
|
|
11951
|
-
for (let g = 0; g < maxChunks; g++) {
|
|
11952
|
-
const group = usable.slice(
|
|
11953
|
-
Math.floor(g * usable.length / maxChunks),
|
|
11954
|
-
Math.floor((g + 1) * usable.length / maxChunks)
|
|
11955
|
-
);
|
|
11956
|
-
const dims = group[0].vector.length;
|
|
11957
|
-
const mean = new Array(dims).fill(0);
|
|
11958
|
-
for (const c of group) {
|
|
11959
|
-
const unit = normalized(c.vector);
|
|
11960
|
-
for (let d = 0; d < dims; d++) mean[d] += unit[d];
|
|
11932
|
+
updated_at: r.updatedAt,
|
|
11933
|
+
is_deleted: r.isDeleted
|
|
11934
|
+
};
|
|
11935
|
+
});
|
|
11936
|
+
if (wireRevisions.length === 0) return [];
|
|
11937
|
+
const value = await request(
|
|
11938
|
+
"/verify",
|
|
11939
|
+
{
|
|
11940
|
+
method: "POST",
|
|
11941
|
+
body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
|
|
11942
|
+
},
|
|
11943
|
+
signal
|
|
11944
|
+
);
|
|
11945
|
+
if (!object(value) || !Array.isArray(value.missing)) invalid();
|
|
11946
|
+
const missing2 = value.missing.map(ref);
|
|
11947
|
+
if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
|
|
11948
|
+
return missing2;
|
|
11949
|
+
},
|
|
11950
|
+
async activate(signal) {
|
|
11951
|
+
const value = await request(
|
|
11952
|
+
"/account",
|
|
11953
|
+
{ method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
|
|
11954
|
+
signal
|
|
11955
|
+
);
|
|
11956
|
+
if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
|
|
11957
|
+
invalid();
|
|
11958
|
+
return value.transitioned;
|
|
11959
|
+
},
|
|
11960
|
+
async changes(cursor, options2) {
|
|
11961
|
+
const limit = options2?.limit ?? 100;
|
|
11962
|
+
if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
|
|
11963
|
+
invalid();
|
|
11964
|
+
const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
|
|
11965
|
+
if (cursor) params.set("cursor", cursor);
|
|
11966
|
+
const value = await request(`/changes?${params}`, {}, options2?.signal);
|
|
11967
|
+
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !text5(value.next_cursor) || value.changes_cursor !== void 0 && !text5(value.changes_cursor))
|
|
11968
|
+
invalid();
|
|
11969
|
+
const items = [];
|
|
11970
|
+
for (const item of value.items) items.push(await decode(item));
|
|
11971
|
+
options2?.signal?.throwIfAborted();
|
|
11972
|
+
return {
|
|
11973
|
+
items,
|
|
11974
|
+
...value.next_cursor ? { nextCursor: value.next_cursor } : {},
|
|
11975
|
+
changesCursor: value.changes_cursor ?? cursor ?? ""
|
|
11976
|
+
};
|
|
11977
|
+
},
|
|
11978
|
+
async search(embedding2, options2) {
|
|
11979
|
+
const limit = options2?.limit ?? 20;
|
|
11980
|
+
const kindsFilter = options2?.kinds;
|
|
11981
|
+
if (!Array.isArray(embedding2) || !embeddings({
|
|
11982
|
+
record: { ...emptyMessage, isDeleted: false },
|
|
11983
|
+
embeddings: [embedding2]
|
|
11984
|
+
}) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!text5(options2.embeddingModel) || options2.embeddingModel.length > 256))
|
|
11985
|
+
invalid();
|
|
11986
|
+
const value = await request(
|
|
11987
|
+
"/search",
|
|
11988
|
+
{
|
|
11989
|
+
method: "POST",
|
|
11990
|
+
body: JSON.stringify({
|
|
11991
|
+
account_id: accountId,
|
|
11992
|
+
embedding: embedding2.slice(0, storedDims2),
|
|
11993
|
+
limit,
|
|
11994
|
+
...kindsFilter ? { kinds: kindsFilter } : {},
|
|
11995
|
+
...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
|
|
11996
|
+
...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
|
|
11997
|
+
...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
|
|
11998
|
+
})
|
|
11999
|
+
},
|
|
12000
|
+
options2?.signal
|
|
12001
|
+
);
|
|
12002
|
+
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
|
|
12003
|
+
const hits = [];
|
|
12004
|
+
for (const item of value.items) {
|
|
12005
|
+
if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
|
|
12006
|
+
invalid();
|
|
12007
|
+
const snapshot = await decode(item);
|
|
12008
|
+
if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId || snapshot.record.conversationId === options2?.excludeConversationId)
|
|
12009
|
+
invalid();
|
|
12010
|
+
hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
|
|
12011
|
+
}
|
|
12012
|
+
options2?.signal?.throwIfAborted();
|
|
12013
|
+
return hits;
|
|
12014
|
+
},
|
|
12015
|
+
async deleteAll(signal) {
|
|
12016
|
+
const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
|
|
12017
|
+
if (!object(value) || !integer(value.deleted)) invalid();
|
|
12018
|
+
return value.deleted;
|
|
12019
|
+
},
|
|
12020
|
+
attachments: {
|
|
12021
|
+
async create(sizeBytes, signal) {
|
|
12022
|
+
if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
|
|
12023
|
+
const value = await request(
|
|
12024
|
+
"/attachments",
|
|
12025
|
+
{
|
|
12026
|
+
method: "POST",
|
|
12027
|
+
body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
|
|
12028
|
+
},
|
|
12029
|
+
signal
|
|
12030
|
+
);
|
|
12031
|
+
if (!object(value)) invalid();
|
|
12032
|
+
const created = attachment(value.attachment);
|
|
12033
|
+
if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
|
|
12034
|
+
return { attachment: created, upload: presigned(value.upload) };
|
|
12035
|
+
},
|
|
12036
|
+
async commit(attachmentId, owner, signal) {
|
|
12037
|
+
if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
|
|
12038
|
+
invalid();
|
|
12039
|
+
const value = await request(
|
|
12040
|
+
`/attachments/${attachmentId}/commit`,
|
|
12041
|
+
{
|
|
12042
|
+
method: "POST",
|
|
12043
|
+
body: JSON.stringify({
|
|
12044
|
+
account_id: accountId,
|
|
12045
|
+
owner_kind: owner.kind,
|
|
12046
|
+
owner_id: owner.id
|
|
12047
|
+
})
|
|
12048
|
+
},
|
|
12049
|
+
signal
|
|
12050
|
+
);
|
|
12051
|
+
if (!object(value)) invalid();
|
|
12052
|
+
const committed = attachment(value.attachment);
|
|
12053
|
+
if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
|
|
12054
|
+
invalid();
|
|
12055
|
+
return committed;
|
|
12056
|
+
},
|
|
12057
|
+
async get(attachmentId, signal) {
|
|
12058
|
+
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
12059
|
+
let value;
|
|
12060
|
+
try {
|
|
12061
|
+
value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
|
|
12062
|
+
} catch (error) {
|
|
12063
|
+
if (error instanceof ChatStoreError && error.status === 404) return null;
|
|
12064
|
+
throw error;
|
|
12065
|
+
}
|
|
12066
|
+
if (!object(value)) invalid();
|
|
12067
|
+
const found = attachment(value.attachment);
|
|
12068
|
+
if (found.id !== attachmentId) invalid();
|
|
12069
|
+
return {
|
|
12070
|
+
attachment: found,
|
|
12071
|
+
...value.download !== void 0 ? { download: presigned(value.download) } : {}
|
|
12072
|
+
};
|
|
12073
|
+
},
|
|
12074
|
+
async delete(attachmentId, signal) {
|
|
12075
|
+
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
12076
|
+
await request(
|
|
12077
|
+
`/attachments/${attachmentId}?account_id=${accountId}`,
|
|
12078
|
+
{ method: "DELETE" },
|
|
12079
|
+
signal
|
|
12080
|
+
);
|
|
12081
|
+
}
|
|
11961
12082
|
}
|
|
11962
|
-
|
|
11963
|
-
vector: normalized(mean),
|
|
11964
|
-
startOffset: group[0].startOffset,
|
|
11965
|
-
endOffset: group[group.length - 1].endOffset
|
|
11966
|
-
});
|
|
11967
|
-
}
|
|
11968
|
-
return out;
|
|
12083
|
+
};
|
|
11969
12084
|
}
|
|
12085
|
+
var emptyMessage = {
|
|
12086
|
+
kind: "message",
|
|
12087
|
+
id: "query",
|
|
12088
|
+
conversationId: "query",
|
|
12089
|
+
sortKey: 0,
|
|
12090
|
+
createdAt: 1,
|
|
12091
|
+
updatedAt: 1,
|
|
12092
|
+
isDeleted: false,
|
|
12093
|
+
data: {}
|
|
12094
|
+
};
|
|
11970
12095
|
|
|
11971
12096
|
// src/lib/chatStore/migrateChats.ts
|
|
11972
12097
|
var maxPasses = 5;
|
|
11973
12098
|
var verifyBatch = 1e3;
|
|
11974
|
-
var importBatch = 100;
|
|
11975
|
-
var importChunks = 200;
|
|
11976
|
-
var importPlaintextBytes = 39e5;
|
|
11977
12099
|
var writeBatch = 25;
|
|
11978
12100
|
function key(record2) {
|
|
11979
12101
|
return `${record2.kind}/${record2.id}`;
|
|
11980
12102
|
}
|
|
11981
|
-
function ms(date10, fallback = 1) {
|
|
11982
|
-
const value = date10?.getTime();
|
|
11983
|
-
return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
|
|
11984
|
-
}
|
|
11985
12103
|
function sealed(value) {
|
|
11986
12104
|
if (typeof value === "string") return isEncrypted(value);
|
|
11987
12105
|
if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
|
|
@@ -11989,42 +12107,6 @@ function sealed(value) {
|
|
|
11989
12107
|
return Object.values(value).some(sealed);
|
|
11990
12108
|
return false;
|
|
11991
12109
|
}
|
|
11992
|
-
function bytes2(value) {
|
|
11993
|
-
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
11994
|
-
}
|
|
11995
|
-
function messageRecord(message) {
|
|
11996
|
-
const {
|
|
11997
|
-
uniqueId: _uniqueId,
|
|
11998
|
-
messageId: _messageId,
|
|
11999
|
-
createdAt: _createdAt,
|
|
12000
|
-
updatedAt: _updatedAt,
|
|
12001
|
-
decryptionStatus: _status,
|
|
12002
|
-
chunks: chunks3,
|
|
12003
|
-
vector: vector2,
|
|
12004
|
-
...fields
|
|
12005
|
-
} = message;
|
|
12006
|
-
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
12007
|
-
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
12008
|
-
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
12009
|
-
const record2 = fitRecord({
|
|
12010
|
-
kind: "message",
|
|
12011
|
-
id: message.uniqueId,
|
|
12012
|
-
conversationId: message.conversationId,
|
|
12013
|
-
sortKey: message.messageId,
|
|
12014
|
-
createdAt: ms(message.createdAt),
|
|
12015
|
-
updatedAt: ms(message.updatedAt, ms(message.createdAt)),
|
|
12016
|
-
isDeleted: false,
|
|
12017
|
-
data: {
|
|
12018
|
-
...messageData(fields),
|
|
12019
|
-
...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
|
|
12020
|
-
}
|
|
12021
|
-
});
|
|
12022
|
-
return {
|
|
12023
|
-
record: record2,
|
|
12024
|
-
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
12025
|
-
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
12026
|
-
};
|
|
12027
|
-
}
|
|
12028
12110
|
async function readLocal(options) {
|
|
12029
12111
|
const { database } = options;
|
|
12030
12112
|
const ctx = {
|
|
@@ -12035,7 +12117,7 @@ async function readLocal(options) {
|
|
|
12035
12117
|
signMessage: options.signMessage,
|
|
12036
12118
|
embeddedWalletSigner: options.embeddedWalletSigner
|
|
12037
12119
|
};
|
|
12038
|
-
const summaries = createSummaryContext(database);
|
|
12120
|
+
const summaries = createSummaryContext(database, ctx);
|
|
12039
12121
|
const memory = {
|
|
12040
12122
|
database,
|
|
12041
12123
|
conversationMemoryCollection: database.get(ConversationMemory.table)
|
|
@@ -12078,29 +12160,10 @@ async function readLocal(options) {
|
|
|
12078
12160
|
const messages = await getMessagesOp(ctx, conversationId);
|
|
12079
12161
|
const unreadableTitle = isEncrypted(conversation.title);
|
|
12080
12162
|
if (unreadableTitle) out.untitled++;
|
|
12081
|
-
const createdAt = ms(conversation.createdAt);
|
|
12082
|
-
const data = plain({
|
|
12083
|
-
title: unreadableTitle ? "" : conversation.title,
|
|
12084
|
-
projectId: conversation.projectId || void 0,
|
|
12085
|
-
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
12086
|
-
lastActivityAt: Math.max(
|
|
12087
|
-
ms(conversation.updatedAt, createdAt),
|
|
12088
|
-
...messages.map((m) => ms(m.createdAt))
|
|
12089
|
-
)
|
|
12090
|
-
});
|
|
12091
12163
|
out.conversations++;
|
|
12092
|
-
out.records.push(
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
id: conversationId,
|
|
12096
|
-
conversationId: "",
|
|
12097
|
-
sortKey: conversationSortKey(data, createdAt),
|
|
12098
|
-
createdAt,
|
|
12099
|
-
updatedAt: ms(conversation.updatedAt, createdAt),
|
|
12100
|
-
isDeleted: false,
|
|
12101
|
-
data
|
|
12102
|
-
}
|
|
12103
|
-
});
|
|
12164
|
+
out.records.push(
|
|
12165
|
+
conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
|
|
12166
|
+
);
|
|
12104
12167
|
for (const message of messages) {
|
|
12105
12168
|
if (message.decryptionStatus || sealed(message)) {
|
|
12106
12169
|
skip("message", message.uniqueId, "unreadable");
|
|
@@ -12116,7 +12179,9 @@ async function readLocal(options) {
|
|
|
12116
12179
|
out.records.push(prepared);
|
|
12117
12180
|
}
|
|
12118
12181
|
const summary = await getConversationSummaryOp(summaries, conversationId);
|
|
12119
|
-
if (summary)
|
|
12182
|
+
if (summary && isEncrypted(summary.summary)) {
|
|
12183
|
+
skip("summary", conversationId, "unreadable");
|
|
12184
|
+
} else if (summary)
|
|
12120
12185
|
out.records.push({
|
|
12121
12186
|
record: {
|
|
12122
12187
|
kind: "summary",
|
|
@@ -12219,27 +12284,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
|
|
|
12219
12284
|
};
|
|
12220
12285
|
});
|
|
12221
12286
|
}
|
|
12222
|
-
function batches(records) {
|
|
12223
|
-
const out = [];
|
|
12224
|
-
let batch = [];
|
|
12225
|
-
let chunks3 = 0;
|
|
12226
|
-
let size = 0;
|
|
12227
|
-
for (const item of records) {
|
|
12228
|
-
const vectors = item.embeddings?.length ?? 0;
|
|
12229
|
-
const itemSize = bytes2(item.record);
|
|
12230
|
-
if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
|
|
12231
|
-
out.push(batch);
|
|
12232
|
-
batch = [];
|
|
12233
|
-
chunks3 = 0;
|
|
12234
|
-
size = 0;
|
|
12235
|
-
}
|
|
12236
|
-
batch.push(item);
|
|
12237
|
-
chunks3 += vectors;
|
|
12238
|
-
size += itemSize;
|
|
12239
|
-
}
|
|
12240
|
-
if (batch.length) out.push(batch);
|
|
12241
|
-
return out;
|
|
12242
|
-
}
|
|
12243
12287
|
function fitVectors(records, available2, unembedded) {
|
|
12244
12288
|
let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
|
|
12245
12289
|
if (total <= available2) return records;
|
|
@@ -13320,6 +13364,45 @@ function createVaultChatBackend(options) {
|
|
|
13320
13364
|
},
|
|
13321
13365
|
flush,
|
|
13322
13366
|
poll,
|
|
13367
|
+
async importChats(chats) {
|
|
13368
|
+
await ready();
|
|
13369
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13370
|
+
const unique = (items) => items.filter(({ record: record2 }) => {
|
|
13371
|
+
const k = key2(record2.kind, record2.id);
|
|
13372
|
+
if (seen.has(k)) return false;
|
|
13373
|
+
seen.add(k);
|
|
13374
|
+
return true;
|
|
13375
|
+
});
|
|
13376
|
+
const valid = chats.filter((c) => validChatId(c.conversation.conversationId));
|
|
13377
|
+
const conversations = unique(
|
|
13378
|
+
valid.map((c) => conversationRecord(c.conversation, c.messages))
|
|
13379
|
+
);
|
|
13380
|
+
const messages = unique(
|
|
13381
|
+
valid.flatMap(
|
|
13382
|
+
(c) => c.messages.filter(
|
|
13383
|
+
(m) => m.conversationId === c.conversation.conversationId && validChatId(m.uniqueId) && Number.isSafeInteger(m.messageId)
|
|
13384
|
+
).map((m) => messageRecord({ ...m, vector: void 0, chunks: void 0 }))
|
|
13385
|
+
)
|
|
13386
|
+
);
|
|
13387
|
+
let conversationCount = 0;
|
|
13388
|
+
let messageCount = 0;
|
|
13389
|
+
try {
|
|
13390
|
+
for (const batch of batches(conversations))
|
|
13391
|
+
conversationCount += await store.importRecords(batch);
|
|
13392
|
+
for (const batch of batches(messages)) messageCount += await store.importRecords(batch);
|
|
13393
|
+
} finally {
|
|
13394
|
+
for (const { record: record2 } of messages) checked.delete(key2("message", record2.id));
|
|
13395
|
+
await refresh(conversations.map(({ record: record2 }) => key2("conversation", record2.id))).catch(
|
|
13396
|
+
() => void 0
|
|
13397
|
+
);
|
|
13398
|
+
for (const { record: record2 } of conversations) threads.delete(record2.id);
|
|
13399
|
+
channel?.postMessage("changed");
|
|
13400
|
+
emit({ type: "conversations", origin: "local" });
|
|
13401
|
+
for (const { record: record2 } of conversations)
|
|
13402
|
+
emit({ type: "messages", conversationId: record2.id, origin: "local" });
|
|
13403
|
+
}
|
|
13404
|
+
return { conversations: conversationCount, messages: messageCount };
|
|
13405
|
+
},
|
|
13323
13406
|
status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
|
|
13324
13407
|
close() {
|
|
13325
13408
|
closed = true;
|
|
@@ -15797,11 +15880,14 @@ var WatermelonChatStorageAdapter = class {
|
|
|
15797
15880
|
return searchChunksOp(this.ctx, queryVector, options);
|
|
15798
15881
|
}
|
|
15799
15882
|
getSummary(conversationId) {
|
|
15800
|
-
return getConversationSummaryOp(
|
|
15883
|
+
return getConversationSummaryOp(
|
|
15884
|
+
createSummaryContext(this.ctx.database, this.ctx),
|
|
15885
|
+
conversationId
|
|
15886
|
+
);
|
|
15801
15887
|
}
|
|
15802
15888
|
upsertSummary(conversationId, summary, summarizedUpTo, tokenCount) {
|
|
15803
15889
|
return upsertConversationSummaryOp(
|
|
15804
|
-
createSummaryContext(this.ctx.database),
|
|
15890
|
+
createSummaryContext(this.ctx.database, this.ctx),
|
|
15805
15891
|
conversationId,
|
|
15806
15892
|
summary,
|
|
15807
15893
|
summarizedUpTo,
|
|
@@ -34098,7 +34184,7 @@ async function summarizeHistoryAtRevision(options, revision2) {
|
|
|
34098
34184
|
const cachedSummary = await summaryStore(options).getSummary(conversationId);
|
|
34099
34185
|
return {
|
|
34100
34186
|
messagesToConvert: messages,
|
|
34101
|
-
summarySystemMessage: cachedSummary?.summary ? summaryToSystemMessage(cachedSummary.summary) : null
|
|
34187
|
+
summarySystemMessage: cachedSummary?.summary && !isEncrypted(cachedSummary.summary) ? summaryToSystemMessage(cachedSummary.summary) : null
|
|
34102
34188
|
};
|
|
34103
34189
|
} catch {
|
|
34104
34190
|
return { messagesToConvert: messages, summarySystemMessage: null };
|
|
@@ -34153,14 +34239,15 @@ async function doSummarizeHistory(options, revision2) {
|
|
|
34153
34239
|
} = options;
|
|
34154
34240
|
try {
|
|
34155
34241
|
const summaries = summaryStore(options);
|
|
34156
|
-
const persistSummary = (summary, summarizedUpTo, tokenCount) =>
|
|
34242
|
+
const persistSummary = (summary, summarizedUpTo, tokenCount) => {
|
|
34157
34243
|
assertConversationRevision(database, conversationId, revision2);
|
|
34158
|
-
|
|
34159
|
-
|
|
34160
|
-
);
|
|
34161
|
-
});
|
|
34244
|
+
return summaries.upsertSummary(conversationId, summary, summarizedUpTo, tokenCount);
|
|
34245
|
+
};
|
|
34162
34246
|
let cachedSummary = await summaries.getSummary(conversationId);
|
|
34163
34247
|
assertConversationRevision(database, conversationId, revision2);
|
|
34248
|
+
if (cachedSummary && isEncrypted(cachedSummary.summary)) {
|
|
34249
|
+
throw new Error("The cached summary could not be decrypted");
|
|
34250
|
+
}
|
|
34164
34251
|
const lastCompacted = lastCompactionTime.get(conversationId) ?? 0;
|
|
34165
34252
|
const compactionCooledDown = Date.now() - lastCompacted > COMPACTION_COOLDOWN_MS;
|
|
34166
34253
|
if (cachedSummary && cachedSummary.tokenCount > summaryTokenThreshold * MAX_SUMMARY_TOKEN_RATIO && compactionCooledDown) {
|