@anuma/sdk 10.1.1 → 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.
@@ -12403,6 +12403,275 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
12403
12403
  });
12404
12404
  }
12405
12405
 
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 ?? {}));
12417
+ }
12418
+ function text4(value) {
12419
+ return typeof value === "string" ? value : void 0;
12420
+ }
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);
12516
+ }
12517
+ return plain({ links: current });
12518
+ }
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
+ }));
12527
+ }
12528
+ function bytes(value) {
12529
+ return new TextEncoder().encode(JSON.stringify(value)).length;
12530
+ }
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);
12540
+ }
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;
12564
+ const out = [];
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
+ }
12576
+ out.push({
12577
+ vector: normalized(mean),
12578
+ startOffset: group[0].startOffset,
12579
+ endOffset: group[group.length - 1].endOffset
12580
+ });
12581
+ }
12582
+ return out;
12583
+ }
12584
+
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;
12592
+ }
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
+ });
12607
+ return {
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
+
12406
12675
  // src/lib/memory/store/remotePersistence.ts
12407
12676
  init_portalLlm();
12408
12677
 
@@ -13145,7 +13414,7 @@ var ChatStoreError = class extends Error {
13145
13414
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
13146
13415
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
13147
13416
  var maxPayload = 2 * 1024 * 1024;
13148
- var storedDims = 1536;
13417
+ var storedDims2 = 1536;
13149
13418
  var maxRequestCiphertext = 8 * 1024 * 1024;
13150
13419
  var maxGetRefs = 50;
13151
13420
  var maxImportRecords = 100;
@@ -13213,24 +13482,24 @@ function vector(v) {
13213
13482
  for (let i = 0; i < v.length; i++) {
13214
13483
  const x = v[i];
13215
13484
  if (typeof x !== "number" || !Number.isFinite(x)) return false;
13216
- if (i < storedDims && x !== 0) nonZero = true;
13485
+ if (i < storedDims2 && x !== 0) nonZero = true;
13217
13486
  }
13218
13487
  return nonZero;
13219
13488
  }
13220
13489
  function vectorFields(write) {
13221
13490
  return {
13222
- ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims)) } : {},
13491
+ ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
13223
13492
  ...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
13224
13493
  };
13225
13494
  }
13226
- function text4(value) {
13495
+ function text5(value) {
13227
13496
  return typeof value === "string";
13228
13497
  }
13229
13498
  function timestamp(value) {
13230
13499
  return typeof value === "string" && Number.isFinite(Date.parse(value));
13231
13500
  }
13232
13501
  function presigned(value) {
13233
- if (!object(value) || !text4(value.url) || !/^https:\/\//.test(value.url) || !text4(value.method) || !object(value.headers) || !Object.values(value.headers).every(text4) || !timestamp(value.expires_at))
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))
13234
13503
  invalid();
13235
13504
  return {
13236
13505
  url: value.url,
@@ -13240,7 +13509,7 @@ function presigned(value) {
13240
13509
  };
13241
13510
  }
13242
13511
  function attachment(value) {
13243
- if (!object(value) || !text4(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))
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))
13244
13513
  invalid();
13245
13514
  return {
13246
13515
  id: value.attachment_id,
@@ -13253,7 +13522,7 @@ function attachment(value) {
13253
13522
  };
13254
13523
  }
13255
13524
  function ref(value) {
13256
- if (!object(value) || !text4(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
13525
+ if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
13257
13526
  return { kind: value.kind, id: value.id };
13258
13527
  }
13259
13528
  function sameMetadata(a, b) {
@@ -13476,7 +13745,7 @@ async function createRemoteChatStore(options) {
13476
13745
  },
13477
13746
  async account(signal) {
13478
13747
  const value = await request("/account", {}, signal);
13479
- if (!object(value) || value.account_id !== accountId || !text4(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 && (!text4(value.changes_cursor) || value.changes_cursor.length > 2048))
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))
13480
13749
  invalid();
13481
13750
  if (value.key_id && value.key_id !== keyId)
13482
13751
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -13551,12 +13820,12 @@ async function createRemoteChatStore(options) {
13551
13820
  },
13552
13821
  async changes(cursor, options2) {
13553
13822
  const limit = options2?.limit ?? 100;
13554
- if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text4(cursor) || cursor.length > 2048))
13823
+ if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
13555
13824
  invalid();
13556
13825
  const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
13557
13826
  if (cursor) params.set("cursor", cursor);
13558
13827
  const value = await request(`/changes?${params}`, {}, options2?.signal);
13559
- if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !text4(value.next_cursor) || value.changes_cursor !== void 0 && !text4(value.changes_cursor))
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))
13560
13829
  invalid();
