@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.cjs
CHANGED
|
@@ -12204,17 +12204,19 @@ function createWebSearchPreProcessor(options = {}) {
|
|
|
12204
12204
|
|
|
12205
12205
|
// src/lib/db/chat/summaryOperations.ts
|
|
12206
12206
|
var import_watermelondb5 = require("@nozbe/watermelondb");
|
|
12207
|
-
|
|
12207
|
+
init_logger();
|
|
12208
|
+
function createSummaryContext(database, encryption = {}) {
|
|
12208
12209
|
return {
|
|
12210
|
+
...encryption,
|
|
12209
12211
|
database,
|
|
12210
12212
|
summariesCollection: database.get("conversation_summaries")
|
|
12211
12213
|
};
|
|
12212
12214
|
}
|
|
12213
|
-
function modelToStored(record2) {
|
|
12215
|
+
function modelToStored(record2, summary) {
|
|
12214
12216
|
return {
|
|
12215
12217
|
uniqueId: record2.id,
|
|
12216
12218
|
conversationId: record2.conversationId,
|
|
12217
|
-
summary
|
|
12219
|
+
summary,
|
|
12218
12220
|
summarizedUpTo: record2.summarizedUpTo,
|
|
12219
12221
|
tokenCount: record2.tokenCount,
|
|
12220
12222
|
createdAt: record2.createdAt,
|
|
@@ -12224,28 +12226,62 @@ function modelToStored(record2) {
|
|
|
12224
12226
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
12225
12227
|
const results = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
|
|
12226
12228
|
if (results.length === 0) return null;
|
|
12227
|
-
|
|
12229
|
+
const record2 = results[0];
|
|
12230
|
+
const stored2 = modelToStored(record2, record2.summary);
|
|
12231
|
+
if (ctx.walletAddress && isEncrypted(stored2.summary)) {
|
|
12232
|
+
if (ctx.signMessage) {
|
|
12233
|
+
try {
|
|
12234
|
+
await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
12235
|
+
} catch (error) {
|
|
12236
|
+
getLogger().warn("Failed to request the encryption key for the summary:", error);
|
|
12237
|
+
}
|
|
12238
|
+
}
|
|
12239
|
+
stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
|
|
12240
|
+
} else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
|
|
12241
|
+
try {
|
|
12242
|
+
const encryptedSummary = await encryptField(
|
|
12243
|
+
stored2.summary,
|
|
12244
|
+
ctx.walletAddress,
|
|
12245
|
+
ctx.signMessage,
|
|
12246
|
+
ctx.embeddedWalletSigner
|
|
12247
|
+
);
|
|
12248
|
+
await ctx.database.write(async () => {
|
|
12249
|
+
const current = await ctx.summariesCollection.query(import_watermelondb5.Q.where("id", record2.id)).fetch();
|
|
12250
|
+
if (current[0]?.summary === stored2.summary) {
|
|
12251
|
+
await current[0].update((rec) => {
|
|
12252
|
+
rec.summary = encryptedSummary;
|
|
12253
|
+
});
|
|
12254
|
+
}
|
|
12255
|
+
});
|
|
12256
|
+
} catch (error) {
|
|
12257
|
+
getLogger().warn("Failed to encrypt the legacy summary:", error);
|
|
12258
|
+
}
|
|
12259
|
+
}
|
|
12260
|
+
return stored2;
|
|
12228
12261
|
}
|
|
12229
12262
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
12263
|
+
const revision2 = getConversationRevision(ctx.database, conversationId);
|
|
12230
12264
|
let record2;
|
|
12265
|
+
const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
|
|
12231
12266
|
await ctx.database.write(async () => {
|
|
12267
|
+
assertConversationRevision(ctx.database, conversationId, revision2);
|
|
12232
12268
|
const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
|
|
12233
12269
|
if (existing.length > 0) {
|
|
12234
12270
|
record2 = await existing[0].update((rec) => {
|
|
12235
|
-
rec.summary =
|
|
12271
|
+
rec.summary = encryptedSummary;
|
|
12236
12272
|
rec.summarizedUpTo = summarizedUpTo;
|
|
12237
12273
|
rec.tokenCount = tokenCount;
|
|
12238
12274
|
});
|
|
12239
12275
|
} else {
|
|
12240
12276
|
record2 = await ctx.summariesCollection.create((rec) => {
|
|
12241
12277
|
rec.conversationId = conversationId;
|
|
12242
|
-
rec.summary =
|
|
12278
|
+
rec.summary = encryptedSummary;
|
|
12243
12279
|
rec.summarizedUpTo = summarizedUpTo;
|
|
12244
12280
|
rec.tokenCount = tokenCount;
|
|
12245
12281
|
});
|
|
12246
12282
|
}
|
|
12247
12283
|
});
|
|
12248
|
-
return modelToStored(record2);
|
|
12284
|
+
return modelToStored(record2, summary);
|
|
12249
12285
|
}
|
|
12250
12286
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
12251
12287
|
await ctx.database.write(async () => {
|
|
@@ -12367,94 +12403,363 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
|
|
|
12367
12403
|
});
|
|
12368
12404
|
}
|
|
12369
12405
|
|
|
12370
|
-
// src/lib/
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
var
|
|
12375
|
-
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
"concept",
|
|
12382
|
-
"other"
|
|
12383
|
-
];
|
|
12384
|
-
function normalizeEntityName(name) {
|
|
12385
|
-
return name.trim().toLowerCase();
|
|
12406
|
+
// src/lib/chatStore/vaultRecords.ts
|
|
12407
|
+
var PINNED_SORT_BASE = 2 ** 51;
|
|
12408
|
+
var recordBudgetBytes = 104e4;
|
|
12409
|
+
var storedDims = 1536;
|
|
12410
|
+
var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
|
|
12411
|
+
var maxChunks = 16;
|
|
12412
|
+
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
12413
|
+
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
12414
|
+
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
12415
|
+
function plain(value) {
|
|
12416
|
+
return JSON.parse(JSON.stringify(value ?? {}));
|
|
12386
12417
|
}
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
return topic2.source === "user" ? 1 : topic2.weight ?? 1;
|
|
12418
|
+
function text4(value) {
|
|
12419
|
+
return typeof value === "string" ? value : void 0;
|
|
12390
12420
|
}
|
|
12391
|
-
function
|
|
12392
|
-
|
|
12393
|
-
|
|
12394
|
-
|
|
12421
|
+
function number(value) {
|
|
12422
|
+
return typeof value === "number" ? value : void 0;
|
|
12423
|
+
}
|
|
12424
|
+
function conversationSortKey(data, createdAt) {
|
|
12425
|
+
const pinnedAt = number(data.pinnedAt);
|
|
12426
|
+
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
12427
|
+
return number(data.lastActivityAt) ?? createdAt;
|
|
12428
|
+
}
|
|
12429
|
+
function toConversation(record2) {
|
|
12430
|
+
const pinnedAt = number(record2.data.pinnedAt);
|
|
12431
|
+
const projectId = text4(record2.data.projectId);
|
|
12432
|
+
return {
|
|
12433
|
+
uniqueId: record2.id,
|
|
12434
|
+
conversationId: record2.id,
|
|
12435
|
+
title: text4(record2.data.title) ?? "",
|
|
12436
|
+
...projectId ? { projectId } : {},
|
|
12437
|
+
createdAt: new Date(record2.createdAt),
|
|
12438
|
+
updatedAt: new Date(record2.updatedAt),
|
|
12439
|
+
isDeleted: record2.isDeleted,
|
|
12440
|
+
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
12441
|
+
};
|
|
12442
|
+
}
|
|
12443
|
+
function messageData(options) {
|
|
12444
|
+
return plain(
|
|
12445
|
+
Object.fromEntries(
|
|
12446
|
+
Object.entries(options).filter(
|
|
12447
|
+
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
12448
|
+
)
|
|
12449
|
+
)
|
|
12450
|
+
);
|
|
12451
|
+
}
|
|
12452
|
+
function toMessage(record2) {
|
|
12453
|
+
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
12454
|
+
return {
|
|
12455
|
+
...fields,
|
|
12456
|
+
uniqueId: record2.id,
|
|
12457
|
+
messageId: record2.sortKey,
|
|
12458
|
+
conversationId: record2.conversationId,
|
|
12459
|
+
createdAt: new Date(record2.createdAt),
|
|
12460
|
+
updatedAt: new Date(record2.updatedAt)
|
|
12461
|
+
};
|
|
12462
|
+
}
|
|
12463
|
+
function chunkOffsets(record2) {
|
|
12464
|
+
const offsets = record2.data.chunkOffsets;
|
|
12465
|
+
return Array.isArray(offsets) ? offsets : void 0;
|
|
12466
|
+
}
|
|
12467
|
+
function toSkeletons(records) {
|
|
12468
|
+
const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
|
|
12469
|
+
return records.map((r) => {
|
|
12470
|
+
const parentMessageId = text4(r.data.parentMessageId);
|
|
12471
|
+
const model = text4(r.data.model);
|
|
12472
|
+
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
12473
|
+
return {
|
|
12474
|
+
uniqueId: r.id,
|
|
12475
|
+
messageId: r.sortKey,
|
|
12476
|
+
conversationId: r.conversationId,
|
|
12477
|
+
role: text4(r.data.role) ?? "",
|
|
12478
|
+
createdAt: new Date(r.createdAt),
|
|
12479
|
+
...parentMessageId ? { parentMessageId } : {},
|
|
12480
|
+
...model ? { model } : {},
|
|
12481
|
+
...artifact ? { content: text4(r.data.content) ?? "" } : {}
|
|
12482
|
+
};
|
|
12483
|
+
});
|
|
12484
|
+
}
|
|
12485
|
+
function toSummary(record2) {
|
|
12486
|
+
return {
|
|
12487
|
+
uniqueId: record2.id,
|
|
12488
|
+
conversationId: record2.id,
|
|
12489
|
+
summary: text4(record2.data.summary) ?? "",
|
|
12490
|
+
summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
|
|
12491
|
+
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
12492
|
+
createdAt: new Date(record2.createdAt),
|
|
12493
|
+
updatedAt: new Date(record2.updatedAt)
|
|
12494
|
+
};
|
|
12495
|
+
}
|
|
12496
|
+
function links(data) {
|
|
12497
|
+
return Array.isArray(data.links) ? data.links : [];
|
|
12498
|
+
}
|
|
12499
|
+
function applyLinkOps(data, ops) {
|
|
12500
|
+
let current = links(data);
|
|
12501
|
+
for (const op of ops) {
|
|
12502
|
+
if ("clear" in op) {
|
|
12503
|
+
current = [];
|
|
12504
|
+
continue;
|
|
12505
|
+
}
|
|
12506
|
+
const byId = new Map(current.map((l) => [l.memoryId, l]));
|
|
12507
|
+
const turn = /* @__PURE__ */ new Set();
|
|
12508
|
+
op.add.forEach((item, i) => {
|
|
12509
|
+
if (!item.memoryId || turn.has(item.memoryId)) return;
|
|
12510
|
+
turn.add(item.memoryId);
|
|
12511
|
+
const known = byId.get(item.memoryId);
|
|
12512
|
+
if (known && known.createdAt >= op.at + i) return;
|
|
12513
|
+
byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
|
|
12514
|
+
});
|
|
12515
|
+
current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
|
|
12395
12516
|
}
|
|
12396
|
-
return
|
|
12517
|
+
return plain({ links: current });
|
|
12397
12518
|
}
|
|
12398
|
-
function
|
|
12399
|
-
return
|
|
12519
|
+
function toLinks(record2) {
|
|
12520
|
+
return links(record2.data).map((l) => ({
|
|
12521
|
+
uniqueId: `${record2.id}:${l.memoryId}`,
|
|
12522
|
+
conversationId: record2.id,
|
|
12523
|
+
memoryId: l.memoryId,
|
|
12524
|
+
score: l.score,
|
|
12525
|
+
createdAt: new Date(l.createdAt)
|
|
12526
|
+
}));
|
|
12400
12527
|
}
|
|
12401
|
-
function
|
|
12402
|
-
return JSON.stringify(
|
|
12528
|
+
function bytes(value) {
|
|
12529
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
12403
12530
|
}
|
|
12404
|
-
function
|
|
12405
|
-
if (
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12531
|
+
function fitRecord(record2) {
|
|
12532
|
+
if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
|
|
12533
|
+
const data = { ...record2.data };
|
|
12534
|
+
const truncated = [];
|
|
12535
|
+
for (const field10 of droppable) {
|
|
12536
|
+
if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
|
|
12537
|
+
if (data[field10] === void 0) continue;
|
|
12538
|
+
delete data[field10];
|
|
12539
|
+
truncated.push(field10);
|
|
12411
12540
|
}
|
|
12412
|
-
|
|
12541
|
+
const content = text4(data.content) ?? "";
|
|
12542
|
+
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
12543
|
+
if (over > 0) {
|
|
12544
|
+
const encoded = new TextEncoder().encode(content);
|
|
12545
|
+
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
12546
|
+
truncated.push("content");
|
|
12547
|
+
}
|
|
12548
|
+
return { ...record2, data: { ...data, truncated } };
|
|
12549
|
+
}
|
|
12550
|
+
function acceptedVector(vector2) {
|
|
12551
|
+
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
12552
|
+
if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims).some((x) => x !== 0))
|
|
12553
|
+
return void 0;
|
|
12554
|
+
return [...vector2];
|
|
12555
|
+
}
|
|
12556
|
+
function normalized(vector2) {
|
|
12557
|
+
const norm = Math.hypot(...vector2) || 1;
|
|
12558
|
+
return vector2.map((x) => x / norm);
|
|
12559
|
+
}
|
|
12560
|
+
function fitChunks(chunks3) {
|
|
12561
|
+
const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
|
|
12562
|
+
if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
|
|
12563
|
+
if (usable.length <= maxChunks) return usable;
|
|
12413
12564
|
const out = [];
|
|
12414
|
-
for (
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12565
|
+
for (let g = 0; g < maxChunks; g++) {
|
|
12566
|
+
const group = usable.slice(
|
|
12567
|
+
Math.floor(g * usable.length / maxChunks),
|
|
12568
|
+
Math.floor((g + 1) * usable.length / maxChunks)
|
|
12569
|
+
);
|
|
12570
|
+
const dims = group[0].vector.length;
|
|
12571
|
+
const mean = new Array(dims).fill(0);
|
|
12572
|
+
for (const c of group) {
|
|
12573
|
+
const unit = normalized(c.vector);
|
|
12574
|
+
for (let d = 0; d < dims; d++) mean[d] += unit[d];
|
|
12575
|
+
}
|
|
12419
12576
|
out.push({
|
|
12420
|
-
|
|
12421
|
-
|
|
12422
|
-
|
|
12423
|
-
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
12577
|
+
vector: normalized(mean),
|
|
12578
|
+
startOffset: group[0].startOffset,
|
|
12579
|
+
endOffset: group[group.length - 1].endOffset
|
|
12424
12580
|
});
|
|
12425
12581
|
}
|
|
12426
12582
|
return out;
|
|
12427
12583
|
}
|
|
12428
12584
|
|
|
12429
|
-
// src/lib/
|
|
12430
|
-
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12585
|
+
// src/lib/chatStore/chatImports.ts
|
|
12586
|
+
var importBatch = 100;
|
|
12587
|
+
var importChunks = 200;
|
|
12588
|
+
var importPlaintextBytes = 39e5;
|
|
12589
|
+
function ms(date10, fallback = 1) {
|
|
12590
|
+
const value = date10?.getTime();
|
|
12591
|
+
return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
|
|
12435
12592
|
}
|
|
12436
|
-
function
|
|
12593
|
+
function bytes2(value) {
|
|
12594
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
12595
|
+
}
|
|
12596
|
+
function conversationRecord(conversation, messages) {
|
|
12597
|
+
const createdAt = ms(conversation.createdAt);
|
|
12598
|
+
const data = plain({
|
|
12599
|
+
title: conversation.title,
|
|
12600
|
+
projectId: conversation.projectId || void 0,
|
|
12601
|
+
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
12602
|
+
lastActivityAt: Math.max(
|
|
12603
|
+
ms(conversation.updatedAt, createdAt),
|
|
12604
|
+
...messages.map((m) => ms(m.createdAt))
|
|
12605
|
+
)
|
|
12606
|
+
});
|
|
12437
12607
|
return {
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12608
|
+
record: {
|
|
12609
|
+
kind: "conversation",
|
|
12610
|
+
id: conversation.conversationId,
|
|
12611
|
+
conversationId: "",
|
|
12612
|
+
sortKey: conversationSortKey(data, createdAt),
|
|
12613
|
+
createdAt,
|
|
12614
|
+
updatedAt: ms(conversation.updatedAt, createdAt),
|
|
12615
|
+
isDeleted: false,
|
|
12616
|
+
data
|
|
12617
|
+
}
|
|
12618
|
+
};
|
|
12619
|
+
}
|
|
12620
|
+
function messageRecord(message) {
|
|
12621
|
+
const {
|
|
12622
|
+
uniqueId: _uniqueId,
|
|
12623
|
+
messageId: _messageId,
|
|
12624
|
+
createdAt: _createdAt,
|
|
12625
|
+
updatedAt: _updatedAt,
|
|
12626
|
+
decryptionStatus: _status,
|
|
12627
|
+
chunks: chunks3,
|
|
12628
|
+
vector: vector2,
|
|
12629
|
+
...fields
|
|
12630
|
+
} = message;
|
|
12631
|
+
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
12632
|
+
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
12633
|
+
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
12634
|
+
const record2 = fitRecord({
|
|
12635
|
+
kind: "message",
|
|
12636
|
+
id: message.uniqueId,
|
|
12637
|
+
conversationId: message.conversationId,
|
|
12638
|
+
sortKey: message.messageId,
|
|
12639
|
+
createdAt: ms(message.createdAt),
|
|
12640
|
+
updatedAt: ms(message.updatedAt, ms(message.createdAt)),
|
|
12641
|
+
isDeleted: false,
|
|
12642
|
+
data: {
|
|
12643
|
+
...messageData(fields),
|
|
12644
|
+
...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
|
|
12645
|
+
}
|
|
12646
|
+
});
|
|
12647
|
+
return {
|
|
12648
|
+
record: record2,
|
|
12649
|
+
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
12650
|
+
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
12651
|
+
};
|
|
12652
|
+
}
|
|
12653
|
+
function batches(records) {
|
|
12654
|
+
const out = [];
|
|
12655
|
+
let batch = [];
|
|
12656
|
+
let chunks3 = 0;
|
|
12657
|
+
let size = 0;
|
|
12658
|
+
for (const item of records) {
|
|
12659
|
+
const vectors = item.embeddings?.length ?? 0;
|
|
12660
|
+
const itemSize = bytes2(item.record);
|
|
12661
|
+
if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
|
|
12662
|
+
out.push(batch);
|
|
12663
|
+
batch = [];
|
|
12664
|
+
chunks3 = 0;
|
|
12665
|
+
size = 0;
|
|
12666
|
+
}
|
|
12667
|
+
batch.push(item);
|
|
12668
|
+
chunks3 += vectors;
|
|
12669
|
+
size += itemSize;
|
|
12670
|
+
}
|
|
12671
|
+
if (batch.length) out.push(batch);
|
|
12672
|
+
return out;
|
|
12673
|
+
}
|
|
12674
|
+
|
|
12675
|
+
// src/lib/memory/store/remotePersistence.ts
|
|
12676
|
+
init_portalLlm();
|
|
12677
|
+
|
|
12678
|
+
// src/lib/db/entities/types.ts
|
|
12679
|
+
var ENTITY_KINDS = [
|
|
12680
|
+
"person",
|
|
12681
|
+
"organization",
|
|
12682
|
+
"place",
|
|
12683
|
+
"event",
|
|
12684
|
+
"product",
|
|
12685
|
+
"thing",
|
|
12686
|
+
"concept",
|
|
12687
|
+
"other"
|
|
12688
|
+
];
|
|
12689
|
+
function normalizeEntityName(name) {
|
|
12690
|
+
return name.trim().toLowerCase();
|
|
12691
|
+
}
|
|
12692
|
+
var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
|
|
12693
|
+
function topicWeight(topic2) {
|
|
12694
|
+
return topic2.source === "user" ? 1 : topic2.weight ?? 1;
|
|
12695
|
+
}
|
|
12696
|
+
function primaryTopic(topics) {
|
|
12697
|
+
let best = null;
|
|
12698
|
+
for (const topic2 of topics ?? []) {
|
|
12699
|
+
if (best === null || topicWeight(topic2) > topicWeight(best)) best = topic2;
|
|
12700
|
+
}
|
|
12701
|
+
return best;
|
|
12702
|
+
}
|
|
12703
|
+
function parseTopicWeight(value) {
|
|
12704
|
+
return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
|
|
12705
|
+
}
|
|
12706
|
+
function serializeTopics(topics) {
|
|
12707
|
+
return JSON.stringify(topics);
|
|
12708
|
+
}
|
|
12709
|
+
function parseTopics(value) {
|
|
12710
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
12711
|
+
let parsed;
|
|
12712
|
+
try {
|
|
12713
|
+
parsed = JSON.parse(value);
|
|
12714
|
+
} catch {
|
|
12715
|
+
return null;
|
|
12716
|
+
}
|
|
12717
|
+
if (!Array.isArray(parsed)) return null;
|
|
12718
|
+
const out = [];
|
|
12719
|
+
for (const raw of parsed) {
|
|
12720
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
12721
|
+
const { name, kind, source, weight } = raw;
|
|
12722
|
+
if (typeof name !== "string" || name.trim().length === 0) continue;
|
|
12723
|
+
const parsedWeight = parseTopicWeight(weight);
|
|
12724
|
+
out.push({
|
|
12725
|
+
name,
|
|
12726
|
+
...typeof kind === "string" && kind.length > 0 ? { kind } : {},
|
|
12727
|
+
source: source === "user" ? "user" : "auto",
|
|
12728
|
+
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
12729
|
+
});
|
|
12730
|
+
}
|
|
12731
|
+
return out;
|
|
12732
|
+
}
|
|
12733
|
+
|
|
12734
|
+
// src/lib/memory/store/remoteTopics.ts
|
|
12735
|
+
function topic(value) {
|
|
12736
|
+
const t = value;
|
|
12737
|
+
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")
|
|
12738
|
+
throw new Error("Invalid nearby topic");
|
|
12739
|
+
return t;
|
|
12740
|
+
}
|
|
12741
|
+
function createRemoteTopicPersistence(request) {
|
|
12742
|
+
return {
|
|
12743
|
+
topics: async () => {
|
|
12744
|
+
const out = [];
|
|
12745
|
+
let cursor;
|
|
12746
|
+
do {
|
|
12747
|
+
const page = await request(
|
|
12748
|
+
"/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
|
|
12749
|
+
{}
|
|
12750
|
+
);
|
|
12751
|
+
if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
|
|
12752
|
+
throw new Error("Invalid nearby topic page");
|
|
12753
|
+
out.push(...page.items.map(topic));
|
|
12754
|
+
cursor = page.next_cursor;
|
|
12755
|
+
} while (cursor);
|
|
12756
|
+
return out;
|
|
12757
|
+
},
|
|
12758
|
+
putTopic: async (value, expectedVersion) => {
|
|
12759
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
12760
|
+
throw new Error("Expected topic version must be a nonnegative integer");
|
|
12761
|
+
return topic(
|
|
12762
|
+
await request("/topics", {
|
|
12458
12763
|
method: "PUT",
|
|
12459
12764
|
body: JSON.stringify({ topic: value, expected_version: expectedVersion })
|
|
12460
12765
|
})
|
|
@@ -13109,7 +13414,7 @@ var ChatStoreError = class extends Error {
|
|
|
13109
13414
|
var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
|
|
13110
13415
|
var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
|
|
13111
13416
|
var maxPayload = 2 * 1024 * 1024;
|
|
13112
|
-
var
|
|
13417
|
+
var storedDims2 = 1536;
|
|
13113
13418
|
var maxRequestCiphertext = 8 * 1024 * 1024;
|
|
13114
13419
|
var maxGetRefs = 50;
|
|
13115
13420
|
var maxImportRecords = 100;
|
|
@@ -13177,24 +13482,24 @@ function vector(v) {
|
|
|
13177
13482
|
for (let i = 0; i < v.length; i++) {
|
|
13178
13483
|
const x = v[i];
|
|
13179
13484
|
if (typeof x !== "number" || !Number.isFinite(x)) return false;
|
|
13180
|
-
if (i <
|
|
13485
|
+
if (i < storedDims2 && x !== 0) nonZero = true;
|
|
13181
13486
|
}
|
|
13182
13487
|
return nonZero;
|
|
13183
13488
|
}
|
|
13184
13489
|
function vectorFields(write) {
|
|
13185
13490
|
return {
|
|
13186
|
-
...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0,
|
|
13491
|
+
...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
|
|
13187
13492
|
...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
|
|
13188
13493
|
};
|
|
13189
13494
|
}
|
|
13190
|
-
function
|
|
13495
|
+
function text5(value) {
|
|
13191
13496
|
return typeof value === "string";
|
|
13192
13497
|
}
|
|
13193
13498
|
function timestamp(value) {
|
|
13194
13499
|
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
13195
13500
|
}
|
|
13196
13501
|
function presigned(value) {
|
|
13197
|
-
if (!object(value) || !
|
|
13502
|
+
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))
|
|
13198
13503
|
invalid();
|
|
13199
13504
|
return {
|
|
13200
13505
|
url: value.url,
|
|
@@ -13204,7 +13509,7 @@ function presigned(value) {
|
|
|
13204
13509
|
};
|
|
13205
13510
|
}
|
|
13206
13511
|
function attachment(value) {
|
|
13207
|
-
if (!object(value) || !
|
|
13512
|
+
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))
|
|
13208
13513
|
invalid();
|
|
13209
13514
|
return {
|
|
13210
13515
|
id: value.attachment_id,
|
|
@@ -13217,7 +13522,7 @@ function attachment(value) {
|
|
|
13217
13522
|
};
|
|
13218
13523
|
}
|
|
13219
13524
|
function ref(value) {
|
|
13220
|
-
if (!object(value) || !
|
|
13525
|
+
if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
|
|
13221
13526
|
return { kind: value.kind, id: value.id };
|
|
13222
13527
|
}
|
|
13223
13528
|
function sameMetadata(a, b) {
|
|
@@ -13440,7 +13745,7 @@ async function createRemoteChatStore(options) {
|
|
|
13440
13745
|
},
|
|
13441
13746
|
async account(signal) {
|
|
13442
13747
|
const value = await request("/account", {}, signal);
|
|
13443
|
-
if (!object(value) || value.account_id !== accountId || !
|
|
13748
|
+
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))
|
|
13444
13749
|
invalid();
|
|
13445
13750
|
if (value.key_id && value.key_id !== keyId)
|
|
13446
13751
|
throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
|
|
@@ -13485,363 +13790,177 @@ async function createRemoteChatStore(options) {
|
|
|
13485
13790
|
return {
|
|
13486
13791
|
kind: checked.kind,
|
|
13487
13792
|
id: checked.id,
|
|
13488
|
-
updated_at: r.updatedAt,
|
|
13489
|
-
is_deleted: r.isDeleted
|
|
13490
|
-
};
|
|
13491
|
-
});
|
|
13492
|
-
if (wireRevisions.length === 0) return [];
|
|
13493
|
-
const value = await request(
|
|
13494
|
-
"/verify",
|
|
13495
|
-
{
|
|
13496
|
-
method: "POST",
|
|
13497
|
-
body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
|
|
13498
|
-
},
|
|
13499
|
-
signal
|
|
13500
|
-
);
|
|
13501
|
-
if (!object(value) || !Array.isArray(value.missing)) invalid();
|
|
13502
|
-
const missing2 = value.missing.map(ref);
|
|
13503
|
-
if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
|
|
13504
|
-
return missing2;
|
|
13505
|
-
},
|
|
13506
|
-
async activate(signal) {
|
|
13507
|
-
const value = await request(
|
|
13508
|
-
"/account",
|
|
13509
|
-
{ method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
|
|
13510
|
-
signal
|
|
13511
|
-
);
|
|
13512
|
-
if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
|
|
13513
|
-
invalid();
|
|
13514
|
-
return value.transitioned;
|
|
13515
|
-
},
|
|
13516
|
-
async changes(cursor, options2) {
|
|
13517
|
-
const limit = options2?.limit ?? 100;
|
|
13518
|
-
if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!
|
|
13519
|
-
invalid();
|
|
13520
|
-
const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
|
|
13521
|
-
if (cursor) params.set("cursor", cursor);
|
|
13522
|
-
const value = await request(`/changes?${params}`, {}, options2?.signal);
|
|
13523
|
-
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !
|
|
13524
|
-
invalid();
|
|
13525
|
-
const items = [];
|
|
13526
|
-
for (const item of value.items) items.push(await decode(item));
|
|
13527
|
-
options2?.signal?.throwIfAborted();
|
|
13528
|
-
return {
|
|
13529
|
-
items,
|
|
13530
|
-
...value.next_cursor ? { nextCursor: value.next_cursor } : {},
|
|
13531
|
-
changesCursor: value.changes_cursor ?? cursor ?? ""
|
|
13532
|
-
};
|
|
13533
|
-
},
|
|
13534
|
-
async search(embedding2, options2) {
|
|
13535
|
-
const limit = options2?.limit ?? 20;
|
|
13536
|
-
const kindsFilter = options2?.kinds;
|
|
13537
|
-
if (!Array.isArray(embedding2) || !embeddings({
|
|
13538
|
-
record: { ...emptyMessage, isDeleted: false },
|
|
13539
|
-
embeddings: [embedding2]
|
|
13540
|
-
}) || !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 && (!
|
|
13541
|
-
invalid();
|
|
13542
|
-
const value = await request(
|
|
13543
|
-
"/search",
|
|
13544
|
-
{
|
|
13545
|
-
method: "POST",
|
|
13546
|
-
body: JSON.stringify({
|
|
13547
|
-
account_id: accountId,
|
|
13548
|
-
embedding: embedding2.slice(0,
|
|
13549
|
-
limit,
|
|
13550
|
-
...kindsFilter ? { kinds: kindsFilter } : {},
|
|
13551
|
-
...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
|
|
13552
|
-
...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
|
|
13553
|
-
...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
|
|
13554
|
-
})
|
|
13555
|
-
},
|
|
13556
|
-
options2?.signal
|
|
13557
|
-
);
|
|
13558
|
-
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
|
|
13559
|
-
const hits = [];
|
|
13560
|
-
for (const item of value.items) {
|
|
13561
|
-
if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
|
|
13562
|
-
invalid();
|
|
13563
|
-
const snapshot = await decode(item);
|
|
13564
|
-
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)
|
|
13565
|
-
invalid();
|
|
13566
|
-
hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
|
|
13567
|
-
}
|
|
13568
|
-
options2?.signal?.throwIfAborted();
|
|
13569
|
-
return hits;
|
|
13570
|
-
},
|
|
13571
|
-
async deleteAll(signal) {
|
|
13572
|
-
const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
|
|
13573
|
-
if (!object(value) || !integer(value.deleted)) invalid();
|
|
13574
|
-
return value.deleted;
|
|
13575
|
-
},
|
|
13576
|
-
attachments: {
|
|
13577
|
-
async create(sizeBytes, signal) {
|
|
13578
|
-
if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
|
|
13579
|
-
const value = await request(
|
|
13580
|
-
"/attachments",
|
|
13581
|
-
{
|
|
13582
|
-
method: "POST",
|
|
13583
|
-
body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
|
|
13584
|
-
},
|
|
13585
|
-
signal
|
|
13586
|
-
);
|
|
13587
|
-
if (!object(value)) invalid();
|
|
13588
|
-
const created = attachment(value.attachment);
|
|
13589
|
-
if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
|
|
13590
|
-
return { attachment: created, upload: presigned(value.upload) };
|
|
13591
|
-
},
|
|
13592
|
-
async commit(attachmentId, owner, signal) {
|
|
13593
|
-
if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
|
|
13594
|
-
invalid();
|
|
13595
|
-
const value = await request(
|
|
13596
|
-
`/attachments/${attachmentId}/commit`,
|
|
13597
|
-
{
|
|
13598
|
-
method: "POST",
|
|
13599
|
-
body: JSON.stringify({
|
|
13600
|
-
account_id: accountId,
|
|
13601
|
-
owner_kind: owner.kind,
|
|
13602
|
-
owner_id: owner.id
|
|
13603
|
-
})
|
|
13604
|
-
},
|
|
13605
|
-
signal
|
|
13606
|
-
);
|
|
13607
|
-
if (!object(value)) invalid();
|
|
13608
|
-
const committed = attachment(value.attachment);
|
|
13609
|
-
if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
|
|
13610
|
-
invalid();
|
|
13611
|
-
return committed;
|
|
13612
|
-
},
|
|
13613
|
-
async get(attachmentId, signal) {
|
|
13614
|
-
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
13615
|
-
let value;
|
|
13616
|
-
try {
|
|
13617
|
-
value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
|
|
13618
|
-
} catch (error) {
|
|
13619
|
-
if (error instanceof ChatStoreError && error.status === 404) return null;
|
|
13620
|
-
throw error;
|
|
13621
|
-
}
|
|
13622
|
-
if (!object(value)) invalid();
|
|
13623
|
-
const found = attachment(value.attachment);
|
|
13624
|
-
if (found.id !== attachmentId) invalid();
|
|
13625
|
-
return {
|
|
13626
|
-
attachment: found,
|
|
13627
|
-
...value.download !== void 0 ? { download: presigned(value.download) } : {}
|
|
13628
|
-
};
|
|
13629
|
-
},
|
|
13630
|
-
async delete(attachmentId, signal) {
|
|
13631
|
-
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
13632
|
-
await request(
|
|
13633
|
-
`/attachments/${attachmentId}?account_id=${accountId}`,
|
|
13634
|
-
{ method: "DELETE" },
|
|
13635
|
-
signal
|
|
13636
|
-
);
|
|
13637
|
-
}
|
|
13638
|
-
}
|
|
13639
|
-
};
|
|
13640
|
-
}
|
|
13641
|
-
var emptyMessage = {
|
|
13642
|
-
kind: "message",
|
|
13643
|
-
id: "query",
|
|
13644
|
-
conversationId: "query",
|
|
13645
|
-
sortKey: 0,
|
|
13646
|
-
createdAt: 1,
|
|
13647
|
-
updatedAt: 1,
|
|
13648
|
-
isDeleted: false,
|
|
13649
|
-
data: {}
|
|
13650
|
-
};
|
|
13651
|
-
|
|
13652
|
-
// src/lib/chatStore/vaultRecords.ts
|
|
13653
|
-
var PINNED_SORT_BASE = 2 ** 51;
|
|
13654
|
-
var recordBudgetBytes = 104e4;
|
|
13655
|
-
var storedDims2 = 1536;
|
|
13656
|
-
var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
|
|
13657
|
-
var maxChunks = 16;
|
|
13658
|
-
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
13659
|
-
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
13660
|
-
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
13661
|
-
function plain(value) {
|
|
13662
|
-
return JSON.parse(JSON.stringify(value ?? {}));
|
|
13663
|
-
}
|
|
13664
|
-
function text5(value) {
|
|
13665
|
-
return typeof value === "string" ? value : void 0;
|
|
13666
|
-
}
|
|
13667
|
-
function number(value) {
|
|
13668
|
-
return typeof value === "number" ? value : void 0;
|
|
13669
|
-
}
|
|
13670
|
-
function conversationSortKey(data, createdAt) {
|
|
13671
|
-
const pinnedAt = number(data.pinnedAt);
|
|
13672
|
-
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
13673
|
-
return number(data.lastActivityAt) ?? createdAt;
|
|
13674
|
-
}
|
|
13675
|
-
function toConversation(record2) {
|
|
13676
|
-
const pinnedAt = number(record2.data.pinnedAt);
|
|
13677
|
-
const projectId = text5(record2.data.projectId);
|
|
13678
|
-
return {
|
|
13679
|
-
uniqueId: record2.id,
|
|
13680
|
-
conversationId: record2.id,
|
|
13681
|
-
title: text5(record2.data.title) ?? "",
|
|
13682
|
-
...projectId ? { projectId } : {},
|
|
13683
|
-
createdAt: new Date(record2.createdAt),
|
|
13684
|
-
updatedAt: new Date(record2.updatedAt),
|
|
13685
|
-
isDeleted: record2.isDeleted,
|
|
13686
|
-
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
13687
|
-
};
|
|
13688
|
-
}
|
|
13689
|
-
function messageData(options) {
|
|
13690
|
-
return plain(
|
|
13691
|
-
Object.fromEntries(
|
|
13692
|
-
Object.entries(options).filter(
|
|
13693
|
-
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
13694
|
-
)
|
|
13695
|
-
)
|
|
13696
|
-
);
|
|
13697
|
-
}
|
|
13698
|
-
function toMessage(record2) {
|
|
13699
|
-
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
13700
|
-
return {
|
|
13701
|
-
...fields,
|
|
13702
|
-
uniqueId: record2.id,
|
|
13703
|
-
messageId: record2.sortKey,
|
|
13704
|
-
conversationId: record2.conversationId,
|
|
13705
|
-
createdAt: new Date(record2.createdAt),
|
|
13706
|
-
updatedAt: new Date(record2.updatedAt)
|
|
13707
|
-
};
|
|
13708
|
-
}
|
|
13709
|
-
function chunkOffsets(record2) {
|
|
13710
|
-
const offsets = record2.data.chunkOffsets;
|
|
13711
|
-
return Array.isArray(offsets) ? offsets : void 0;
|
|
13712
|
-
}
|
|
13713
|
-
function toSkeletons(records) {
|
|
13714
|
-
const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
|
|
13715
|
-
return records.map((r) => {
|
|
13716
|
-
const parentMessageId = text5(r.data.parentMessageId);
|
|
13717
|
-
const model = text5(r.data.model);
|
|
13718
|
-
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
13719
|
-
return {
|
|
13720
|
-
uniqueId: r.id,
|
|
13721
|
-
messageId: r.sortKey,
|
|
13722
|
-
conversationId: r.conversationId,
|
|
13723
|
-
role: text5(r.data.role) ?? "",
|
|
13724
|
-
createdAt: new Date(r.createdAt),
|
|
13725
|
-
...parentMessageId ? { parentMessageId } : {},
|
|
13726
|
-
...model ? { model } : {},
|
|
13727
|
-
...artifact ? { content: text5(r.data.content) ?? "" } : {}
|
|
13728
|
-
};
|
|
13729
|
-
});
|
|
13730
|
-
}
|
|
13731
|
-
function toSummary(record2) {
|
|
13732
|
-
return {
|
|
13733
|
-
uniqueId: record2.id,
|
|
13734
|
-
conversationId: record2.id,
|
|
13735
|
-
summary: text5(record2.data.summary) ?? "",
|
|
13736
|
-
summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
|
|
13737
|
-
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
13738
|
-
createdAt: new Date(record2.createdAt),
|
|
13739
|
-
updatedAt: new Date(record2.updatedAt)
|
|
13740
|
-
};
|
|
13741
|
-
}
|
|
13742
|
-
function links(data) {
|
|
13743
|
-
return Array.isArray(data.links) ? data.links : [];
|
|
13744
|
-
}
|
|
13745
|
-
function applyLinkOps(data, ops) {
|
|
13746
|
-
let current = links(data);
|
|
13747
|
-
for (const op of ops) {
|
|
13748
|
-
if ("clear" in op) {
|
|
13749
|
-
current = [];
|
|
13750
|
-
continue;
|
|
13751
|
-
}
|
|
13752
|
-
const byId = new Map(current.map((l) => [l.memoryId, l]));
|
|
13753
|
-
const turn = /* @__PURE__ */ new Set();
|
|
13754
|
-
op.add.forEach((item, i) => {
|
|
13755
|
-
if (!item.memoryId || turn.has(item.memoryId)) return;
|
|
13756
|
-
turn.add(item.memoryId);
|
|
13757
|
-
const known = byId.get(item.memoryId);
|
|
13758
|
-
if (known && known.createdAt >= op.at + i) return;
|
|
13759
|
-
byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
|
|
13760
|
-
});
|
|
13761
|
-
current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
|
|
13762
|
-
}
|
|
13763
|
-
return plain({ links: current });
|
|
13764
|
-
}
|
|
13765
|
-
function toLinks(record2) {
|
|
13766
|
-
return links(record2.data).map((l) => ({
|
|
13767
|
-
uniqueId: `${record2.id}:${l.memoryId}`,
|
|
13768
|
-
conversationId: record2.id,
|
|
13769
|
-
memoryId: l.memoryId,
|
|
13770
|
-
score: l.score,
|
|
13771
|
-
createdAt: new Date(l.createdAt)
|
|
13772
|
-
}));
|
|
13773
|
-
}
|
|
13774
|
-
function bytes(value) {
|
|
13775
|
-
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
13776
|
-
}
|
|
13777
|
-
function fitRecord(record2) {
|
|
13778
|
-
if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
|
|
13779
|
-
const data = { ...record2.data };
|
|
13780
|
-
const truncated = [];
|
|
13781
|
-
for (const field10 of droppable) {
|
|
13782
|
-
if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
|
|
13783
|
-
if (data[field10] === void 0) continue;
|
|
13784
|
-
delete data[field10];
|
|
13785
|
-
truncated.push(field10);
|
|
13786
|
-
}
|
|
13787
|
-
const content = text5(data.content) ?? "";
|
|
13788
|
-
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
13789
|
-
if (over > 0) {
|
|
13790
|
-
const encoded = new TextEncoder().encode(content);
|
|
13791
|
-
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
13792
|
-
truncated.push("content");
|
|
13793
|
-
}
|
|
13794
|
-
return { ...record2, data: { ...data, truncated } };
|
|
13795
|
-
}
|
|
13796
|
-
function acceptedVector(vector2) {
|
|
13797
|
-
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
13798
|
-
if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
|
|
13799
|
-
return void 0;
|
|
13800
|
-
return [...vector2];
|
|
13801
|
-
}
|
|
13802
|
-
function normalized(vector2) {
|
|
13803
|
-
const norm = Math.hypot(...vector2) || 1;
|
|
13804
|
-
return vector2.map((x) => x / norm);
|
|
13805
|
-
}
|
|
13806
|
-
function fitChunks(chunks3) {
|
|
13807
|
-
const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
|
|
13808
|
-
if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
|
|
13809
|
-
if (usable.length <= maxChunks) return usable;
|
|
13810
|
-
const out = [];
|
|
13811
|
-
for (let g = 0; g < maxChunks; g++) {
|
|
13812
|
-
const group = usable.slice(
|
|
13813
|
-
Math.floor(g * usable.length / maxChunks),
|
|
13814
|
-
Math.floor((g + 1) * usable.length / maxChunks)
|
|
13815
|
-
);
|
|
13816
|
-
const dims = group[0].vector.length;
|
|
13817
|
-
const mean = new Array(dims).fill(0);
|
|
13818
|
-
for (const c of group) {
|
|
13819
|
-
const unit = normalized(c.vector);
|
|
13820
|
-
for (let d = 0; d < dims; d++) mean[d] += unit[d];
|
|
13793
|
+
updated_at: r.updatedAt,
|
|
13794
|
+
is_deleted: r.isDeleted
|
|
13795
|
+
};
|
|
13796
|
+
});
|
|
13797
|
+
if (wireRevisions.length === 0) return [];
|
|
13798
|
+
const value = await request(
|
|
13799
|
+
"/verify",
|
|
13800
|
+
{
|
|
13801
|
+
method: "POST",
|
|
13802
|
+
body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
|
|
13803
|
+
},
|
|
13804
|
+
signal
|
|
13805
|
+
);
|
|
13806
|
+
if (!object(value) || !Array.isArray(value.missing)) invalid();
|
|
13807
|
+
const missing2 = value.missing.map(ref);
|
|
13808
|
+
if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
|
|
13809
|
+
return missing2;
|
|
13810
|
+
},
|
|
13811
|
+
async activate(signal) {
|
|
13812
|
+
const value = await request(
|
|
13813
|
+
"/account",
|
|
13814
|
+
{ method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
|
|
13815
|
+
signal
|
|
13816
|
+
);
|
|
13817
|
+
if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
|
|
13818
|
+
invalid();
|
|
13819
|
+
return value.transitioned;
|
|
13820
|
+
},
|
|
13821
|
+
async changes(cursor, options2) {
|
|
13822
|
+
const limit = options2?.limit ?? 100;
|
|
13823
|
+
if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
|
|
13824
|
+
invalid();
|
|
13825
|
+
const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
|
|
13826
|
+
if (cursor) params.set("cursor", cursor);
|
|
13827
|
+
const value = await request(`/changes?${params}`, {}, options2?.signal);
|
|
13828
|
+
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))
|
|
13829
|
+
invalid();
|
|
13830
|
+
const items = [];
|
|
13831
|
+
for (const item of value.items) items.push(await decode(item));
|
|
13832
|
+
options2?.signal?.throwIfAborted();
|
|
13833
|
+
return {
|
|
13834
|
+
items,
|
|
13835
|
+
...value.next_cursor ? { nextCursor: value.next_cursor } : {},
|
|
13836
|
+
changesCursor: value.changes_cursor ?? cursor ?? ""
|
|
13837
|
+
};
|
|
13838
|
+
},
|
|
13839
|
+
async search(embedding2, options2) {
|
|
13840
|
+
const limit = options2?.limit ?? 20;
|
|
13841
|
+
const kindsFilter = options2?.kinds;
|
|
13842
|
+
if (!Array.isArray(embedding2) || !embeddings({
|
|
13843
|
+
record: { ...emptyMessage, isDeleted: false },
|
|
13844
|
+
embeddings: [embedding2]
|
|
13845
|
+
}) || !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))
|
|
13846
|
+
invalid();
|
|
13847
|
+
const value = await request(
|
|
13848
|
+
"/search",
|
|
13849
|
+
{
|
|
13850
|
+
method: "POST",
|
|
13851
|
+
body: JSON.stringify({
|
|
13852
|
+
account_id: accountId,
|
|
13853
|
+
embedding: embedding2.slice(0, storedDims2),
|
|
13854
|
+
limit,
|
|
13855
|
+
...kindsFilter ? { kinds: kindsFilter } : {},
|
|
13856
|
+
...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
|
|
13857
|
+
...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
|
|
13858
|
+
...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
|
|
13859
|
+
})
|
|
13860
|
+
},
|
|
13861
|
+
options2?.signal
|
|
13862
|
+
);
|
|
13863
|
+
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
|
|
13864
|
+
const hits = [];
|
|
13865
|
+
for (const item of value.items) {
|
|
13866
|
+
if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
|
|
13867
|
+
invalid();
|
|
13868
|
+
const snapshot = await decode(item);
|
|
13869
|
+
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)
|
|
13870
|
+
invalid();
|
|
13871
|
+
hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
|
|
13872
|
+
}
|
|
13873
|
+
options2?.signal?.throwIfAborted();
|
|
13874
|
+
return hits;
|
|
13875
|
+
},
|
|
13876
|
+
async deleteAll(signal) {
|
|
13877
|
+
const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
|
|
13878
|
+
if (!object(value) || !integer(value.deleted)) invalid();
|
|
13879
|
+
return value.deleted;
|
|
13880
|
+
},
|
|
13881
|
+
attachments: {
|
|
13882
|
+
async create(sizeBytes, signal) {
|
|
13883
|
+
if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
|
|
13884
|
+
const value = await request(
|
|
13885
|
+
"/attachments",
|
|
13886
|
+
{
|
|
13887
|
+
method: "POST",
|
|
13888
|
+
body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
|
|
13889
|
+
},
|
|
13890
|
+
signal
|
|
13891
|
+
);
|
|
13892
|
+
if (!object(value)) invalid();
|
|
13893
|
+
const created = attachment(value.attachment);
|
|
13894
|
+
if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
|
|
13895
|
+
return { attachment: created, upload: presigned(value.upload) };
|
|
13896
|
+
},
|
|
13897
|
+
async commit(attachmentId, owner, signal) {
|
|
13898
|
+
if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
|
|
13899
|
+
invalid();
|
|
13900
|
+
const value = await request(
|
|
13901
|
+
`/attachments/${attachmentId}/commit`,
|
|
13902
|
+
{
|
|
13903
|
+
method: "POST",
|
|
13904
|
+
body: JSON.stringify({
|
|
13905
|
+
account_id: accountId,
|
|
13906
|
+
owner_kind: owner.kind,
|
|
13907
|
+
owner_id: owner.id
|
|
13908
|
+
})
|
|
13909
|
+
},
|
|
13910
|
+
signal
|
|
13911
|
+
);
|
|
13912
|
+
if (!object(value)) invalid();
|
|
13913
|
+
const committed = attachment(value.attachment);
|
|
13914
|
+
if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
|
|
13915
|
+
invalid();
|
|
13916
|
+
return committed;
|
|
13917
|
+
},
|
|
13918
|
+
async get(attachmentId, signal) {
|
|
13919
|
+
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
13920
|
+
let value;
|
|
13921
|
+
try {
|
|
13922
|
+
value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
|
|
13923
|
+
} catch (error) {
|
|
13924
|
+
if (error instanceof ChatStoreError && error.status === 404) return null;
|
|
13925
|
+
throw error;
|
|
13926
|
+
}
|
|
13927
|
+
if (!object(value)) invalid();
|
|
13928
|
+
const found = attachment(value.attachment);
|
|
13929
|
+
if (found.id !== attachmentId) invalid();
|
|
13930
|
+
return {
|
|
13931
|
+
attachment: found,
|
|
13932
|
+
...value.download !== void 0 ? { download: presigned(value.download) } : {}
|
|
13933
|
+
};
|
|
13934
|
+
},
|
|
13935
|
+
async delete(attachmentId, signal) {
|
|
13936
|
+
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
13937
|
+
await request(
|
|
13938
|
+
`/attachments/${attachmentId}?account_id=${accountId}`,
|
|
13939
|
+
{ method: "DELETE" },
|
|
13940
|
+
signal
|
|
13941
|
+
);
|
|
13942
|
+
}
|
|
13821
13943
|
}
|
|
13822
|
-
|
|
13823
|
-
vector: normalized(mean),
|
|
13824
|
-
startOffset: group[0].startOffset,
|
|
13825
|
-
endOffset: group[group.length - 1].endOffset
|
|
13826
|
-
});
|
|
13827
|
-
}
|
|
13828
|
-
return out;
|
|
13944
|
+
};
|
|
13829
13945
|
}
|
|
13946
|
+
var emptyMessage = {
|
|
13947
|
+
kind: "message",
|
|
13948
|
+
id: "query",
|
|
13949
|
+
conversationId: "query",
|
|
13950
|
+
sortKey: 0,
|
|
13951
|
+
createdAt: 1,
|
|
13952
|
+
updatedAt: 1,
|
|
13953
|
+
isDeleted: false,
|
|
13954
|
+
data: {}
|
|
13955
|
+
};
|
|
13830
13956
|
|
|
13831
13957
|
// src/lib/chatStore/migrateChats.ts
|
|
13832
13958
|
var maxPasses = 5;
|
|
13833
13959
|
var verifyBatch = 1e3;
|
|
13834
|
-
var importBatch = 100;
|
|
13835
|
-
var importChunks = 200;
|
|
13836
|
-
var importPlaintextBytes = 39e5;
|
|
13837
13960
|
var writeBatch = 25;
|
|
13838
13961
|
function key(record2) {
|
|
13839
13962
|
return `${record2.kind}/${record2.id}`;
|
|
13840
13963
|
}
|
|
13841
|
-
function ms(date10, fallback = 1) {
|
|
13842
|
-
const value = date10?.getTime();
|
|
13843
|
-
return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
|
|
13844
|
-
}
|
|
13845
13964
|
function sealed(value) {
|
|
13846
13965
|
if (typeof value === "string") return isEncrypted(value);
|
|
13847
13966
|
if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
|
|
@@ -13849,42 +13968,6 @@ function sealed(value) {
|
|
|
13849
13968
|
return Object.values(value).some(sealed);
|
|
13850
13969
|
return false;
|
|
13851
13970
|
}
|
|
13852
|
-
function bytes2(value) {
|
|
13853
|
-
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
13854
|
-
}
|
|
13855
|
-
function messageRecord(message) {
|
|
13856
|
-
const {
|
|
13857
|
-
uniqueId: _uniqueId,
|
|
13858
|
-
messageId: _messageId,
|
|
13859
|
-
createdAt: _createdAt,
|
|
13860
|
-
updatedAt: _updatedAt,
|
|
13861
|
-
decryptionStatus: _status,
|
|
13862
|
-
chunks: chunks3,
|
|
13863
|
-
vector: vector2,
|
|
13864
|
-
...fields
|
|
13865
|
-
} = message;
|
|
13866
|
-
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
13867
|
-
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
13868
|
-
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
13869
|
-
const record2 = fitRecord({
|
|
13870
|
-
kind: "message",
|
|
13871
|
-
id: message.uniqueId,
|
|
13872
|
-
conversationId: message.conversationId,
|
|
13873
|
-
sortKey: message.messageId,
|
|
13874
|
-
createdAt: ms(message.createdAt),
|
|
13875
|
-
updatedAt: ms(message.updatedAt, ms(message.createdAt)),
|
|
13876
|
-
isDeleted: false,
|
|
13877
|
-
data: {
|
|
13878
|
-
...messageData(fields),
|
|
13879
|
-
...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
|
|
13880
|
-
}
|
|
13881
|
-
});
|
|
13882
|
-
return {
|
|
13883
|
-
record: record2,
|
|
13884
|
-
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
13885
|
-
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
13886
|
-
};
|
|
13887
|
-
}
|
|
13888
13971
|
async function readLocal(options) {
|
|
13889
13972
|
const { database } = options;
|
|
13890
13973
|
const ctx = {
|
|
@@ -13895,7 +13978,7 @@ async function readLocal(options) {
|
|
|
13895
13978
|
signMessage: options.signMessage,
|
|
13896
13979
|
embeddedWalletSigner: options.embeddedWalletSigner
|
|
13897
13980
|
};
|
|
13898
|
-
const summaries = createSummaryContext(database);
|
|
13981
|
+
const summaries = createSummaryContext(database, ctx);
|
|
13899
13982
|
const memory = {
|
|
13900
13983
|
database,
|
|
13901
13984
|
conversationMemoryCollection: database.get(ConversationMemory.table)
|
|
@@ -13938,29 +14021,10 @@ async function readLocal(options) {
|
|
|
13938
14021
|
const messages = await getMessagesOp(ctx, conversationId);
|
|
13939
14022
|
const unreadableTitle = isEncrypted(conversation.title);
|
|
13940
14023
|
if (unreadableTitle) out.untitled++;
|
|
13941
|
-
const createdAt = ms(conversation.createdAt);
|
|
13942
|
-
const data = plain({
|
|
13943
|
-
title: unreadableTitle ? "" : conversation.title,
|
|
13944
|
-
projectId: conversation.projectId || void 0,
|
|
13945
|
-
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
13946
|
-
lastActivityAt: Math.max(
|
|
13947
|
-
ms(conversation.updatedAt, createdAt),
|
|
13948
|
-
...messages.map((m) => ms(m.createdAt))
|
|
13949
|
-
)
|
|
13950
|
-
});
|
|
13951
14024
|
out.conversations++;
|
|
13952
|
-
out.records.push(
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
id: conversationId,
|
|
13956
|
-
conversationId: "",
|
|
13957
|
-
sortKey: conversationSortKey(data, createdAt),
|
|
13958
|
-
createdAt,
|
|
13959
|
-
updatedAt: ms(conversation.updatedAt, createdAt),
|
|
13960
|
-
isDeleted: false,
|
|
13961
|
-
data
|
|
13962
|
-
}
|
|
13963
|
-
});
|
|
14025
|
+
out.records.push(
|
|
14026
|
+
conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
|
|
14027
|
+
);
|
|
13964
14028
|
for (const message of messages) {
|
|
13965
14029
|
if (message.decryptionStatus || sealed(message)) {
|
|
13966
14030
|
skip("message", message.uniqueId, "unreadable");
|
|
@@ -13976,7 +14040,9 @@ async function readLocal(options) {
|
|
|
13976
14040
|
out.records.push(prepared);
|
|
13977
14041
|
}
|
|
13978
14042
|
const summary = await getConversationSummaryOp(summaries, conversationId);
|
|
13979
|
-
if (summary)
|
|
14043
|
+
if (summary && isEncrypted(summary.summary)) {
|
|
14044
|
+
skip("summary", conversationId, "unreadable");
|
|
14045
|
+
} else if (summary)
|
|
13980
14046
|
out.records.push({
|
|
13981
14047
|
record: {
|
|
13982
14048
|
kind: "summary",
|
|
@@ -14079,27 +14145,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
|
|
|
14079
14145
|
};
|
|
14080
14146
|
});
|
|
14081
14147
|
}
|
|
14082
|
-
function batches(records) {
|
|
14083
|
-
const out = [];
|
|
14084
|
-
let batch = [];
|
|
14085
|
-
let chunks3 = 0;
|
|
14086
|
-
let size = 0;
|
|
14087
|
-
for (const item of records) {
|
|
14088
|
-
const vectors = item.embeddings?.length ?? 0;
|
|
14089
|
-
const itemSize = bytes2(item.record);
|
|
14090
|
-
if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
|
|
14091
|
-
out.push(batch);
|
|
14092
|
-
batch = [];
|
|
14093
|
-
chunks3 = 0;
|
|
14094
|
-
size = 0;
|
|
14095
|
-
}
|
|
14096
|
-
batch.push(item);
|
|
14097
|
-
chunks3 += vectors;
|
|
14098
|
-
size += itemSize;
|
|
14099
|
-
}
|
|
14100
|
-
if (batch.length) out.push(batch);
|
|
14101
|
-
return out;
|
|
14102
|
-
}
|
|
14103
14148
|
function fitVectors(records, available2, unembedded) {
|
|
14104
14149
|
let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
|
|
14105
14150
|
if (total <= available2) return records;
|
|
@@ -15180,6 +15225,45 @@ function createVaultChatBackend(options) {
|
|
|
15180
15225
|
},
|
|
15181
15226
|
flush,
|
|
15182
15227
|
poll,
|
|
15228
|
+
async importChats(chats) {
|
|
15229
|
+
await ready();
|
|
15230
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15231
|
+
const unique = (items) => items.filter(({ record: record2 }) => {
|
|
15232
|
+
const k = key2(record2.kind, record2.id);
|
|
15233
|
+
if (seen.has(k)) return false;
|
|
15234
|
+
seen.add(k);
|
|
15235
|
+
return true;
|
|
15236
|
+
});
|
|
15237
|
+
const valid = chats.filter((c) => validChatId(c.conversation.conversationId));
|
|
15238
|
+
const conversations = unique(
|
|
15239
|
+
valid.map((c) => conversationRecord(c.conversation, c.messages))
|
|
15240
|
+
);
|
|
15241
|
+
const messages = unique(
|
|
15242
|
+
valid.flatMap(
|
|
15243
|
+
(c) => c.messages.filter(
|
|
15244
|
+
(m) => m.conversationId === c.conversation.conversationId && validChatId(m.uniqueId) && Number.isSafeInteger(m.messageId)
|
|
15245
|
+
).map((m) => messageRecord({ ...m, vector: void 0, chunks: void 0 }))
|
|
15246
|
+
)
|
|
15247
|
+
);
|
|
15248
|
+
let conversationCount = 0;
|
|
15249
|
+
let messageCount = 0;
|
|
15250
|
+
try {
|
|
15251
|
+
for (const batch of batches(conversations))
|
|
15252
|
+
conversationCount += await store.importRecords(batch);
|
|
15253
|
+
for (const batch of batches(messages)) messageCount += await store.importRecords(batch);
|
|
15254
|
+
} finally {
|
|
15255
|
+
for (const { record: record2 } of messages) checked.delete(key2("message", record2.id));
|
|
15256
|
+
await refresh(conversations.map(({ record: record2 }) => key2("conversation", record2.id))).catch(
|
|
15257
|
+
() => void 0
|
|
15258
|
+
);
|
|
15259
|
+
for (const { record: record2 } of conversations) threads.delete(record2.id);
|
|
15260
|
+
channel?.postMessage("changed");
|
|
15261
|
+
emit({ type: "conversations", origin: "local" });
|
|
15262
|
+
for (const { record: record2 } of conversations)
|
|
15263
|
+
emit({ type: "messages", conversationId: record2.id, origin: "local" });
|
|
15264
|
+
}
|
|
15265
|
+
return { conversations: conversationCount, messages: messageCount };
|
|
15266
|
+
},
|
|
15183
15267
|
status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
|
|
15184
15268
|
close() {
|
|
15185
15269
|
closed = true;
|
|
@@ -17654,11 +17738,14 @@ var WatermelonChatStorageAdapter = class {
|
|
|
17654
17738
|
return searchChunksOp(this.ctx, queryVector, options);
|
|
17655
17739
|
}
|
|
17656
17740
|
getSummary(conversationId) {
|
|
17657
|
-
return getConversationSummaryOp(
|
|
17741
|
+
return getConversationSummaryOp(
|
|
17742
|
+
createSummaryContext(this.ctx.database, this.ctx),
|
|
17743
|
+
conversationId
|
|
17744
|
+
);
|
|
17658
17745
|
}
|
|
17659
17746
|
upsertSummary(conversationId, summary, summarizedUpTo, tokenCount) {
|
|
17660
17747
|
return upsertConversationSummaryOp(
|
|
17661
|
-
createSummaryContext(this.ctx.database),
|
|
17748
|
+
createSummaryContext(this.ctx.database, this.ctx),
|
|
17662
17749
|
conversationId,
|
|
17663
17750
|
summary,
|
|
17664
17751
|
summarizedUpTo,
|
|
@@ -36017,7 +36104,7 @@ async function summarizeHistoryAtRevision(options, revision2) {
|
|
|
36017
36104
|
const cachedSummary = await summaryStore(options).getSummary(conversationId);
|
|
36018
36105
|
return {
|
|
36019
36106
|
messagesToConvert: messages,
|
|
36020
|
-
summarySystemMessage: cachedSummary?.summary ? summaryToSystemMessage(cachedSummary.summary) : null
|
|
36107
|
+
summarySystemMessage: cachedSummary?.summary && !isEncrypted(cachedSummary.summary) ? summaryToSystemMessage(cachedSummary.summary) : null
|
|
36021
36108
|
};
|
|
36022
36109
|
} catch {
|
|
36023
36110
|
return { messagesToConvert: messages, summarySystemMessage: null };
|
|
@@ -36072,14 +36159,15 @@ async function doSummarizeHistory(options, revision2) {
|
|
|
36072
36159
|
} = options;
|
|
36073
36160
|
try {
|
|
36074
36161
|
const summaries = summaryStore(options);
|
|
36075
|
-
const persistSummary = (summary, summarizedUpTo, tokenCount) =>
|
|
36162
|
+
const persistSummary = (summary, summarizedUpTo, tokenCount) => {
|
|
36076
36163
|
assertConversationRevision(database, conversationId, revision2);
|
|
36077
|
-
|
|
36078
|
-
|
|
36079
|
-
);
|
|
36080
|
-
});
|
|
36164
|
+
return summaries.upsertSummary(conversationId, summary, summarizedUpTo, tokenCount);
|
|
36165
|
+
};
|
|
36081
36166
|
let cachedSummary = await summaries.getSummary(conversationId);
|
|
36082
36167
|
assertConversationRevision(database, conversationId, revision2);
|
|
36168
|
+
if (cachedSummary && isEncrypted(cachedSummary.summary)) {
|
|
36169
|
+
throw new Error("The cached summary could not be decrypted");
|
|
36170
|
+
}
|
|
36083
36171
|
const lastCompacted = lastCompactionTime.get(conversationId) ?? 0;
|
|
36084
36172
|
const compactionCooledDown = Date.now() - lastCompacted > COMPACTION_COOLDOWN_MS;
|
|
36085
36173
|
if (cachedSummary && cachedSummary.tokenCount > summaryTokenThreshold * MAX_SUMMARY_TOKEN_RATIO && compactionCooledDown) {
|