@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/expo/index.cjs
CHANGED
|
@@ -11434,17 +11434,19 @@ var xhrTransport = (options) => {
|
|
|
11434
11434
|
|
|
11435
11435
|
// src/lib/db/chat/summaryOperations.ts
|
|
11436
11436
|
var import_watermelondb5 = require("@nozbe/watermelondb");
|
|
11437
|
-
|
|
11437
|
+
init_logger();
|
|
11438
|
+
function createSummaryContext(database, encryption = {}) {
|
|
11438
11439
|
return {
|
|
11440
|
+
...encryption,
|
|
11439
11441
|
database,
|
|
11440
11442
|
summariesCollection: database.get("conversation_summaries")
|
|
11441
11443
|
};
|
|
11442
11444
|
}
|
|
11443
|
-
function modelToStored(record2) {
|
|
11445
|
+
function modelToStored(record2, summary) {
|
|
11444
11446
|
return {
|
|
11445
11447
|
uniqueId: record2.id,
|
|
11446
11448
|
conversationId: record2.conversationId,
|
|
11447
|
-
summary
|
|
11449
|
+
summary,
|
|
11448
11450
|
summarizedUpTo: record2.summarizedUpTo,
|
|
11449
11451
|
tokenCount: record2.tokenCount,
|
|
11450
11452
|
createdAt: record2.createdAt,
|
|
@@ -11454,28 +11456,62 @@ function modelToStored(record2) {
|
|
|
11454
11456
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
11455
11457
|
const results = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
|
|
11456
11458
|
if (results.length === 0) return null;
|
|
11457
|
-
|
|
11459
|
+
const record2 = results[0];
|
|
11460
|
+
const stored2 = modelToStored(record2, record2.summary);
|
|
11461
|
+
if (ctx.walletAddress && isEncrypted(stored2.summary)) {
|
|
11462
|
+
if (ctx.signMessage) {
|
|
11463
|
+
try {
|
|
11464
|
+
await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11465
|
+
} catch (error) {
|
|
11466
|
+
getLogger().warn("Failed to request the encryption key for the summary:", error);
|
|
11467
|
+
}
|
|
11468
|
+
}
|
|
11469
|
+
stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
|
|
11470
|
+
} else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
|
|
11471
|
+
try {
|
|
11472
|
+
const encryptedSummary = await encryptField(
|
|
11473
|
+
stored2.summary,
|
|
11474
|
+
ctx.walletAddress,
|
|
11475
|
+
ctx.signMessage,
|
|
11476
|
+
ctx.embeddedWalletSigner
|
|
11477
|
+
);
|
|
11478
|
+
await ctx.database.write(async () => {
|
|
11479
|
+
const current = await ctx.summariesCollection.query(import_watermelondb5.Q.where("id", record2.id)).fetch();
|
|
11480
|
+
if (current[0]?.summary === stored2.summary) {
|
|
11481
|
+
await current[0].update((rec) => {
|
|
11482
|
+
rec.summary = encryptedSummary;
|
|
11483
|
+
});
|
|
11484
|
+
}
|
|
11485
|
+
});
|
|
11486
|
+
} catch (error) {
|
|
11487
|
+
getLogger().warn("Failed to encrypt the legacy summary:", error);
|
|
11488
|
+
}
|
|
11489
|
+
}
|
|
11490
|
+
return stored2;
|
|
11458
11491
|
}
|
|
11459
11492
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
11493
|
+
const revision2 = getConversationRevision(ctx.database, conversationId);
|
|
11460
11494
|
let record2;
|
|
11495
|
+
const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
|
|
11461
11496
|
await ctx.database.write(async () => {
|
|
11497
|
+
assertConversationRevision(ctx.database, conversationId, revision2);
|
|
11462
11498
|
const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
|
|
11463
11499
|
if (existing.length > 0) {
|
|
11464
11500
|
record2 = await existing[0].update((rec) => {
|
|
11465
|
-
rec.summary =
|
|
11501
|
+
rec.summary = encryptedSummary;
|
|
11466
11502
|
rec.summarizedUpTo = summarizedUpTo;
|
|
11467
11503
|
rec.tokenCount = tokenCount;
|
|
11468
11504
|
});
|
|
11469
11505
|
} else {
|
|
11470
11506
|
record2 = await ctx.summariesCollection.create((rec) => {
|
|
11471
11507
|
rec.conversationId = conversationId;
|
|
11472
|
-
rec.summary =
|
|
11508
|
+
rec.summary = encryptedSummary;
|
|
11473
11509
|
rec.summarizedUpTo = summarizedUpTo;
|
|
11474
11510
|
rec.tokenCount = tokenCount;
|
|
11475
11511
|
});
|
|
11476
11512
|
}
|
|
11477
11513
|
});
|
|
11478
|
-
return modelToStored(record2);
|
|
11514
|
+
return modelToStored(record2, summary);
|
|
11479
11515
|
}
|
|
11480
11516
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
11481
11517
|
await ctx.database.write(async () => {
|
|
@@ -11597,94 +11633,363 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
|
|
|
11597
11633
|
});
|
|
11598
11634
|
}
|
|
11599
11635
|
|
|
11600
|
-
// src/lib/
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
var
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
"concept",
|
|
11612
|
-
"other"
|
|
11613
|
-
];
|
|
11614
|
-
function normalizeEntityName(name) {
|
|
11615
|
-
return name.trim().toLowerCase();
|
|
11636
|
+
// src/lib/chatStore/vaultRecords.ts
|
|
11637
|
+
var PINNED_SORT_BASE = 2 ** 51;
|
|
11638
|
+
var recordBudgetBytes = 104e4;
|
|
11639
|
+
var storedDims = 1536;
|
|
11640
|
+
var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
|
|
11641
|
+
var maxChunks = 16;
|
|
11642
|
+
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
11643
|
+
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
11644
|
+
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
11645
|
+
function plain(value) {
|
|
11646
|
+
return JSON.parse(JSON.stringify(value ?? {}));
|
|
11616
11647
|
}
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
return topic2.source === "user" ? 1 : topic2.weight ?? 1;
|
|
11648
|
+
function text4(value) {
|
|
11649
|
+
return typeof value === "string" ? value : void 0;
|
|
11620
11650
|
}
|
|
11621
|
-
function
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11651
|
+
function number(value) {
|
|
11652
|
+
return typeof value === "number" ? value : void 0;
|
|
11653
|
+
}
|
|
11654
|
+
function conversationSortKey(data, createdAt) {
|
|
11655
|
+
const pinnedAt = number(data.pinnedAt);
|
|
11656
|
+
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
11657
|
+
return number(data.lastActivityAt) ?? createdAt;
|
|
11658
|
+
}
|
|
11659
|
+
function toConversation(record2) {
|
|
11660
|
+
const pinnedAt = number(record2.data.pinnedAt);
|
|
11661
|
+
const projectId = text4(record2.data.projectId);
|
|
11662
|
+
return {
|
|
11663
|
+
uniqueId: record2.id,
|
|
11664
|
+
conversationId: record2.id,
|
|
11665
|
+
title: text4(record2.data.title) ?? "",
|
|
11666
|
+
...projectId ? { projectId } : {},
|
|
11667
|
+
createdAt: new Date(record2.createdAt),
|
|
11668
|
+
updatedAt: new Date(record2.updatedAt),
|
|
11669
|
+
isDeleted: record2.isDeleted,
|
|
11670
|
+
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
11671
|
+
};
|
|
11672
|
+
}
|
|
11673
|
+
function messageData(options) {
|
|
11674
|
+
return plain(
|
|
11675
|
+
Object.fromEntries(
|
|
11676
|
+
Object.entries(options).filter(
|
|
11677
|
+
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
11678
|
+
)
|
|
11679
|
+
)
|
|
11680
|
+
);
|
|
11681
|
+
}
|
|
11682
|
+
function toMessage(record2) {
|
|
11683
|
+
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
11684
|
+
return {
|
|
11685
|
+
...fields,
|
|
11686
|
+
uniqueId: record2.id,
|
|
11687
|
+
messageId: record2.sortKey,
|
|
11688
|
+
conversationId: record2.conversationId,
|
|
11689
|
+
createdAt: new Date(record2.createdAt),
|
|
11690
|
+
updatedAt: new Date(record2.updatedAt)
|
|
11691
|
+
};
|
|
11692
|
+
}
|
|
11693
|
+
function chunkOffsets(record2) {
|
|
11694
|
+
const offsets = record2.data.chunkOffsets;
|
|
11695
|
+
return Array.isArray(offsets) ? offsets : void 0;
|
|
11696
|
+
}
|
|
11697
|
+
function toSkeletons(records) {
|
|
11698
|
+
const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
|
|
11699
|
+
return records.map((r) => {
|
|
11700
|
+
const parentMessageId = text4(r.data.parentMessageId);
|
|
11701
|
+
const model = text4(r.data.model);
|
|
11702
|
+
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
11703
|
+
return {
|
|
11704
|
+
uniqueId: r.id,
|
|
11705
|
+
messageId: r.sortKey,
|
|
11706
|
+
conversationId: r.conversationId,
|
|
11707
|
+
role: text4(r.data.role) ?? "",
|
|
11708
|
+
createdAt: new Date(r.createdAt),
|
|
11709
|
+
...parentMessageId ? { parentMessageId } : {},
|
|
11710
|
+
...model ? { model } : {},
|
|
11711
|
+
...artifact ? { content: text4(r.data.content) ?? "" } : {}
|
|
11712
|
+
};
|
|
11713
|
+
});
|
|
11714
|
+
}
|
|
11715
|
+
function toSummary(record2) {
|
|
11716
|
+
return {
|
|
11717
|
+
uniqueId: record2.id,
|
|
11718
|
+
conversationId: record2.id,
|
|
11719
|
+
summary: text4(record2.data.summary) ?? "",
|
|
11720
|
+
summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
|
|
11721
|
+
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
11722
|
+
createdAt: new Date(record2.createdAt),
|
|
11723
|
+
updatedAt: new Date(record2.updatedAt)
|
|
11724
|
+
};
|
|
11725
|
+
}
|
|
11726
|
+
function links(data) {
|
|
11727
|
+
return Array.isArray(data.links) ? data.links : [];
|
|
11728
|
+
}
|
|
11729
|
+
function applyLinkOps(data, ops) {
|
|
11730
|
+
let current = links(data);
|
|
11731
|
+
for (const op of ops) {
|
|
11732
|
+
if ("clear" in op) {
|
|
11733
|
+
current = [];
|
|
11734
|
+
continue;
|
|
11735
|
+
}
|
|
11736
|
+
const byId = new Map(current.map((l) => [l.memoryId, l]));
|
|
11737
|
+
const turn = /* @__PURE__ */ new Set();
|
|
11738
|
+
op.add.forEach((item, i) => {
|
|
11739
|
+
if (!item.memoryId || turn.has(item.memoryId)) return;
|
|
11740
|
+
turn.add(item.memoryId);
|
|
11741
|
+
const known = byId.get(item.memoryId);
|
|
11742
|
+
if (known && known.createdAt >= op.at + i) return;
|
|
11743
|
+
byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
|
|
11744
|
+
});
|
|
11745
|
+
current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
|
|
11625
11746
|
}
|
|
11626
|
-
return
|
|
11747
|
+
return plain({ links: current });
|
|
11627
11748
|
}
|
|
11628
|
-
function
|
|
11629
|
-
return
|
|
11749
|
+
function toLinks(record2) {
|
|
11750
|
+
return links(record2.data).map((l) => ({
|
|
11751
|
+
uniqueId: `${record2.id}:${l.memoryId}`,
|
|
11752
|
+
conversationId: record2.id,
|
|
11753
|
+
memoryId: l.memoryId,
|
|
11754
|
+
score: l.score,
|
|
11755
|
+
createdAt: new Date(l.createdAt)
|
|
11756
|
+
}));
|
|
11630
11757
|
}
|
|
11631
|
-
function
|
|
11632
|
-
return JSON.stringify(
|
|
11758
|
+
function bytes(value) {
|
|
11759
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
11633
11760
|
}
|
|
11634
|
-
function
|
|
11635
|
-
if (
|
|
11636
|
-
|
|
11637
|
-
|
|
11638
|
-
|
|
11639
|
-
|
|
11640
|
-
|
|
11761
|
+
function fitRecord(record2) {
|
|
11762
|
+
if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
|
|
11763
|
+
const data = { ...record2.data };
|
|
11764
|
+
const truncated = [];
|
|
11765
|
+
for (const field10 of droppable) {
|
|
11766
|
+
if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
|
|
11767
|
+
if (data[field10] === void 0) continue;
|
|
11768
|
+
delete data[field10];
|
|
11769
|
+
truncated.push(field10);
|
|
11641
11770
|
}
|
|
11642
|
-
|
|
11771
|
+
const content = text4(data.content) ?? "";
|
|
11772
|
+
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
11773
|
+
if (over > 0) {
|
|
11774
|
+
const encoded = new TextEncoder().encode(content);
|
|
11775
|
+
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
11776
|
+
truncated.push("content");
|
|
11777
|
+
}
|
|
11778
|
+
return { ...record2, data: { ...data, truncated } };
|
|
11779
|
+
}
|
|
11780
|
+
function acceptedVector(vector2) {
|
|
11781
|
+
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
11782
|
+
if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims).some((x) => x !== 0))
|
|
11783
|
+
return void 0;
|
|
11784
|
+
return [...vector2];
|
|
11785
|
+
}
|
|
11786
|
+
function normalized(vector2) {
|
|
11787
|
+
const norm = Math.hypot(...vector2) || 1;
|
|
11788
|
+
return vector2.map((x) => x / norm);
|
|
11789
|
+
}
|
|
11790
|
+
function fitChunks(chunks3) {
|
|
11791
|
+
const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
|
|
11792
|
+
if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
|
|
11793
|
+
if (usable.length <= maxChunks) return usable;
|
|
11643
11794
|
const out = [];
|
|
11644
|
-
for (
|
|
11645
|
-
|
|
11646
|
-
|
|
11647
|
-
|
|
11648
|
-
|
|
11795
|
+
for (let g = 0; g < maxChunks; g++) {
|
|
11796
|
+
const group = usable.slice(
|
|
11797
|
+
Math.floor(g * usable.length / maxChunks),
|
|
11798
|
+
Math.floor((g + 1) * usable.length / maxChunks)
|
|
11799
|
+
);
|
|
11800
|
+
const dims = group[0].vector.length;
|
|
11801
|
+
const mean = new Array(dims).fill(0);
|
|
11802
|
+
for (const c of group) {
|
|
11803
|
+
const unit = normalized(c.vector);
|
|
11804
|
+
for (let d = 0; d < dims; d++) mean[d] += unit[d];
|
|
11805
|
+
}
|
|
11649
11806
|
out.push({
|
|
11650
|
-
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
11807
|
+
vector: normalized(mean),
|
|
11808
|
+
startOffset: group[0].startOffset,
|
|
11809
|
+
endOffset: group[group.length - 1].endOffset
|
|
11654
11810
|
});
|
|
11655
11811
|
}
|
|
11656
11812
|
return out;
|
|
11657
11813
|
}
|
|
11658
11814
|
|
|
11659
|
-
// src/lib/
|
|
11660
|
-
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11815
|
+
// src/lib/chatStore/chatImports.ts
|
|
11816
|
+
var importBatch = 100;
|
|
11817
|
+
var importChunks = 200;
|
|
11818
|
+
var importPlaintextBytes = 39e5;
|
|
11819
|
+
function ms(date10, fallback = 1) {
|
|
11820
|
+
const value = date10?.getTime();
|
|
11821
|
+
return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
|
|
11665
11822
|
}
|
|
11666
|
-
function
|
|
11823
|
+
function bytes2(value) {
|
|
11824
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
11825
|
+
}
|
|
11826
|
+
function conversationRecord(conversation, messages) {
|
|
11827
|
+
const createdAt = ms(conversation.createdAt);
|
|
11828
|
+
const data = plain({
|
|
11829
|
+
title: conversation.title,
|
|
11830
|
+
projectId: conversation.projectId || void 0,
|
|
11831
|
+
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
11832
|
+
lastActivityAt: Math.max(
|
|
11833
|
+
ms(conversation.updatedAt, createdAt),
|
|
11834
|
+
...messages.map((m) => ms(m.createdAt))
|
|
11835
|
+
)
|
|
11836
|
+
});
|
|
11667
11837
|
return {
|
|
11668
|
-
|
|
11669
|
-
|
|
11670
|
-
|
|
11671
|
-
|
|
11672
|
-
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
|
|
11676
|
-
|
|
11677
|
-
|
|
11678
|
-
|
|
11679
|
-
|
|
11680
|
-
|
|
11681
|
-
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
11686
|
-
|
|
11687
|
-
|
|
11838
|
+
record: {
|
|
11839
|
+
kind: "conversation",
|
|
11840
|
+
id: conversation.conversationId,
|
|
11841
|
+
conversationId: "",
|
|
11842
|
+
sortKey: conversationSortKey(data, createdAt),
|
|
11843
|
+
createdAt,
|
|
11844
|
+
updatedAt: ms(conversation.updatedAt, createdAt),
|
|
11845
|
+
isDeleted: false,
|
|
11846
|
+
data
|
|
11847
|
+
}
|
|
11848
|
+
};
|
|
11849
|
+
}
|
|
11850
|
+
function messageRecord(message) {
|
|
11851
|
+
const {
|
|
11852
|
+
uniqueId: _uniqueId,
|
|
11853
|
+
messageId: _messageId,
|
|
11854
|
+
createdAt: _createdAt,
|
|
11855
|
+
updatedAt: _updatedAt,
|
|
11856
|
+
decryptionStatus: _status,
|
|
11857
|
+
chunks: chunks3,
|
|
11858
|
+
vector: vector2,
|
|
11859
|
+
...fields
|
|
11860
|
+
} = message;
|
|
11861
|
+
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
11862
|
+
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
11863
|
+
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
11864
|
+
const record2 = fitRecord({
|
|
11865
|
+
kind: "message",
|
|
11866
|
+
id: message.uniqueId,
|
|
11867
|
+
conversationId: message.conversationId,
|
|
11868
|
+
sortKey: message.messageId,
|
|
11869
|
+
createdAt: ms(message.createdAt),
|
|
11870
|
+
updatedAt: ms(message.updatedAt, ms(message.createdAt)),
|
|
11871
|
+
isDeleted: false,
|
|
11872
|
+
data: {
|
|
11873
|
+
...messageData(fields),
|
|
11874
|
+
...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
|
|
11875
|
+
}
|
|
11876
|
+
});
|
|
11877
|
+
return {
|
|
11878
|
+
record: record2,
|
|
11879
|
+
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
11880
|
+
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
11881
|
+
};
|
|
11882
|
+
}
|
|
11883
|
+
function batches(records) {
|
|
11884
|
+
const out = [];
|
|
11885
|
+
let batch = [];
|
|
11886
|
+
let chunks3 = 0;
|
|
11887
|
+
let size = 0;
|
|
11888
|
+
for (const item of records) {
|
|
11889
|
+
const vectors = item.embeddings?.length ?? 0;
|
|
11890
|
+
const itemSize = bytes2(item.record);
|
|
11891
|
+
if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
|
|
11892
|
+
out.push(batch);
|
|
11893
|
+
batch = [];
|
|
11894
|
+
chunks3 = 0;
|
|
11895
|
+
size = 0;
|
|
11896
|
+
}
|
|
11897
|
+
batch.push(item);
|
|
11898
|
+
chunks3 += vectors;
|
|
11899
|
+
size += itemSize;
|
|
11900
|
+
}
|
|
11901
|
+
if (batch.length) out.push(batch);
|
|
11902
|
+
return out;
|
|
11903
|
+
}
|
|
11904
|
+
|
|
11905
|
+
// src/lib/memory/store/remotePersistence.ts
|
|
11906
|
+
init_portalLlm();
|
|
11907
|
+
|
|
11908
|
+
// src/lib/db/entities/types.ts
|
|
11909
|
+
var ENTITY_KINDS = [
|
|
11910
|
+
"person",
|
|
11911
|
+
"organization",
|
|
11912
|
+
"place",
|
|
11913
|
+
"event",
|
|
11914
|
+
"product",
|
|
11915
|
+
"thing",
|
|
11916
|
+
"concept",
|
|
11917
|
+
"other"
|
|
11918
|
+
];
|
|
11919
|
+
function normalizeEntityName(name) {
|
|
11920
|
+
return name.trim().toLowerCase();
|
|
11921
|
+
}
|
|
11922
|
+
var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
|
|
11923
|
+
function topicWeight(topic2) {
|
|
11924
|
+
return topic2.source === "user" ? 1 : topic2.weight ?? 1;
|
|
11925
|
+
}
|
|
11926
|
+
function primaryTopic(topics) {
|
|
11927
|
+
let best = null;
|
|
11928
|
+
for (const topic2 of topics ?? []) {
|
|
11929
|
+
if (best === null || topicWeight(topic2) > topicWeight(best)) best = topic2;
|
|
11930
|
+
}
|
|
11931
|
+
return best;
|
|
11932
|
+
}
|
|
11933
|
+
function parseTopicWeight(value) {
|
|
11934
|
+
return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
|
|
11935
|
+
}
|
|
11936
|
+
function serializeTopics(topics) {
|
|
11937
|
+
return JSON.stringify(topics);
|
|
11938
|
+
}
|
|
11939
|
+
function parseTopics(value) {
|
|
11940
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
11941
|
+
let parsed;
|
|
11942
|
+
try {
|
|
11943
|
+
parsed = JSON.parse(value);
|
|
11944
|
+
} catch {
|
|
11945
|
+
return null;
|
|
11946
|
+
}
|
|
11947
|
+
if (!Array.isArray(parsed)) return null;
|
|
11948
|
+
const out = [];
|
|
11949
|
+
for (const raw of parsed) {
|
|
11950
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
11951
|
+
const { name, kind, source, weight } = raw;
|
|
11952
|
+
if (typeof name !== "string" || name.trim().length === 0) continue;
|
|
11953
|
+
const parsedWeight = parseTopicWeight(weight);
|
|
11954
|
+
out.push({
|
|
11955
|
+
name,
|
|
11956
|
+
...typeof kind === "string" && kind.length > 0 ? { kind } : {},
|
|
11957
|
+
source: source === "user" ? "user" : "auto",
|
|
11958
|
+
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
11959
|
+
});
|
|
11960
|
+
}
|
|
11961
|
+
return out;
|
|
11962
|
+
}
|
|
11963
|
+
|
|
11964
|
+
// src/lib/memory/store/remoteTopics.ts
|
|
11965
|
+
function topic(value) {
|
|
11966
|
+
const t = value;
|
|
11967
|
+
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")
|
|
11968
|
+
throw new Error("Invalid nearby topic");
|
|
11969
|
+
return t;
|
|
11970
|
+
}
|
|
11971
|
+
function createRemoteTopicPersistence(request) {
|
|
11972
|
+
return {
|
|
11973
|
+
topics: async () => {
|
|
11974
|
+
const out = [];
|
|
11975
|
+
let cursor;
|
|
11976
|
+
do {
|
|
11977
|
+
const page = await request(
|
|
11978
|
+
"/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
|
|
11979
|
+
{}
|
|
11980
|
+
);
|
|
11981
|
+
if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
|
|
11982
|
+
throw new Error("Invalid nearby topic page");
|
|
11983
|
+
out.push(...page.items.map(topic));
|
|
11984
|
+
cursor = page.next_cursor;
|
|
11985
|
+
} while (cursor);
|
|
11986
|
+
return out;
|
|
11987
|
+
},
|
|
11988
|
+
putTopic: async (value, expectedVersion) => {
|
|
11989
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
11990
|
+
throw new Error("Expected topic version must be a nonnegative integer");
|
|
11991
|
+
return topic(
|
|
11992
|
+
await request("/topics", {
|
|
11688
11993
|
method: "PUT",
|
|
11689
11994
|
body: JSON.stringify({ topic: value, expected_version: expectedVersion })
|
|
11690
11995
|
})
|
|
@@ -12339,7 +12644,7 @@ var ChatStoreError = class extends Error {
|
|
|
12339
12644
|
var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
|
|
12340
12645
|
var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
|
|
12341
12646
|
var maxPayload = 2 * 1024 * 1024;
|
|
12342
|
-
var
|
|
12647
|
+
var storedDims2 = 1536;
|
|
12343
12648
|
var maxRequestCiphertext = 8 * 1024 * 1024;
|
|
12344
12649
|
var maxGetRefs = 50;
|
|
12345
12650
|
var maxImportRecords = 100;
|
|
@@ -12407,24 +12712,24 @@ function vector(v) {
|
|
|
12407
12712
|
for (let i = 0; i < v.length; i++) {
|
|
12408
12713
|
const x = v[i];
|
|
12409
12714
|
if (typeof x !== "number" || !Number.isFinite(x)) return false;
|
|
12410
|
-
if (i <
|
|
12715
|
+
if (i < storedDims2 && x !== 0) nonZero = true;
|
|
12411
12716
|
}
|
|
12412
12717
|
return nonZero;
|
|
12413
12718
|
}
|
|
12414
12719
|
function vectorFields(write) {
|
|
12415
12720
|
return {
|
|
12416
|
-
...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0,
|
|
12721
|
+
...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
|
|
12417
12722
|
...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
|
|
12418
12723
|
};
|
|
12419
12724
|
}
|
|
12420
|
-
function
|
|
12725
|
+
function text5(value) {
|
|
12421
12726
|
return typeof value === "string";
|
|
12422
12727
|
}
|
|
12423
12728
|
function timestamp(value) {
|
|
12424
12729
|
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
12425
12730
|
}
|
|
12426
12731
|
function presigned(value) {
|
|
12427
|
-
if (!object(value) || !
|
|
12732
|
+
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))
|
|
12428
12733
|
invalid();
|
|
12429
12734
|
return {
|
|
12430
12735
|
url: value.url,
|
|
@@ -12434,7 +12739,7 @@ function presigned(value) {
|
|
|
12434
12739
|
};
|
|
12435
12740
|
}
|
|
12436
12741
|
function attachment(value) {
|
|
12437
|
-
if (!object(value) || !
|
|
12742
|
+
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))
|
|
12438
12743
|
invalid();
|
|
12439
12744
|
return {
|
|
12440
12745
|
id: value.attachment_id,
|
|
@@ -12447,7 +12752,7 @@ function attachment(value) {
|
|
|
12447
12752
|
};
|
|
12448
12753
|
}
|
|
12449
12754
|
function ref(value) {
|
|
12450
|
-
if (!object(value) || !
|
|
12755
|
+
if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
|
|
12451
12756
|
return { kind: value.kind, id: value.id };
|
|
12452
12757
|
}
|
|
12453
12758
|
function sameMetadata(a, b) {
|
|
@@ -12670,7 +12975,7 @@ async function createRemoteChatStore(options) {
|
|
|
12670
12975
|
},
|
|
12671
12976
|
async account(signal) {
|
|
12672
12977
|
const value = await request("/account", {}, signal);
|
|
12673
|
-
if (!object(value) || value.account_id !== accountId || !
|
|
12978
|
+
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))
|
|
12674
12979
|
invalid();
|
|
12675
12980
|
if (value.key_id && value.key_id !== keyId)
|
|
12676
12981
|
throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
|
|
@@ -12714,364 +13019,178 @@ async function createRemoteChatStore(options) {
|
|
|
12714
13019
|
asked.add(`${checked.kind}/${checked.id}`);
|
|
12715
13020
|
return {
|
|
12716
13021
|
kind: checked.kind,
|
|
12717
|
-
id: checked.id,
|
|
12718
|
-
updated_at: r.updatedAt,
|
|
12719
|
-
is_deleted: r.isDeleted
|
|
12720
|
-
};
|
|
12721
|
-
});
|
|
12722
|
-
if (wireRevisions.length === 0) return [];
|
|
12723
|
-
const value = await request(
|
|
12724
|
-
"/verify",
|
|
12725
|
-
{
|
|
12726
|
-
method: "POST",
|
|
12727
|
-
body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
|
|
12728
|
-
},
|
|
12729
|
-
signal
|
|
12730
|
-
);
|
|
12731
|
-
if (!object(value) || !Array.isArray(value.missing)) invalid();
|
|
12732
|
-
const missing2 = value.missing.map(ref);
|
|
12733
|
-
if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
|
|
12734
|
-
return missing2;
|
|
12735
|
-
},
|
|
12736
|
-
async activate(signal) {
|
|
12737
|
-
const value = await request(
|
|
12738
|
-
"/account",
|
|
12739
|
-
{ method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
|
|
12740
|
-
signal
|
|
12741
|
-
);
|
|
12742
|
-
if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
|
|
12743
|
-
invalid();
|
|
12744
|
-
return value.transitioned;
|
|
12745
|
-
},
|
|
12746
|
-
async changes(cursor, options2) {
|
|
12747
|
-
const limit = options2?.limit ?? 100;
|
|
12748
|
-
if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!
|
|
12749
|
-
invalid();
|
|
12750
|
-
const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
|
|
12751
|
-
if (cursor) params.set("cursor", cursor);
|
|
12752
|
-
const value = await request(`/changes?${params}`, {}, options2?.signal);
|
|
12753
|
-
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !
|
|
12754
|
-
invalid();
|
|
12755
|
-
const items = [];
|
|
12756
|
-
for (const item of value.items) items.push(await decode(item));
|
|
12757
|
-
options2?.signal?.throwIfAborted();
|
|
12758
|
-
return {
|
|
12759
|
-
items,
|
|
12760
|
-
...value.next_cursor ? { nextCursor: value.next_cursor } : {},
|
|
12761
|
-
changesCursor: value.changes_cursor ?? cursor ?? ""
|
|
12762
|
-
};
|
|
12763
|
-
},
|
|
12764
|
-
async search(embedding2, options2) {
|
|
12765
|
-
const limit = options2?.limit ?? 20;
|
|
12766
|
-
const kindsFilter = options2?.kinds;
|
|
12767
|
-
if (!Array.isArray(embedding2) || !embeddings({
|
|
12768
|
-
record: { ...emptyMessage, isDeleted: false },
|
|
12769
|
-
embeddings: [embedding2]
|
|
12770
|
-
}) || !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 && (!
|
|
12771
|
-
invalid();
|
|
12772
|
-
const value = await request(
|
|
12773
|
-
"/search",
|
|
12774
|
-
{
|
|
12775
|
-
method: "POST",
|
|
12776
|
-
body: JSON.stringify({
|
|
12777
|
-
account_id: accountId,
|
|
12778
|
-
embedding: embedding2.slice(0,
|
|
12779
|
-
limit,
|
|
12780
|
-
...kindsFilter ? { kinds: kindsFilter } : {},
|
|
12781
|
-
...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
|
|
12782
|
-
...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
|
|
12783
|
-
...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
|
|
12784
|
-
})
|
|
12785
|
-
},
|
|
12786
|
-
options2?.signal
|
|
12787
|
-
);
|
|
12788
|
-
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
|
|
12789
|
-
const hits = [];
|
|
12790
|
-
for (const item of value.items) {
|
|
12791
|
-
if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
|
|
12792
|
-
invalid();
|
|
12793
|
-
const snapshot = await decode(item);
|
|
12794
|
-
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)
|
|
12795
|
-
invalid();
|
|
12796
|
-
hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
|
|
12797
|
-
}
|
|
12798
|
-
options2?.signal?.throwIfAborted();
|
|
12799
|
-
return hits;
|
|
12800
|
-
},
|
|
12801
|
-
async deleteAll(signal) {
|
|
12802
|
-
const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
|
|
12803
|
-
if (!object(value) || !integer(value.deleted)) invalid();
|
|
12804
|
-
return value.deleted;
|
|
12805
|
-
},
|
|
12806
|
-
attachments: {
|
|
12807
|
-
async create(sizeBytes, signal) {
|
|
12808
|
-
if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
|
|
12809
|
-
const value = await request(
|
|
12810
|
-
"/attachments",
|
|
12811
|
-
{
|
|
12812
|
-
method: "POST",
|
|
12813
|
-
body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
|
|
12814
|
-
},
|
|
12815
|
-
signal
|
|
12816
|
-
);
|
|
12817
|
-
if (!object(value)) invalid();
|
|
12818
|
-
const created = attachment(value.attachment);
|
|
12819
|
-
if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
|
|
12820
|
-
return { attachment: created, upload: presigned(value.upload) };
|
|
12821
|
-
},
|
|
12822
|
-
async commit(attachmentId, owner, signal) {
|
|
12823
|
-
if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
|
|
12824
|
-
invalid();
|
|
12825
|
-
const value = await request(
|
|
12826
|
-
`/attachments/${attachmentId}/commit`,
|
|
12827
|
-
{
|
|
12828
|
-
method: "POST",
|
|
12829
|
-
body: JSON.stringify({
|
|
12830
|
-
account_id: accountId,
|
|
12831
|
-
owner_kind: owner.kind,
|
|
12832
|
-
owner_id: owner.id
|
|
12833
|
-
})
|
|
12834
|
-
},
|
|
12835
|
-
signal
|
|
12836
|
-
);
|
|
12837
|
-
if (!object(value)) invalid();
|
|
12838
|
-
const committed = attachment(value.attachment);
|
|
12839
|
-
if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
|
|
12840
|
-
invalid();
|
|
12841
|
-
return committed;
|
|
12842
|
-
},
|
|
12843
|
-
async get(attachmentId, signal) {
|
|
12844
|
-
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
12845
|
-
let value;
|
|
12846
|
-
try {
|
|
12847
|
-
value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
|
|
12848
|
-
} catch (error) {
|
|
12849
|
-
if (error instanceof ChatStoreError && error.status === 404) return null;
|
|
12850
|
-
throw error;
|
|
12851
|
-
}
|
|
12852
|
-
if (!object(value)) invalid();
|
|
12853
|
-
const found = attachment(value.attachment);
|
|
12854
|
-
if (found.id !== attachmentId) invalid();
|
|
12855
|
-
return {
|
|
12856
|
-
attachment: found,
|
|
12857
|
-
...value.download !== void 0 ? { download: presigned(value.download) } : {}
|
|
12858
|
-
};
|
|
12859
|
-
},
|
|
12860
|
-
async delete(attachmentId, signal) {
|
|
12861
|
-
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
12862
|
-
await request(
|
|
12863
|
-
`/attachments/${attachmentId}?account_id=${accountId}`,
|
|
12864
|
-
{ method: "DELETE" },
|
|
12865
|
-
signal
|
|
12866
|
-
);
|
|
12867
|
-
}
|
|
12868
|
-
}
|
|
12869
|
-
};
|
|
12870
|
-
}
|
|
12871
|
-
var emptyMessage = {
|
|
12872
|
-
kind: "message",
|
|
12873
|
-
id: "query",
|
|
12874
|
-
conversationId: "query",
|
|
12875
|
-
sortKey: 0,
|
|
12876
|
-
createdAt: 1,
|
|
12877
|
-
updatedAt: 1,
|
|
12878
|
-
isDeleted: false,
|
|
12879
|
-
data: {}
|
|
12880
|
-
};
|
|
12881
|
-
|
|
12882
|
-
// src/lib/chatStore/vaultRecords.ts
|
|
12883
|
-
var PINNED_SORT_BASE = 2 ** 51;
|
|
12884
|
-
var recordBudgetBytes = 104e4;
|
|
12885
|
-
var storedDims2 = 1536;
|
|
12886
|
-
var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
|
|
12887
|
-
var maxChunks = 16;
|
|
12888
|
-
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
12889
|
-
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
12890
|
-
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
12891
|
-
function plain(value) {
|
|
12892
|
-
return JSON.parse(JSON.stringify(value ?? {}));
|
|
12893
|
-
}
|
|
12894
|
-
function text5(value) {
|
|
12895
|
-
return typeof value === "string" ? value : void 0;
|
|
12896
|
-
}
|
|
12897
|
-
function number(value) {
|
|
12898
|
-
return typeof value === "number" ? value : void 0;
|
|
12899
|
-
}
|
|
12900
|
-
function conversationSortKey(data, createdAt) {
|
|
12901
|
-
const pinnedAt = number(data.pinnedAt);
|
|
12902
|
-
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
12903
|
-
return number(data.lastActivityAt) ?? createdAt;
|
|
12904
|
-
}
|
|
12905
|
-
function toConversation(record2) {
|
|
12906
|
-
const pinnedAt = number(record2.data.pinnedAt);
|
|
12907
|
-
const projectId = text5(record2.data.projectId);
|
|
12908
|
-
return {
|
|
12909
|
-
uniqueId: record2.id,
|
|
12910
|
-
conversationId: record2.id,
|
|
12911
|
-
title: text5(record2.data.title) ?? "",
|
|
12912
|
-
...projectId ? { projectId } : {},
|
|
12913
|
-
createdAt: new Date(record2.createdAt),
|
|
12914
|
-
updatedAt: new Date(record2.updatedAt),
|
|
12915
|
-
isDeleted: record2.isDeleted,
|
|
12916
|
-
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
12917
|
-
};
|
|
12918
|
-
}
|
|
12919
|
-
function messageData(options) {
|
|
12920
|
-
return plain(
|
|
12921
|
-
Object.fromEntries(
|
|
12922
|
-
Object.entries(options).filter(
|
|
12923
|
-
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
12924
|
-
)
|
|
12925
|
-
)
|
|
12926
|
-
);
|
|
12927
|
-
}
|
|
12928
|
-
function toMessage(record2) {
|
|
12929
|
-
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
12930
|
-
return {
|
|
12931
|
-
...fields,
|
|
12932
|
-
uniqueId: record2.id,
|
|
12933
|
-
messageId: record2.sortKey,
|
|
12934
|
-
conversationId: record2.conversationId,
|
|
12935
|
-
createdAt: new Date(record2.createdAt),
|
|
12936
|
-
updatedAt: new Date(record2.updatedAt)
|
|
12937
|
-
};
|
|
12938
|
-
}
|
|
12939
|
-
function chunkOffsets(record2) {
|
|
12940
|
-
const offsets = record2.data.chunkOffsets;
|
|
12941
|
-
return Array.isArray(offsets) ? offsets : void 0;
|
|
12942
|
-
}
|
|
12943
|
-
function toSkeletons(records) {
|
|
12944
|
-
const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
|
|
12945
|
-
return records.map((r) => {
|
|
12946
|
-
const parentMessageId = text5(r.data.parentMessageId);
|
|
12947
|
-
const model = text5(r.data.model);
|
|
12948
|
-
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
12949
|
-
return {
|
|
12950
|
-
uniqueId: r.id,
|
|
12951
|
-
messageId: r.sortKey,
|
|
12952
|
-
conversationId: r.conversationId,
|
|
12953
|
-
role: text5(r.data.role) ?? "",
|
|
12954
|
-
createdAt: new Date(r.createdAt),
|
|
12955
|
-
...parentMessageId ? { parentMessageId } : {},
|
|
12956
|
-
...model ? { model } : {},
|
|
12957
|
-
...artifact ? { content: text5(r.data.content) ?? "" } : {}
|
|
12958
|
-
};
|
|
12959
|
-
});
|
|
12960
|
-
}
|
|
12961
|
-
function toSummary(record2) {
|
|
12962
|
-
return {
|
|
12963
|
-
uniqueId: record2.id,
|
|
12964
|
-
conversationId: record2.id,
|
|
12965
|
-
summary: text5(record2.data.summary) ?? "",
|
|
12966
|
-
summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
|
|
12967
|
-
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
12968
|
-
createdAt: new Date(record2.createdAt),
|
|
12969
|
-
updatedAt: new Date(record2.updatedAt)
|
|
12970
|
-
};
|
|
12971
|
-
}
|
|
12972
|
-
function links(data) {
|
|
12973
|
-
return Array.isArray(data.links) ? data.links : [];
|
|
12974
|
-
}
|
|
12975
|
-
function applyLinkOps(data, ops) {
|
|
12976
|
-
let current = links(data);
|
|
12977
|
-
for (const op of ops) {
|
|
12978
|
-
if ("clear" in op) {
|
|
12979
|
-
current = [];
|
|
12980
|
-
continue;
|
|
12981
|
-
}
|
|
12982
|
-
const byId = new Map(current.map((l) => [l.memoryId, l]));
|
|
12983
|
-
const turn = /* @__PURE__ */ new Set();
|
|
12984
|
-
op.add.forEach((item, i) => {
|
|
12985
|
-
if (!item.memoryId || turn.has(item.memoryId)) return;
|
|
12986
|
-
turn.add(item.memoryId);
|
|
12987
|
-
const known = byId.get(item.memoryId);
|
|
12988
|
-
if (known && known.createdAt >= op.at + i) return;
|
|
12989
|
-
byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
|
|
12990
|
-
});
|
|
12991
|
-
current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
|
|
12992
|
-
}
|
|
12993
|
-
return plain({ links: current });
|
|
12994
|
-
}
|
|
12995
|
-
function toLinks(record2) {
|
|
12996
|
-
return links(record2.data).map((l) => ({
|
|
12997
|
-
uniqueId: `${record2.id}:${l.memoryId}`,
|
|
12998
|
-
conversationId: record2.id,
|
|
12999
|
-
memoryId: l.memoryId,
|
|
13000
|
-
score: l.score,
|
|
13001
|
-
createdAt: new Date(l.createdAt)
|
|
13002
|
-
}));
|
|
13003
|
-
}
|
|
13004
|
-
function bytes(value) {
|
|
13005
|
-
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
13006
|
-
}
|
|
13007
|
-
function fitRecord(record2) {
|
|
13008
|
-
if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
|
|
13009
|
-
const data = { ...record2.data };
|
|
13010
|
-
const truncated = [];
|
|
13011
|
-
for (const field10 of droppable) {
|
|
13012
|
-
if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
|
|
13013
|
-
if (data[field10] === void 0) continue;
|
|
13014
|
-
delete data[field10];
|
|
13015
|
-
truncated.push(field10);
|
|
13016
|
-
}
|
|
13017
|
-
const content = text5(data.content) ?? "";
|
|
13018
|
-
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
13019
|
-
if (over > 0) {
|
|
13020
|
-
const encoded = new TextEncoder().encode(content);
|
|
13021
|
-
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
13022
|
-
truncated.push("content");
|
|
13023
|
-
}
|
|
13024
|
-
return { ...record2, data: { ...data, truncated } };
|
|
13025
|
-
}
|
|
13026
|
-
function acceptedVector(vector2) {
|
|
13027
|
-
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
13028
|
-
if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
|
|
13029
|
-
return void 0;
|
|
13030
|
-
return [...vector2];
|
|
13031
|
-
}
|
|
13032
|
-
function normalized(vector2) {
|
|
13033
|
-
const norm = Math.hypot(...vector2) || 1;
|
|
13034
|
-
return vector2.map((x) => x / norm);
|
|
13035
|
-
}
|
|
13036
|
-
function fitChunks(chunks3) {
|
|
13037
|
-
const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
|
|
13038
|
-
if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
|
|
13039
|
-
if (usable.length <= maxChunks) return usable;
|
|
13040
|
-
const out = [];
|
|
13041
|
-
for (let g = 0; g < maxChunks; g++) {
|
|
13042
|
-
const group = usable.slice(
|
|
13043
|
-
Math.floor(g * usable.length / maxChunks),
|
|
13044
|
-
Math.floor((g + 1) * usable.length / maxChunks)
|
|
13045
|
-
);
|
|
13046
|
-
const dims = group[0].vector.length;
|
|
13047
|
-
const mean = new Array(dims).fill(0);
|
|
13048
|
-
for (const c of group) {
|
|
13049
|
-
const unit = normalized(c.vector);
|
|
13050
|
-
for (let d = 0; d < dims; d++) mean[d] += unit[d];
|
|
13022
|
+
id: checked.id,
|
|
13023
|
+
updated_at: r.updatedAt,
|
|
13024
|
+
is_deleted: r.isDeleted
|
|
13025
|
+
};
|
|
13026
|
+
});
|
|
13027
|
+
if (wireRevisions.length === 0) return [];
|
|
13028
|
+
const value = await request(
|
|
13029
|
+
"/verify",
|
|
13030
|
+
{
|
|
13031
|
+
method: "POST",
|
|
13032
|
+
body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
|
|
13033
|
+
},
|
|
13034
|
+
signal
|
|
13035
|
+
);
|
|
13036
|
+
if (!object(value) || !Array.isArray(value.missing)) invalid();
|
|
13037
|
+
const missing2 = value.missing.map(ref);
|
|
13038
|
+
if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
|
|
13039
|
+
return missing2;
|
|
13040
|
+
},
|
|
13041
|
+
async activate(signal) {
|
|
13042
|
+
const value = await request(
|
|
13043
|
+
"/account",
|
|
13044
|
+
{ method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
|
|
13045
|
+
signal
|
|
13046
|
+
);
|
|
13047
|
+
if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
|
|
13048
|
+
invalid();
|
|
13049
|
+
return value.transitioned;
|
|
13050
|
+
},
|
|
13051
|
+
async changes(cursor, options2) {
|
|
13052
|
+
const limit = options2?.limit ?? 100;
|
|
13053
|
+
if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
|
|
13054
|
+
invalid();
|
|
13055
|
+
const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
|
|
13056
|
+
if (cursor) params.set("cursor", cursor);
|
|
13057
|
+
const value = await request(`/changes?${params}`, {}, options2?.signal);
|
|
13058
|
+
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))
|
|
13059
|
+
invalid();
|
|
13060
|
+
const items = [];
|
|
13061
|
+
for (const item of value.items) items.push(await decode(item));
|
|
13062
|
+
options2?.signal?.throwIfAborted();
|
|
13063
|
+
return {
|
|
13064
|
+
items,
|
|
13065
|
+
...value.next_cursor ? { nextCursor: value.next_cursor } : {},
|
|
13066
|
+
changesCursor: value.changes_cursor ?? cursor ?? ""
|
|
13067
|
+
};
|
|
13068
|
+
},
|
|
13069
|
+
async search(embedding2, options2) {
|
|
13070
|
+
const limit = options2?.limit ?? 20;
|
|
13071
|
+
const kindsFilter = options2?.kinds;
|
|
13072
|
+
if (!Array.isArray(embedding2) || !embeddings({
|
|
13073
|
+
record: { ...emptyMessage, isDeleted: false },
|
|
13074
|
+
embeddings: [embedding2]
|
|
13075
|
+
}) || !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))
|
|
13076
|
+
invalid();
|
|
13077
|
+
const value = await request(
|
|
13078
|
+
"/search",
|
|
13079
|
+
{
|
|
13080
|
+
method: "POST",
|
|
13081
|
+
body: JSON.stringify({
|
|
13082
|
+
account_id: accountId,
|
|
13083
|
+
embedding: embedding2.slice(0, storedDims2),
|
|
13084
|
+
limit,
|
|
13085
|
+
...kindsFilter ? { kinds: kindsFilter } : {},
|
|
13086
|
+
...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
|
|
13087
|
+
...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
|
|
13088
|
+
...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
|
|
13089
|
+
})
|
|
13090
|
+
},
|
|
13091
|
+
options2?.signal
|
|
13092
|
+
);
|
|
13093
|
+
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
|
|
13094
|
+
const hits = [];
|
|
13095
|
+
for (const item of value.items) {
|
|
13096
|
+
if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
|
|
13097
|
+
invalid();
|
|
13098
|
+
const snapshot = await decode(item);
|
|
13099
|
+
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)
|
|
13100
|
+
invalid();
|
|
13101
|
+
hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
|
|
13102
|
+
}
|
|
13103
|
+
options2?.signal?.throwIfAborted();
|
|
13104
|
+
return hits;
|
|
13105
|
+
},
|
|
13106
|
+
async deleteAll(signal) {
|
|
13107
|
+
const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
|
|
13108
|
+
if (!object(value) || !integer(value.deleted)) invalid();
|
|
13109
|
+
return value.deleted;
|
|
13110
|
+
},
|
|
13111
|
+
attachments: {
|
|
13112
|
+
async create(sizeBytes, signal) {
|
|
13113
|
+
if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
|
|
13114
|
+
const value = await request(
|
|
13115
|
+
"/attachments",
|
|
13116
|
+
{
|
|
13117
|
+
method: "POST",
|
|
13118
|
+
body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
|
|
13119
|
+
},
|
|
13120
|
+
signal
|
|
13121
|
+
);
|
|
13122
|
+
if (!object(value)) invalid();
|
|
13123
|
+
const created = attachment(value.attachment);
|
|
13124
|
+
if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
|
|
13125
|
+
return { attachment: created, upload: presigned(value.upload) };
|
|
13126
|
+
},
|
|
13127
|
+
async commit(attachmentId, owner, signal) {
|
|
13128
|
+
if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
|
|
13129
|
+
invalid();
|
|
13130
|
+
const value = await request(
|
|
13131
|
+
`/attachments/${attachmentId}/commit`,
|
|
13132
|
+
{
|
|
13133
|
+
method: "POST",
|
|
13134
|
+
body: JSON.stringify({
|
|
13135
|
+
account_id: accountId,
|
|
13136
|
+
owner_kind: owner.kind,
|
|
13137
|
+
owner_id: owner.id
|
|
13138
|
+
})
|
|
13139
|
+
},
|
|
13140
|
+
signal
|
|
13141
|
+
);
|
|
13142
|
+
if (!object(value)) invalid();
|
|
13143
|
+
const committed = attachment(value.attachment);
|
|
13144
|
+
if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
|
|
13145
|
+
invalid();
|
|
13146
|
+
return committed;
|
|
13147
|
+
},
|
|
13148
|
+
async get(attachmentId, signal) {
|
|
13149
|
+
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
13150
|
+
let value;
|
|
13151
|
+
try {
|
|
13152
|
+
value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
|
|
13153
|
+
} catch (error) {
|
|
13154
|
+
if (error instanceof ChatStoreError && error.status === 404) return null;
|
|
13155
|
+
throw error;
|
|
13156
|
+
}
|
|
13157
|
+
if (!object(value)) invalid();
|
|
13158
|
+
const found = attachment(value.attachment);
|
|
13159
|
+
if (found.id !== attachmentId) invalid();
|
|
13160
|
+
return {
|
|
13161
|
+
attachment: found,
|
|
13162
|
+
...value.download !== void 0 ? { download: presigned(value.download) } : {}
|
|
13163
|
+
};
|
|
13164
|
+
},
|
|
13165
|
+
async delete(attachmentId, signal) {
|
|
13166
|
+
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
13167
|
+
await request(
|
|
13168
|
+
`/attachments/${attachmentId}?account_id=${accountId}`,
|
|
13169
|
+
{ method: "DELETE" },
|
|
13170
|
+
signal
|
|
13171
|
+
);
|
|
13172
|
+
}
|
|
13051
13173
|
}
|
|
13052
|
-
|
|
13053
|
-
vector: normalized(mean),
|
|
13054
|
-
startOffset: group[0].startOffset,
|
|
13055
|
-
endOffset: group[group.length - 1].endOffset
|
|
13056
|
-
});
|
|
13057
|
-
}
|
|
13058
|
-
return out;
|
|
13174
|
+
};
|
|
13059
13175
|
}
|
|
13176
|
+
var emptyMessage = {
|
|
13177
|
+
kind: "message",
|
|
13178
|
+
id: "query",
|
|
13179
|
+
conversationId: "query",
|
|
13180
|
+
sortKey: 0,
|
|
13181
|
+
createdAt: 1,
|
|
13182
|
+
updatedAt: 1,
|
|
13183
|
+
isDeleted: false,
|
|
13184
|
+
data: {}
|
|
13185
|
+
};
|
|
13060
13186
|
|
|
13061
13187
|
// src/lib/chatStore/migrateChats.ts
|
|
13062
13188
|
var maxPasses = 5;
|
|
13063
13189
|
var verifyBatch = 1e3;
|
|
13064
|
-
var importBatch = 100;
|
|
13065
|
-
var importChunks = 200;
|
|
13066
|
-
var importPlaintextBytes = 39e5;
|
|
13067
13190
|
var writeBatch = 25;
|
|
13068
13191
|
function key(record2) {
|
|
13069
13192
|
return `${record2.kind}/${record2.id}`;
|
|
13070
13193
|
}
|
|
13071
|
-
function ms(date10, fallback = 1) {
|
|
13072
|
-
const value = date10?.getTime();
|
|
13073
|
-
return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
|
|
13074
|
-
}
|
|
13075
13194
|
function sealed(value) {
|
|
13076
13195
|
if (typeof value === "string") return isEncrypted(value);
|
|
13077
13196
|
if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
|
|
@@ -13079,42 +13198,6 @@ function sealed(value) {
|
|
|
13079
13198
|
return Object.values(value).some(sealed);
|
|
13080
13199
|
return false;
|
|
13081
13200
|
}
|
|
13082
|
-
function bytes2(value) {
|
|
13083
|
-
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
13084
|
-
}
|
|
13085
|
-
function messageRecord(message) {
|
|
13086
|
-
const {
|
|
13087
|
-
uniqueId: _uniqueId,
|
|
13088
|
-
messageId: _messageId,
|
|
13089
|
-
createdAt: _createdAt,
|
|
13090
|
-
updatedAt: _updatedAt,
|
|
13091
|
-
decryptionStatus: _status,
|
|
13092
|
-
chunks: chunks3,
|
|
13093
|
-
vector: vector2,
|
|
13094
|
-
...fields
|
|
13095
|
-
} = message;
|
|
13096
|
-
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
13097
|
-
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
13098
|
-
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
13099
|
-
const record2 = fitRecord({
|
|
13100
|
-
kind: "message",
|
|
13101
|
-
id: message.uniqueId,
|
|
13102
|
-
conversationId: message.conversationId,
|
|
13103
|
-
sortKey: message.messageId,
|
|
13104
|
-
createdAt: ms(message.createdAt),
|
|
13105
|
-
updatedAt: ms(message.updatedAt, ms(message.createdAt)),
|
|
13106
|
-
isDeleted: false,
|
|
13107
|
-
data: {
|
|
13108
|
-
...messageData(fields),
|
|
13109
|
-
...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
|
|
13110
|
-
}
|
|
13111
|
-
});
|
|
13112
|
-
return {
|
|
13113
|
-
record: record2,
|
|
13114
|
-
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
13115
|
-
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
13116
|
-
};
|
|
13117
|
-
}
|
|
13118
13201
|
async function readLocal(options) {
|
|
13119
13202
|
const { database } = options;
|
|
13120
13203
|
const ctx = {
|
|
@@ -13125,7 +13208,7 @@ async function readLocal(options) {
|
|
|
13125
13208
|
signMessage: options.signMessage,
|
|
13126
13209
|
embeddedWalletSigner: options.embeddedWalletSigner
|
|
13127
13210
|
};
|
|
13128
|
-
const summaries = createSummaryContext(database);
|
|
13211
|
+
const summaries = createSummaryContext(database, ctx);
|
|
13129
13212
|
const memory = {
|
|
13130
13213
|
database,
|
|
13131
13214
|
conversationMemoryCollection: database.get(ConversationMemory.table)
|
|
@@ -13168,29 +13251,10 @@ async function readLocal(options) {
|
|
|
13168
13251
|
const messages = await getMessagesOp(ctx, conversationId);
|
|
13169
13252
|
const unreadableTitle = isEncrypted(conversation.title);
|
|
13170
13253
|
if (unreadableTitle) out.untitled++;
|
|
13171
|
-
const createdAt = ms(conversation.createdAt);
|
|
13172
|
-
const data = plain({
|
|
13173
|
-
title: unreadableTitle ? "" : conversation.title,
|
|
13174
|
-
projectId: conversation.projectId || void 0,
|
|
13175
|
-
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
13176
|
-
lastActivityAt: Math.max(
|
|
13177
|
-
ms(conversation.updatedAt, createdAt),
|
|
13178
|
-
...messages.map((m) => ms(m.createdAt))
|
|
13179
|
-
)
|
|
13180
|
-
});
|
|
13181
13254
|
out.conversations++;
|
|
13182
|
-
out.records.push(
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
id: conversationId,
|
|
13186
|
-
conversationId: "",
|
|
13187
|
-
sortKey: conversationSortKey(data, createdAt),
|
|
13188
|
-
createdAt,
|
|
13189
|
-
updatedAt: ms(conversation.updatedAt, createdAt),
|
|
13190
|
-
isDeleted: false,
|
|
13191
|
-
data
|
|
13192
|
-
}
|
|
13193
|
-
});
|
|
13255
|
+
out.records.push(
|
|
13256
|
+
conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
|
|
13257
|
+
);
|
|
13194
13258
|
for (const message of messages) {
|
|
13195
13259
|
if (message.decryptionStatus || sealed(message)) {
|
|
13196
13260
|
skip("message", message.uniqueId, "unreadable");
|
|
@@ -13206,7 +13270,9 @@ async function readLocal(options) {
|
|
|
13206
13270
|
out.records.push(prepared);
|
|
13207
13271
|
}
|
|
13208
13272
|
const summary = await getConversationSummaryOp(summaries, conversationId);
|
|
13209
|
-
if (summary)
|
|
13273
|
+
if (summary && isEncrypted(summary.summary)) {
|
|
13274
|
+
skip("summary", conversationId, "unreadable");
|
|
13275
|
+
} else if (summary)
|
|
13210
13276
|
out.records.push({
|
|
13211
13277
|
record: {
|
|
13212
13278
|
kind: "summary",
|
|
@@ -13309,27 +13375,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
|
|
|
13309
13375
|
};
|
|
13310
13376
|
});
|
|
13311
13377
|
}
|
|
13312
|
-
function batches(records) {
|
|
13313
|
-
const out = [];
|
|
13314
|
-
let batch = [];
|
|
13315
|
-
let chunks3 = 0;
|
|
13316
|
-
let size = 0;
|
|
13317
|
-
for (const item of records) {
|
|
13318
|
-
const vectors = item.embeddings?.length ?? 0;
|
|
13319
|
-
const itemSize = bytes2(item.record);
|
|
13320
|
-
if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
|
|
13321
|
-
out.push(batch);
|
|
13322
|
-
batch = [];
|
|
13323
|
-
chunks3 = 0;
|
|
13324
|
-
size = 0;
|
|
13325
|
-
}
|
|
13326
|
-
batch.push(item);
|
|
13327
|
-
chunks3 += vectors;
|
|
13328
|
-
size += itemSize;
|
|
13329
|
-
}
|
|
13330
|
-
if (batch.length) out.push(batch);
|
|
13331
|
-
return out;
|
|
13332
|
-
}
|
|
13333
13378
|
function fitVectors(records, available2, unembedded) {
|
|
13334
13379
|
let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
|
|
13335
13380
|
if (total <= available2) return records;
|
|
@@ -14410,6 +14455,45 @@ function createVaultChatBackend(options) {
|
|
|
14410
14455
|
},
|
|
14411
14456
|
flush,
|
|
14412
14457
|
poll,
|
|
14458
|
+
async importChats(chats) {
|
|
14459
|
+
await ready();
|
|
14460
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14461
|
+
const unique = (items) => items.filter(({ record: record2 }) => {
|
|
14462
|
+
const k = key2(record2.kind, record2.id);
|
|
14463
|
+
if (seen.has(k)) return false;
|
|
14464
|
+
seen.add(k);
|
|
14465
|
+
return true;
|
|
14466
|
+
});
|
|
14467
|
+
const valid = chats.filter((c) => validChatId(c.conversation.conversationId));
|
|
14468
|
+
const conversations = unique(
|
|
14469
|
+
valid.map((c) => conversationRecord(c.conversation, c.messages))
|
|
14470
|
+
);
|
|
14471
|
+
const messages = unique(
|
|
14472
|
+
valid.flatMap(
|
|
14473
|
+
(c) => c.messages.filter(
|
|
14474
|
+
(m) => m.conversationId === c.conversation.conversationId && validChatId(m.uniqueId) && Number.isSafeInteger(m.messageId)
|
|
14475
|
+
).map((m) => messageRecord({ ...m, vector: void 0, chunks: void 0 }))
|
|
14476
|
+
)
|
|
14477
|
+
);
|
|
14478
|
+
let conversationCount = 0;
|
|
14479
|
+
let messageCount = 0;
|
|
14480
|
+
try {
|
|
14481
|
+
for (const batch of batches(conversations))
|
|
14482
|
+
conversationCount += await store.importRecords(batch);
|
|
14483
|
+
for (const batch of batches(messages)) messageCount += await store.importRecords(batch);
|
|
14484
|
+
} finally {
|
|
14485
|
+
for (const { record: record2 } of messages) checked.delete(key2("message", record2.id));
|
|
14486
|
+
await refresh(conversations.map(({ record: record2 }) => key2("conversation", record2.id))).catch(
|
|
14487
|
+
() => void 0
|
|
14488
|
+
);
|
|
14489
|
+
for (const { record: record2 } of conversations) threads.delete(record2.id);
|
|
14490
|
+
channel?.postMessage("changed");
|
|
14491
|
+
emit({ type: "conversations", origin: "local" });
|
|
14492
|
+
for (const { record: record2 } of conversations)
|
|
14493
|
+
emit({ type: "messages", conversationId: record2.id, origin: "local" });
|
|
14494
|
+
}
|
|
14495
|
+
return { conversations: conversationCount, messages: messageCount };
|
|
14496
|
+
},
|
|
14413
14497
|
status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
|
|
14414
14498
|
close() {
|
|
14415
14499
|
closed = true;
|
|
@@ -28988,11 +29072,14 @@ var WatermelonChatStorageAdapter = class {
|
|
|
28988
29072
|
return searchChunksOp(this.ctx, queryVector, options);
|
|
28989
29073
|
}
|
|
28990
29074
|
getSummary(conversationId) {
|
|
28991
|
-
return getConversationSummaryOp(
|
|
29075
|
+
return getConversationSummaryOp(
|
|
29076
|
+
createSummaryContext(this.ctx.database, this.ctx),
|
|
29077
|
+
conversationId
|
|
29078
|
+
);
|
|
28992
29079
|
}
|
|
28993
29080
|
upsertSummary(conversationId, summary, summarizedUpTo, tokenCount) {
|
|
28994
29081
|
return upsertConversationSummaryOp(
|
|
28995
|
-
createSummaryContext(this.ctx.database),
|
|
29082
|
+
createSummaryContext(this.ctx.database, this.ctx),
|
|
28996
29083
|
conversationId,
|
|
28997
29084
|
summary,
|
|
28998
29085
|
summarizedUpTo,
|
|
@@ -31138,7 +31225,7 @@ async function summarizeHistoryAtRevision(options, revision2) {
|
|
|
31138
31225
|
const cachedSummary = await summaryStore(options).getSummary(conversationId);
|
|
31139
31226
|
return {
|
|
31140
31227
|
messagesToConvert: messages,
|
|
31141
|
-
summarySystemMessage: cachedSummary?.summary ? summaryToSystemMessage(cachedSummary.summary) : null
|
|
31228
|
+
summarySystemMessage: cachedSummary?.summary && !isEncrypted(cachedSummary.summary) ? summaryToSystemMessage(cachedSummary.summary) : null
|
|
31142
31229
|
};
|
|
31143
31230
|
} catch {
|
|
31144
31231
|
return { messagesToConvert: messages, summarySystemMessage: null };
|
|
@@ -31193,14 +31280,15 @@ async function doSummarizeHistory(options, revision2) {
|
|
|
31193
31280
|
} = options;
|
|
31194
31281
|
try {
|
|
31195
31282
|
const summaries = summaryStore(options);
|
|
31196
|
-
const persistSummary = (summary, summarizedUpTo, tokenCount) =>
|
|
31283
|
+
const persistSummary = (summary, summarizedUpTo, tokenCount) => {
|
|
31197
31284
|
assertConversationRevision(database, conversationId, revision2);
|
|
31198
|
-
|
|
31199
|
-
|
|
31200
|
-
);
|
|
31201
|
-
});
|
|
31285
|
+
return summaries.upsertSummary(conversationId, summary, summarizedUpTo, tokenCount);
|
|
31286
|
+
};
|
|
31202
31287
|
let cachedSummary = await summaries.getSummary(conversationId);
|
|
31203
31288
|
assertConversationRevision(database, conversationId, revision2);
|
|
31289
|
+
if (cachedSummary && isEncrypted(cachedSummary.summary)) {
|
|
31290
|
+
throw new Error("The cached summary could not be decrypted");
|
|
31291
|
+
}
|
|
31204
31292
|
const lastCompacted = lastCompactionTime.get(conversationId) ?? 0;
|
|
31205
31293
|
const compactionCooledDown = Date.now() - lastCompacted > COMPACTION_COOLDOWN_MS;
|
|
31206
31294
|
if (cachedSummary && cachedSummary.tokenCount > summaryTokenThreshold * MAX_SUMMARY_TOKEN_RATIO && compactionCooledDown) {
|