@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.
@@ -10546,6 +10546,275 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
10546
10546
  });
10547
10547
  }
10548
10548
 
10549
+ // src/lib/chatStore/vaultRecords.ts
10550
+ var PINNED_SORT_BASE = 2 ** 51;
10551
+ var recordBudgetBytes = 104e4;
10552
+ var storedDims = 1536;
10553
+ var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
10554
+ var maxChunks = 16;
10555
+ var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
10556
+ var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
10557
+ var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
10558
+ function plain(value) {
10559
+ return JSON.parse(JSON.stringify(value ?? {}));
10560
+ }
10561
+ function text4(value) {
10562
+ return typeof value === "string" ? value : void 0;
10563
+ }
10564
+ function number(value) {
10565
+ return typeof value === "number" ? value : void 0;
10566
+ }
10567
+ function conversationSortKey(data, createdAt) {
10568
+ const pinnedAt = number(data.pinnedAt);
10569
+ if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
10570
+ return number(data.lastActivityAt) ?? createdAt;
10571
+ }
10572
+ function toConversation(record2) {
10573
+ const pinnedAt = number(record2.data.pinnedAt);
10574
+ const projectId = text4(record2.data.projectId);
10575
+ return {
10576
+ uniqueId: record2.id,
10577
+ conversationId: record2.id,
10578
+ title: text4(record2.data.title) ?? "",
10579
+ ...projectId ? { projectId } : {},
10580
+ createdAt: new Date(record2.createdAt),
10581
+ updatedAt: new Date(record2.updatedAt),
10582
+ isDeleted: record2.isDeleted,
10583
+ pinnedAt: pinnedAt ? new Date(pinnedAt) : null
10584
+ };
10585
+ }
10586
+ function messageData(options) {
10587
+ return plain(
10588
+ Object.fromEntries(
10589
+ Object.entries(options).filter(
10590
+ ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
10591
+ )
10592
+ )
10593
+ );
10594
+ }
10595
+ function toMessage(record2) {
10596
+ const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
10597
+ return {
10598
+ ...fields,
10599
+ uniqueId: record2.id,
10600
+ messageId: record2.sortKey,
10601
+ conversationId: record2.conversationId,
10602
+ createdAt: new Date(record2.createdAt),
10603
+ updatedAt: new Date(record2.updatedAt)
10604
+ };
10605
+ }
10606
+ function chunkOffsets(record2) {
10607
+ const offsets = record2.data.chunkOffsets;
10608
+ return Array.isArray(offsets) ? offsets : void 0;
10609
+ }
10610
+ function toSkeletons(records) {
10611
+ const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
10612
+ return records.map((r) => {
10613
+ const parentMessageId = text4(r.data.parentMessageId);
10614
+ const model = text4(r.data.model);
10615
+ const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
10616
+ return {
10617
+ uniqueId: r.id,
10618
+ messageId: r.sortKey,
10619
+ conversationId: r.conversationId,
10620
+ role: text4(r.data.role) ?? "",
10621
+ createdAt: new Date(r.createdAt),
10622
+ ...parentMessageId ? { parentMessageId } : {},
10623
+ ...model ? { model } : {},
10624
+ ...artifact ? { content: text4(r.data.content) ?? "" } : {}
10625
+ };
10626
+ });
10627
+ }
10628
+ function toSummary(record2) {
10629
+ return {
10630
+ uniqueId: record2.id,
10631
+ conversationId: record2.id,
10632
+ summary: text4(record2.data.summary) ?? "",
10633
+ summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
10634
+ tokenCount: number(record2.data.tokenCount) ?? 0,
10635
+ createdAt: new Date(record2.createdAt),
10636
+ updatedAt: new Date(record2.updatedAt)
10637
+ };
10638
+ }
10639
+ function links(data) {
10640
+ return Array.isArray(data.links) ? data.links : [];
10641
+ }
10642
+ function applyLinkOps(data, ops) {
10643
+ let current = links(data);
10644
+ for (const op of ops) {
10645
+ if ("clear" in op) {
10646
+ current = [];
10647
+ continue;
10648
+ }
10649
+ const byId = new Map(current.map((l) => [l.memoryId, l]));
10650
+ const turn = /* @__PURE__ */ new Set();
10651
+ op.add.forEach((item, i) => {
10652
+ if (!item.memoryId || turn.has(item.memoryId)) return;
10653
+ turn.add(item.memoryId);
10654
+ const known = byId.get(item.memoryId);
10655
+ if (known && known.createdAt >= op.at + i) return;
10656
+ byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
10657
+ });
10658
+ current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
10659
+ }
10660
+ return plain({ links: current });
10661
+ }
10662
+ function toLinks(record2) {
10663
+ return links(record2.data).map((l) => ({
10664
+ uniqueId: `${record2.id}:${l.memoryId}`,
10665
+ conversationId: record2.id,
10666
+ memoryId: l.memoryId,
10667
+ score: l.score,
10668
+ createdAt: new Date(l.createdAt)
10669
+ }));
10670
+ }
10671
+ function bytes(value) {
10672
+ return new TextEncoder().encode(JSON.stringify(value)).length;
10673
+ }
10674
+ function fitRecord(record2) {
10675
+ if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
10676
+ const data = { ...record2.data };
10677
+ const truncated = [];
10678
+ for (const field10 of droppable) {
10679
+ if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
10680
+ if (data[field10] === void 0) continue;
10681
+ delete data[field10];
10682
+ truncated.push(field10);
10683
+ }
10684
+ const content = text4(data.content) ?? "";
10685
+ const over = bytes({ ...record2, data }) - recordBudgetBytes;
10686
+ if (over > 0) {
10687
+ const encoded = new TextEncoder().encode(content);
10688
+ data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
10689
+ truncated.push("content");
10690
+ }
10691
+ return { ...record2, data: { ...data, truncated } };
10692
+ }
10693
+ function acceptedVector(vector2) {
10694
+ if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
10695
+ if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims).some((x) => x !== 0))
10696
+ return void 0;
10697
+ return [...vector2];
10698
+ }
10699
+ function normalized(vector2) {
10700
+ const norm = Math.hypot(...vector2) || 1;
10701
+ return vector2.map((x) => x / norm);
10702
+ }
10703
+ function fitChunks(chunks3) {
10704
+ const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
10705
+ if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
10706
+ if (usable.length <= maxChunks) return usable;
10707
+ const out = [];
10708
+ for (let g = 0; g < maxChunks; g++) {
10709
+ const group = usable.slice(
10710
+ Math.floor(g * usable.length / maxChunks),
10711
+ Math.floor((g + 1) * usable.length / maxChunks)
10712
+ );
10713
+ const dims = group[0].vector.length;
10714
+ const mean = new Array(dims).fill(0);
10715
+ for (const c of group) {
10716
+ const unit = normalized(c.vector);
10717
+ for (let d = 0; d < dims; d++) mean[d] += unit[d];
10718
+ }
10719
+ out.push({
10720
+ vector: normalized(mean),
10721
+ startOffset: group[0].startOffset,
10722
+ endOffset: group[group.length - 1].endOffset
10723
+ });
10724
+ }
10725
+ return out;
10726
+ }
10727
+
10728
+ // src/lib/chatStore/chatImports.ts
10729
+ var importBatch = 100;
10730
+ var importChunks = 200;
10731
+ var importPlaintextBytes = 39e5;
10732
+ function ms(date10, fallback = 1) {
10733
+ const value = date10?.getTime();
10734
+ return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
10735
+ }
10736
+ function bytes2(value) {
10737
+ return new TextEncoder().encode(JSON.stringify(value)).length;
10738
+ }
10739
+ function conversationRecord(conversation, messages) {
10740
+ const createdAt = ms(conversation.createdAt);
10741
+ const data = plain({
10742
+ title: conversation.title,
10743
+ projectId: conversation.projectId || void 0,
10744
+ pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
10745
+ lastActivityAt: Math.max(
10746
+ ms(conversation.updatedAt, createdAt),
10747
+ ...messages.map((m) => ms(m.createdAt))
10748
+ )
10749
+ });
10750
+ return {
10751
+ record: {
10752
+ kind: "conversation",
10753
+ id: conversation.conversationId,
10754
+ conversationId: "",
10755
+ sortKey: conversationSortKey(data, createdAt),
10756
+ createdAt,
10757
+ updatedAt: ms(conversation.updatedAt, createdAt),
10758
+ isDeleted: false,
10759
+ data
10760
+ }
10761
+ };
10762
+ }
10763
+ function messageRecord(message) {
10764
+ const {
10765
+ uniqueId: _uniqueId,
10766
+ messageId: _messageId,
10767
+ createdAt: _createdAt,
10768
+ updatedAt: _updatedAt,
10769
+ decryptionStatus: _status,
10770
+ chunks: chunks3,
10771
+ vector: vector2,
10772
+ ...fields
10773
+ } = message;
10774
+ const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
10775
+ const single = fitted ? void 0 : acceptedVector(vector2);
10776
+ const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
10777
+ const record2 = fitRecord({
10778
+ kind: "message",
10779
+ id: message.uniqueId,
10780
+ conversationId: message.conversationId,
10781
+ sortKey: message.messageId,
10782
+ createdAt: ms(message.createdAt),
10783
+ updatedAt: ms(message.updatedAt, ms(message.createdAt)),
10784
+ isDeleted: false,
10785
+ data: {
10786
+ ...messageData(fields),
10787
+ ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
10788
+ }
10789
+ });
10790
+ return {
10791
+ record: record2,
10792
+ ...embeddings2 ? { embeddings: embeddings2 } : {},
10793
+ ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
10794
+ };
10795
+ }
10796
+ function batches(records) {
10797
+ const out = [];
10798
+ let batch = [];
10799
+ let chunks3 = 0;
10800
+ let size = 0;
10801
+ for (const item of records) {
10802
+ const vectors = item.embeddings?.length ?? 0;
10803
+ const itemSize = bytes2(item.record);
10804
+ if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
10805
+ out.push(batch);
10806
+ batch = [];
10807
+ chunks3 = 0;
10808
+ size = 0;
10809
+ }
10810
+ batch.push(item);
10811
+ chunks3 += vectors;
10812
+ size += itemSize;
10813
+ }
10814
+ if (batch.length) out.push(batch);
10815
+ return out;
10816
+ }
10817
+
10549
10818
  // src/lib/db/entities/types.ts