13561
13830
  const items = [];
13562
13831
  for (const item of value.items) items.push(await decode(item));
@@ -13573,7 +13842,7 @@ async function createRemoteChatStore(options) {
13573
13842
  if (!Array.isArray(embedding2) || !embeddings({
13574
13843
  record: { ...emptyMessage, isDeleted: false },
13575
13844
  embeddings: [embedding2]
13576
- }) || !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 && (!text4(options2.embeddingModel) || options2.embeddingModel.length > 256))
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))
13577
13846
  invalid();
13578
13847
  const value = await request(
13579
13848
  "/search",
@@ -13581,7 +13850,7 @@ async function createRemoteChatStore(options) {
13581
13850
  method: "POST",
13582
13851
  body: JSON.stringify({
13583
13852
  account_id: accountId,
13584
- embedding: embedding2.slice(0, storedDims),
13853
+ embedding: embedding2.slice(0, storedDims2),
13585
13854
  limit,
13586
13855
  ...kindsFilter ? { kinds: kindsFilter } : {},
13587
13856
  ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
@@ -13685,199 +13954,13 @@ var emptyMessage = {
13685
13954
  data: {}
13686
13955
  };
13687
13956
 
13688
- // src/lib/chatStore/vaultRecords.ts
13689
- var PINNED_SORT_BASE = 2 ** 51;
13690
- var recordBudgetBytes = 104e4;
13691
- var storedDims2 = 1536;
13692
- var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
13693
- var maxChunks = 16;
13694
- var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
13695
- var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
13696
- var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
13697
- function plain(value) {
13698
- return JSON.parse(JSON.stringify(value ?? {}));
13699
- }
13700
- function text5(value) {
13701
- return typeof value === "string" ? value : void 0;
13702
- }
13703
- function number(value) {
13704
- return typeof value === "number" ? value : void 0;
13705
- }
13706
- function conversationSortKey(data, createdAt) {
13707
- const pinnedAt = number(data.pinnedAt);
13708
- if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
13709
- return number(data.lastActivityAt) ?? createdAt;
13710
- }
13711
- function toConversation(record2) {
13712
- const pinnedAt = number(record2.data.pinnedAt);
13713
- const projectId = text5(record2.data.projectId);
13714
- return {
13715
- uniqueId: record2.id,
13716
- conversationId: record2.id,
13717
- title: text5(record2.data.title) ?? "",
13718
- ...projectId ? { projectId } : {},
13719
- createdAt: new Date(record2.createdAt),
13720
- updatedAt: new Date(record2.updatedAt),
13721
- isDeleted: record2.isDeleted,
13722
- pinnedAt: pinnedAt ? new Date(pinnedAt) : null
13723
- };
13724
- }
13725
- function messageData(options) {
13726
- return plain(
13727
- Object.fromEntries(
13728
- Object.entries(options).filter(
13729
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
13730
- )
13731
- )
13732
- );
13733
- }
13734
- function toMessage(record2) {
13735
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
13736
- return {
13737
- ...fields,
13738
- uniqueId: record2.id,
13739
- messageId: record2.sortKey,
13740
- conversationId: record2.conversationId,
13741
- createdAt: new Date(record2.createdAt),
13742
- updatedAt: new Date(record2.updatedAt)
13743
- };
13744
- }
13745
- function chunkOffsets(record2) {
13746
- const offsets = record2.data.chunkOffsets;
13747
- return Array.isArray(offsets) ? offsets : void 0;
13748
- }
13749
- function toSkeletons(records) {
13750
- const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
13751
- return records.map((r) => {
13752
- const parentMessageId = text5(r.data.parentMessageId);
13753
- const model = text5(r.data.model);
13754
- const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
13755
- return {
13756
- uniqueId: r.id,
13757
- messageId: r.sortKey,
13758
- conversationId: r.conversationId,
13759
- role: text5(r.data.role) ?? "",
13760
- createdAt: new Date(r.createdAt),
13761
- ...parentMessageId ? { parentMessageId } : {},
13762
- ...model ? { model } : {},
13763
- ...artifact ? { content: text5(r.data.content) ?? "" } : {}
13764
- };
13765
- });
13766
- }
13767
- function toSummary(record2) {
13768
- return {
13769
- uniqueId: record2.id,
13770
- conversationId: record2.id,
13771
- summary: text5(record2.data.summary) ?? "",
13772
- summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
13773
- tokenCount: number(record2.data.tokenCount) ?? 0,
13774
- createdAt: new Date(record2.createdAt),
13775
- updatedAt: new Date(record2.updatedAt)
13776
- };
13777
- }
13778
- function links(data) {
13779
- return Array.isArray(data.links) ? data.links : [];
13780
- }
13781
- function applyLinkOps(data, ops) {
13782
- let current = links(data);
13783
- for (const op of ops) {
13784
- if ("clear" in op) {
13785
- current = [];
13786
- continue;
13787
- }
13788
- const byId = new Map(current.map((l) => [l.memoryId, l]));
13789
- const turn = /* @__PURE__ */ new Set();
13790
- op.add.forEach((item, i) => {
13791
- if (!item.memoryId || turn.has(item.memoryId)) return;
13792
- turn.add(item.memoryId);
13793
- const known = byId.get(item.memoryId);
13794
- if (known && known.createdAt >= op.at + i) return;
13795
- byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
13796
- });
13797
- current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
13798
- }
13799
- return plain({ links: current });
13800
- }
13801
- function toLinks(record2) {
13802
- return links(record2.data).map((l) => ({
13803
- uniqueId: `${record2.id}:${l.memoryId}`,
13804
- conversationId: record2.id,
13805
- memoryId: l.memoryId,
13806
- score: l.score,
13807
- createdAt: new Date(l.createdAt)
13808
- }));
13809
- }
13810
- function bytes(value) {
13811
- return new TextEncoder().encode(JSON.stringify(value)).length;
13812
- }
13813
- function fitRecord(record2) {
13814
- if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
13815
- const data = { ...record2.data };
13816
- const truncated = [];
13817
- for (const field10 of droppable) {
13818
- if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
13819
- if (data[field10] === void 0) continue;
13820
- delete data[field10];
13821
- truncated.push(field10);
13822
- }
13823
- const content = text5(data.content) ?? "";
13824
- const over = bytes({ ...record2, data }) - recordBudgetBytes;
13825
- if (over > 0) {
13826
- const encoded = new TextEncoder().encode(content);
13827
- data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
13828
- truncated.push("content");
13829
- }
13830
- return { ...record2, data: { ...data, truncated } };
13831
- }
13832
- function acceptedVector(vector2) {
13833
- if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
13834
- if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
13835
- return void 0;
13836
- return [...vector2];
13837
- }
13838
- function normalized(vector2) {
13839
- const norm = Math.hypot(...vector2) || 1;
13840
- return vector2.map((x) => x / norm);
13841
- }
13842
- function fitChunks(chunks3) {
13843
- const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
13844
- if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
13845
- if (usable.length <= maxChunks) return usable;
13846
- const out = [];
13847
- for (let g = 0; g < maxChunks; g++) {
13848
- const group = usable.slice(
13849
- Math.floor(g * usable.length / maxChunks),
13850
- Math.floor((g + 1) * usable.length / maxChunks)
13851
- );
13852
- const dims = group[0].vector.length;
13853
- const mean = new Array(dims).fill(0);
13854
- for (const c of group) {
13855
- const unit = normalized(c.vector);
13856
- for (let d = 0; d < dims; d++) mean[d] += unit[d];
13857
- }
13858
- out.push({
13859
- vector: normalized(mean),
13860
- startOffset: group[0].startOffset,
13861
- endOffset: group[group.length - 1].endOffset
13862
- });
13863
- }
13864
- return out;
13865
- }
13866
-
13867
13957
  // src/lib/chatStore/migrateChats.ts
13868
13958
  var maxPasses = 5;
13869
13959
  var verifyBatch = 1e3;
13870
- var importBatch = 100;
13871
- var importChunks = 200;
13872
- var importPlaintextBytes = 39e5;
13873
13960
  var writeBatch = 25;
13874
13961
  function key(record2) {
13875
13962
  return `${record2.kind}/${record2.id}`;
13876
13963
  }
13877
- function ms(date10, fallback = 1) {
13878
- const value = date10?.getTime();
13879
- return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
13880
- }
13881
13964
  function sealed(value) {
13882
13965
  if (typeof value === "string") return isEncrypted(value);
13883
13966
  if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
@@ -13885,42 +13968,6 @@ function sealed(value) {
13885
13968
  return Object.values(value).some(sealed);
13886
13969
  return false;
13887
13970
  }
13888
- function bytes2(value) {
13889
- return new TextEncoder().encode(JSON.stringify(value)).length;
13890
- }
13891
- function messageRecord(message) {
13892
- const {
13893
- uniqueId: _uniqueId,
13894
- messageId: _messageId,
13895
- createdAt: _createdAt,
13896
- updatedAt: _updatedAt,
13897
- decryptionStatus: _status,
13898
- chunks: chunks3,
13899
- vector: vector2,
13900
- ...fields
13901
- } = message;
13902
- const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
13903
- const single = fitted ? void 0 : acceptedVector(vector2);
13904
- const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
13905
- const record2 = fitRecord({
13906
- kind: "message",
13907
- id: message.uniqueId,
13908
- conversationId: message.conversationId,
13909
- sortKey: message.messageId,
13910
- createdAt: ms(message.createdAt),
13911
- updatedAt: ms(message.updatedAt, ms(message.createdAt)),
13912
- isDeleted: false,
13913
- data: {
13914
- ...messageData(fields),
13915
- ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
13916
- }
13917
- });
13918
- return {
13919
- record: record2,
13920
- ...embeddings2 ? { embeddings: embeddings2 } : {},
13921
- ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
13922
- };
13923
- }
13924
13971
  async function readLocal(options) {
13925
13972
  const { database } = options;
13926
13973
  const ctx = {
@@ -13974,29 +14021,10 @@ async function readLocal(options) {
13974
14021
  const messages = await getMessagesOp(ctx, conversationId);
13975
14022
  const unreadableTitle = isEncrypted(conversation.title);
13976
14023
  if (unreadableTitle) out.untitled++;
13977
- const createdAt = ms(conversation.createdAt);
13978
- const data = plain({
13979
- title: unreadableTitle ? "" : conversation.title,
13980
- projectId: conversation.projectId || void 0,
13981
- pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
13982
- lastActivityAt: Math.max(
13983
- ms(conversation.updatedAt, createdAt),
13984
- ...messages.map((m) => ms(m.createdAt))
13985
- )
13986
- });
13987
14024
  out.conversations++;
13988
- out.records.push({
13989
- record: {
13990
- kind: "conversation",
13991
- id: conversationId,
13992
- conversationId: "",
13993
- sortKey: conversationSortKey(data, createdAt),
13994
- createdAt,
13995
- updatedAt: ms(conversation.updatedAt, createdAt),
13996
- isDeleted: false,
13997
- data
13998
- }
13999
- });
14025
+ out.records.push(
14026
+ conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
14027
+ );
14000
14028
  for (const message of messages) {
14001
14029
  if (message.decryptionStatus || sealed(message)) {
14002
14030
  skip("message", message.uniqueId, "unreadable");
@@ -14117,27 +14145,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
14117
14145
  };
14118
14146
  });
14119
14147
  }
14120
- function batches(records) {
14121
- const out = [];
14122
- let batch = [];
14123
- let chunks3 = 0;
14124
- let size = 0;
14125
- for (const item of records) {
14126
- const vectors = item.embeddings?.length ?? 0;
14127
- const itemSize = bytes2(item.record);
14128
- if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
14129
- out.push(batch);
14130
- batch = [];
14131
- chunks3 = 0;
14132
- size = 0;
14133
- }
14134
- batch.push(item);
14135
- chunks3 += vectors;
14136
- size += itemSize;
14137
- }
14138
- if (batch.length) out.push(batch);
14139
- return out;
14140
- }
14141
14148
  function fitVectors(records, available2, unembedded) {
14142
14149
  let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
14143
14150
  if (total <= available2) return records;
@@ -15218,6 +15225,45 @@ function createVaultChatBackend(options) {
15218
15225
  },
15219
15226
  flush,
15220
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
+ },
15221
15267
  status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
15222
15268
  close() {
15223
15269
  closed = true;