10550
10819
  var ENTITY_KINDS = [
10551
10820
  "person",
@@ -11284,7 +11553,7 @@ var ChatStoreError = class extends Error {
11284
11553
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
11285
11554
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
11286
11555
  var maxPayload = 2 * 1024 * 1024;
11287
- var storedDims = 1536;
11556
+ var storedDims2 = 1536;
11288
11557
  var maxRequestCiphertext = 8 * 1024 * 1024;
11289
11558
  var maxGetRefs = 50;
11290
11559
  var maxImportRecords = 100;
@@ -11352,24 +11621,24 @@ function vector(v) {
11352
11621
  for (let i = 0; i < v.length; i++) {
11353
11622
  const x = v[i];
11354
11623
  if (typeof x !== "number" || !Number.isFinite(x)) return false;
11355
- if (i < storedDims && x !== 0) nonZero = true;
11624
+ if (i < storedDims2 && x !== 0) nonZero = true;
11356
11625
  }
11357
11626
  return nonZero;
11358
11627
  }
11359
11628
  function vectorFields(write) {
11360
11629
  return {
11361
- ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims)) } : {},
11630
+ ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
11362
11631
  ...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
11363
11632
  };
11364
11633
  }
11365
- function text4(value) {
11634
+ function text5(value) {
11366
11635
  return typeof value === "string";
11367
11636
  }
11368
11637
  function timestamp(value) {
11369
11638
  return typeof value === "string" && Number.isFinite(Date.parse(value));
11370
11639
  }
11371
11640
  function presigned(value) {
11372
- 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))
11641
+ if (!object(value) || !text5(value.url) || !/^https:\/\//.test(value.url) || !text5(value.method) || !object(value.headers) || !Object.values(value.headers).every(text5) || !timestamp(value.expires_at))
11373
11642
  invalid();
11374
11643
  return {
11375
11644
  url: value.url,
@@ -11379,7 +11648,7 @@ function presigned(value) {
11379
11648
  };
11380
11649
  }
11381
11650
  function attachment(value) {
11382
- 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))
11651
+ if (!object(value) || !text5(value.attachment_id) || !attachmentIdPattern.test(value.attachment_id) || !integer(value.size_bytes, 1) || value.state !== "pending" && value.state !== "committed" || value.owner_kind !== void 0 && value.owner_kind !== "message" && value.owner_kind !== "summary" || value.owner_id !== void 0 && !id(value.owner_id) || !timestamp(value.created_at) || value.committed_at !== void 0 && !timestamp(value.committed_at))
11383
11652
  invalid();
11384
11653
  return {
11385
11654
  id: value.attachment_id,
@@ -11392,7 +11661,7 @@ function attachment(value) {
11392
11661
  };
11393
11662
  }
11394
11663
  function ref(value) {
11395
- if (!object(value) || !text4(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
11664
+ if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
11396
11665
  return { kind: value.kind, id: value.id };
11397
11666
  }
11398
11667
  function sameMetadata(a, b) {
@@ -11615,7 +11884,7 @@ async function createRemoteChatStore(options) {
11615
11884
  },
11616
11885
  async account(signal) {
11617
11886
  const value = await request("/account", {}, signal);
11618
- 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))
11887
+ if (!object(value) || value.account_id !== accountId || !text5(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count) || value.changes_cursor !== void 0 && (!text5(value.changes_cursor) || value.changes_cursor.length > 2048))
11619
11888
  invalid();
11620
11889
  if (value.key_id && value.key_id !== keyId)
11621
11890
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -11690,12 +11959,12 @@ async function createRemoteChatStore(options) {
11690
11959
  },
11691
11960
  async changes(cursor, options2) {
11692
11961
  const limit = options2?.limit ?? 100;
11693
- if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text4(cursor) || cursor.length > 2048))
11962
+ if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
11694
11963
  invalid();
11695
11964
  const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
11696
11965
  if (cursor) params.set("cursor", cursor);
11697
11966
  const value = await request(`/changes?${params}`, {}, options2?.signal);
11698
- 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))
11967
+ if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !text5(value.next_cursor) || value.changes_cursor !== void 0 && !text5(value.changes_cursor))
11699
11968
  invalid();
11700
11969
  const items = [];
11701
11970
  for (const item of value.items) items.push(await decode(item));
@@ -11712,7 +11981,7 @@ async function createRemoteChatStore(options) {
11712
11981
  if (!Array.isArray(embedding2) || !embeddings({
11713
11982
  record: { ...emptyMessage, isDeleted: false },
11714
11983
  embeddings: [embedding2]
11715
- }) || !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))
11984
+ }) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!text5(options2.embeddingModel) || options2.embeddingModel.length > 256))
11716
11985
  invalid();
11717
11986
  const value = await request(
11718
11987
  "/search",
@@ -11720,7 +11989,7 @@ async function createRemoteChatStore(options) {
11720
11989
  method: "POST",
11721
11990
  body: JSON.stringify({
11722
11991
  account_id: accountId,
11723
- embedding: embedding2.slice(0, storedDims),
11992
+ embedding: embedding2.slice(0, storedDims2),
11724
11993
  limit,
11725
11994
  ...kindsFilter ? { kinds: kindsFilter } : {},
11726
11995
  ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
@@ -11824,199 +12093,13 @@ var emptyMessage = {
11824
12093
  data: {}
11825
12094
  };
11826
12095
 
11827
- // src/lib/chatStore/vaultRecords.ts
11828
- var PINNED_SORT_BASE = 2 ** 51;
11829
- var recordBudgetBytes = 104e4;
11830
- var storedDims2 = 1536;
11831
- var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
11832
- var maxChunks = 16;
11833
- var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
11834
- var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
11835
- var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
11836
- function plain(value) {
11837
- return JSON.parse(JSON.stringify(value ?? {}));
11838
- }
11839
- function text5(value) {
11840
- return typeof value === "string" ? value : void 0;
11841
- }
11842
- function number(value) {
11843
- return typeof value === "number" ? value : void 0;
11844
- }
11845
- function conversationSortKey(data, createdAt) {
11846
- const pinnedAt = number(data.pinnedAt);
11847
- if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
11848
- return number(data.lastActivityAt) ?? createdAt;
11849
- }
11850
- function toConversation(record2) {
11851
- const pinnedAt = number(record2.data.pinnedAt);
11852
- const projectId = text5(record2.data.projectId);
11853
- return {
11854
- uniqueId: record2.id,
11855
- conversationId: record2.id,
11856
- title: text5(record2.data.title) ?? "",
11857
- ...projectId ? { projectId } : {},
11858
- createdAt: new Date(record2.createdAt),
11859
- updatedAt: new Date(record2.updatedAt),
11860
- isDeleted: record2.isDeleted,
11861
- pinnedAt: pinnedAt ? new Date(pinnedAt) : null
11862
- };
11863
- }
11864
- function messageData(options) {
11865
- return plain(
11866
- Object.fromEntries(
11867
- Object.entries(options).filter(
11868
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
11869
- )
11870
- )
11871
- );
11872
- }
11873
- function toMessage(record2) {
11874
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
11875
- return {
11876
- ...fields,
11877
- uniqueId: record2.id,
11878
- messageId: record2.sortKey,
11879
- conversationId: record2.conversationId,
11880
- createdAt: new Date(record2.createdAt),
11881
- updatedAt: new Date(record2.updatedAt)
11882
- };
11883
- }
11884
- function chunkOffsets(record2) {
11885
- const offsets = record2.data.chunkOffsets;
11886
- return Array.isArray(offsets) ? offsets : void 0;
11887
- }
11888
- function toSkeletons(records) {
11889
- const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
11890
- return records.map((r) => {
11891
- const parentMessageId = text5(r.data.parentMessageId);
11892
- const model = text5(r.data.model);
11893
- const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
11894
- return {
11895
- uniqueId: r.id,
11896
- messageId: r.sortKey,
11897
- conversationId: r.conversationId,
11898
- role: text5(r.data.role) ?? "",
11899
- createdAt: new Date(r.createdAt),
11900
- ...parentMessageId ? { parentMessageId } : {},
11901
- ...model ? { model } : {},
11902
- ...artifact ? { content: text5(r.data.content) ?? "" } : {}
11903
- };
11904
- });
11905
- }
11906
- function toSummary(record2) {
11907
- return {
11908
- uniqueId: record2.id,
11909
- conversationId: record2.id,
11910
- summary: text5(record2.data.summary) ?? "",
11911
- summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
11912
- tokenCount: number(record2.data.tokenCount) ?? 0,
11913
- createdAt: new Date(record2.createdAt),
11914
- updatedAt: new Date(record2.updatedAt)
11915
- };
11916
- }
11917
- function links(data) {
11918
- return Array.isArray(data.links) ? data.links : [];
11919
- }
11920
- function applyLinkOps(data, ops) {
11921
- let current = links(data);
11922
- for (const op of ops) {
11923
- if ("clear" in op) {
11924
- current = [];
11925
- continue;
11926
- }
11927
- const byId = new Map(current.map((l) => [l.memoryId, l]));
11928
- const turn = /* @__PURE__ */ new Set();
11929
- op.add.forEach((item, i) => {
11930
- if (!item.memoryId || turn.has(item.memoryId)) return;
11931
- turn.add(item.memoryId);
11932
- const known = byId.get(item.memoryId);
11933
- if (known && known.createdAt >= op.at + i) return;
11934
- byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
11935
- });
11936
- current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
11937
- }
11938
- return plain({ links: current });
11939
- }
11940
- function toLinks(record2) {
11941
- return links(record2.data).map((l) => ({
11942
- uniqueId: `${record2.id}:${l.memoryId}`,
11943
- conversationId: record2.id,
11944
- memoryId: l.memoryId,
11945
- score: l.score,
11946
- createdAt: new Date(l.createdAt)
11947
- }));
11948
- }
11949
- function bytes(value) {
11950
- return new TextEncoder().encode(JSON.stringify(value)).length;
11951
- }
11952
- function fitRecord(record2) {
11953
- if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
11954
- const data = { ...record2.data };
11955
- const truncated = [];
11956
- for (const field10 of droppable) {
11957
- if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
11958
- if (data[field10] === void 0) continue;
11959
- delete data[field10];
11960
- truncated.push(field10);
11961
- }
11962
- const content = text5(data.content) ?? "";
11963
- const over = bytes({ ...record2, data }) - recordBudgetBytes;
11964
- if (over > 0) {
11965
- const encoded = new TextEncoder().encode(content);
11966
- data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
11967
- truncated.push("content");
11968
- }
11969
- return { ...record2, data: { ...data, truncated } };
11970
- }
11971
- function acceptedVector(vector2) {
11972
- if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
11973
- if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
11974
- return void 0;
11975
- return [...vector2];
11976
- }
11977
- function normalized(vector2) {
11978
- const norm = Math.hypot(...vector2) || 1;
11979
- return vector2.map((x) => x / norm);
11980
- }
11981
- function fitChunks(chunks3) {
11982
- const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
11983
- if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
11984
- if (usable.length <= maxChunks) return usable;
11985
- const out = [];
11986
- for (let g = 0; g < maxChunks; g++) {
11987
- const group = usable.slice(
11988
- Math.floor(g * usable.length / maxChunks),
11989
- Math.floor((g + 1) * usable.length / maxChunks)
11990
- );
11991
- const dims = group[0].vector.length;
11992
- const mean = new Array(dims).fill(0);
11993
- for (const c of group) {
11994
- const unit = normalized(c.vector);
11995
- for (let d = 0; d < dims; d++) mean[d] += unit[d];
11996
- }
11997
- out.push({
11998
- vector: normalized(mean),
11999
- startOffset: group[0].startOffset,
12000
- endOffset: group[group.length - 1].endOffset
12001
- });
12002
- }
12003
- return out;
12004
- }
12005
-
12006
12096
  // src/lib/chatStore/migrateChats.ts
12007
12097
  var maxPasses = 5;
12008
12098
  var verifyBatch = 1e3;
12009
- var importBatch = 100;
12010
- var importChunks = 200;
12011
- var importPlaintextBytes = 39e5;
12012
12099
  var writeBatch = 25;
12013
12100
  function key(record2) {
12014
12101
  return `${record2.kind}/${record2.id}`;
12015
12102
  }
12016
- function ms(date10, fallback = 1) {
12017
- const value = date10?.getTime();
12018
- return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
12019
- }
12020
12103
  function sealed(value) {
12021
12104
  if (typeof value === "string") return isEncrypted(value);
12022
12105
  if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
@@ -12024,42 +12107,6 @@ function sealed(value) {
12024
12107
  return Object.values(value).some(sealed);
12025
12108
  return false;
12026
12109
  }
12027
- function bytes2(value) {
12028
- return new TextEncoder().encode(JSON.stringify(value)).length;
12029
- }
12030
- function messageRecord(message) {
12031
- const {
12032
- uniqueId: _uniqueId,
12033
- messageId: _messageId,
12034
- createdAt: _createdAt,
12035
- updatedAt: _updatedAt,
12036
- decryptionStatus: _status,
12037
- chunks: chunks3,
12038
- vector: vector2,
12039
- ...fields
12040
- } = message;
12041
- const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
12042
- const single = fitted ? void 0 : acceptedVector(vector2);
12043
- const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
12044
- const record2 = fitRecord({
12045
- kind: "message",
12046
- id: message.uniqueId,
12047
- conversationId: message.conversationId,
12048
- sortKey: message.messageId,
12049
- createdAt: ms(message.createdAt),
12050
- updatedAt: ms(message.updatedAt, ms(message.createdAt)),
12051
- isDeleted: false,
12052
- data: {
12053
- ...messageData(fields),
12054
- ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
12055
- }
12056
- });
12057
- return {
12058
- record: record2,
12059
- ...embeddings2 ? { embeddings: embeddings2 } : {},
12060
- ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
12061
- };
12062
- }
12063
12110
  async function readLocal(options) {
12064
12111
  const { database } = options;
12065
12112
  const ctx = {
@@ -12113,29 +12160,10 @@ async function readLocal(options) {
12113
12160
  const messages = await getMessagesOp(ctx, conversationId);
12114
12161
  const unreadableTitle = isEncrypted(conversation.title);
12115
12162
  if (unreadableTitle) out.untitled++;
12116
- const createdAt = ms(conversation.createdAt);
12117
- const data = plain({
12118
- title: unreadableTitle ? "" : conversation.title,
12119
- projectId: conversation.projectId || void 0,
12120
- pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
12121
- lastActivityAt: Math.max(
12122
- ms(conversation.updatedAt, createdAt),
12123
- ...messages.map((m) => ms(m.createdAt))
12124
- )
12125
- });
12126
12163
  out.conversations++;
12127
- out.records.push({
12128
- record: {
12129
- kind: "conversation",
12130
- id: conversationId,
12131
- conversationId: "",
12132
- sortKey: conversationSortKey(data, createdAt),
12133
- createdAt,
12134
- updatedAt: ms(conversation.updatedAt, createdAt),
12135
- isDeleted: false,
12136
- data
12137
- }
12138
- });
12164
+ out.records.push(
12165
+ conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
12166
+ );
12139
12167
  for (const message of messages) {
12140
12168
  if (message.decryptionStatus || sealed(message)) {
12141
12169
  skip("message", message.uniqueId, "unreadable");
@@ -12256,27 +12284,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
12256
12284
  };
12257
12285
  });
12258
12286
  }
12259
- function batches(records) {
12260
- const out = [];
12261
- let batch = [];
12262
- let chunks3 = 0;
12263
- let size = 0;
12264
- for (const item of records) {
12265
- const vectors = item.embeddings?.length ?? 0;
12266
- const itemSize = bytes2(item.record);
12267
- if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
12268
- out.push(batch);
12269
- batch = [];
12270
- chunks3 = 0;
12271
- size = 0;
12272
- }
12273
- batch.push(item);
12274
- chunks3 += vectors;
12275
- size += itemSize;
12276
- }
12277
- if (batch.length) out.push(batch);
12278
- return out;
12279
- }
12280
12287
  function fitVectors(records, available2, unembedded) {
12281
12288
  let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
12282
12289
  if (total <= available2) return records;
@@ -13357,6 +13364,45 @@ function createVaultChatBackend(options) {
13357
13364
  },
13358
13365
  flush,
13359
13366
  poll,
13367
+ async importChats(chats) {
13368
+ await ready();
13369
+ const seen = /* @__PURE__ */ new Set();
13370
+ const unique = (items) => items.filter(({ record: record2 }) => {
13371
+ const k = key2(record2.kind, record2.id);
13372
+ if (seen.has(k)) return false;
13373
+ seen.add(k);
13374
+ return true;
13375
+ });
13376
+ const valid = chats.filter((c) => validChatId(c.conversation.conversationId));
13377
+ const conversations = unique(
13378
+ valid.map((c) => conversationRecord(c.conversation, c.messages))
13379
+ );
13380
+ const messages = unique(
13381
+ valid.flatMap(
13382
+ (c) => c.messages.filter(
13383
+ (m) => m.conversationId === c.conversation.conversationId && validChatId(m.uniqueId) && Number.isSafeInteger(m.messageId)
13384
+ ).map((m) => messageRecord({ ...m, vector: void 0, chunks: void 0 }))
13385
+ )
13386
+ );
13387
+ let conversationCount = 0;
13388
+ let messageCount = 0;
13389
+ try {
13390
+ for (const batch of batches(conversations))
13391
+ conversationCount += await store.importRecords(batch);
13392
+ for (const batch of batches(messages)) messageCount += await store.importRecords(batch);
13393
+ } finally {
13394
+ for (const { record: record2 } of messages) checked.delete(key2("message", record2.id));
13395
+ await refresh(conversations.map(({ record: record2 }) => key2("conversation", record2.id))).catch(
13396
+ () => void 0
13397
+ );
13398
+ for (const { record: record2 } of conversations) threads.delete(record2.id);
13399
+ channel?.postMessage("changed");
13400
+ emit({ type: "conversations", origin: "local" });
13401
+ for (const { record: record2 } of conversations)
13402
+ emit({ type: "messages", conversationId: record2.id, origin: "local" });
13403
+ }
13404
+ return { conversations: conversationCount, messages: messageCount };
13405
+ },
13360
13406
  status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
13361
13407
  close() {
13362
13408
  closed = true;