@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.
@@ -11633,6 +11633,275 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
11633
11633
  });
11634
11634
  }
11635
11635
 
11636
+ // src/lib/chatStore/vaultRecords.ts
11637
+ var PINNED_SORT_BASE = 2 ** 51;
11638
+ var recordBudgetBytes = 104e4;
11639
+ var storedDims = 1536;
11640
+ var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
11641
+ var maxChunks = 16;
11642
+ var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
11643
+ var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
11644
+ var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
11645
+ function plain(value) {
11646
+ return JSON.parse(JSON.stringify(value ?? {}));
11647
+ }
11648
+ function text4(value) {
11649
+ return typeof value === "string" ? value : void 0;
11650
+ }
11651
+ function number(value) {
11652
+ return typeof value === "number" ? value : void 0;
11653
+ }
11654
+ function conversationSortKey(data, createdAt) {
11655
+ const pinnedAt = number(data.pinnedAt);
11656
+ if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
11657
+ return number(data.lastActivityAt) ?? createdAt;
11658
+ }
11659
+ function toConversation(record2) {
11660
+ const pinnedAt = number(record2.data.pinnedAt);
11661
+ const projectId = text4(record2.data.projectId);
11662
+ return {
11663
+ uniqueId: record2.id,
11664
+ conversationId: record2.id,
11665
+ title: text4(record2.data.title) ?? "",
11666
+ ...projectId ? { projectId } : {},
11667
+ createdAt: new Date(record2.createdAt),
11668
+ updatedAt: new Date(record2.updatedAt),
11669
+ isDeleted: record2.isDeleted,
11670
+ pinnedAt: pinnedAt ? new Date(pinnedAt) : null
11671
+ };
11672
+ }
11673
+ function messageData(options) {
11674
+ return plain(
11675
+ Object.fromEntries(
11676
+ Object.entries(options).filter(
11677
+ ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
11678
+ )
11679
+ )
11680
+ );
11681
+ }
11682
+ function toMessage(record2) {
11683
+ const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
11684
+ return {
11685
+ ...fields,
11686
+ uniqueId: record2.id,
11687
+ messageId: record2.sortKey,
11688
+ conversationId: record2.conversationId,
11689
+ createdAt: new Date(record2.createdAt),
11690
+ updatedAt: new Date(record2.updatedAt)
11691
+ };
11692
+ }
11693
+ function chunkOffsets(record2) {
11694
+ const offsets = record2.data.chunkOffsets;
11695
+ return Array.isArray(offsets) ? offsets : void 0;
11696
+ }
11697
+ function toSkeletons(records) {
11698
+ const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
11699
+ return records.map((r) => {
11700
+ const parentMessageId = text4(r.data.parentMessageId);
11701
+ const model = text4(r.data.model);
11702
+ const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
11703
+ return {
11704
+ uniqueId: r.id,
11705
+ messageId: r.sortKey,
11706
+ conversationId: r.conversationId,
11707
+ role: text4(r.data.role) ?? "",
11708
+ createdAt: new Date(r.createdAt),
11709
+ ...parentMessageId ? { parentMessageId } : {},
11710
+ ...model ? { model } : {},
11711
+ ...artifact ? { content: text4(r.data.content) ?? "" } : {}
11712
+ };
11713
+ });
11714
+ }
11715
+ function toSummary(record2) {
11716
+ return {
11717
+ uniqueId: record2.id,
11718
+ conversationId: record2.id,
11719
+ summary: text4(record2.data.summary) ?? "",
11720
+ summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
11721
+ tokenCount: number(record2.data.tokenCount) ?? 0,
11722
+ createdAt: new Date(record2.createdAt),
11723
+ updatedAt: new Date(record2.updatedAt)
11724
+ };
11725
+ }
11726
+ function links(data) {
11727
+ return Array.isArray(data.links) ? data.links : [];
11728
+ }
11729
+ function applyLinkOps(data, ops) {
11730
+ let current = links(data);
11731
+ for (const op of ops) {
11732
+ if ("clear" in op) {
11733
+ current = [];
11734
+ continue;
11735
+ }
11736
+ const byId = new Map(current.map((l) => [l.memoryId, l]));
11737
+ const turn = /* @__PURE__ */ new Set();
11738
+ op.add.forEach((item, i) => {
11739
+ if (!item.memoryId || turn.has(item.memoryId)) return;
11740
+ turn.add(item.memoryId);
11741
+ const known = byId.get(item.memoryId);
11742
+ if (known && known.createdAt >= op.at + i) return;
11743
+ byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
11744
+ });
11745
+ current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
11746
+ }
11747
+ return plain({ links: current });
11748
+ }
11749
+ function toLinks(record2) {
11750
+ return links(record2.data).map((l) => ({
11751
+ uniqueId: `${record2.id}:${l.memoryId}`,
11752
+ conversationId: record2.id,
11753
+ memoryId: l.memoryId,
11754
+ score: l.score,
11755
+ createdAt: new Date(l.createdAt)
11756
+ }));
11757
+ }
11758
+ function bytes(value) {
11759
+ return new TextEncoder().encode(JSON.stringify(value)).length;
11760
+ }
11761
+ function fitRecord(record2) {
11762
+ if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
11763
+ const data = { ...record2.data };
11764
+ const truncated = [];
11765
+ for (const field10 of droppable) {
11766
+ if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
11767
+ if (data[field10] === void 0) continue;
11768
+ delete data[field10];
11769
+ truncated.push(field10);
11770
+ }
11771
+ const content = text4(data.content) ?? "";
11772
+ const over = bytes({ ...record2, data }) - recordBudgetBytes;
11773
+ if (over > 0) {
11774
+ const encoded = new TextEncoder().encode(content);
11775
+ data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
11776
+ truncated.push("content");
11777
+ }
11778
+ return { ...record2, data: { ...data, truncated } };
11779
+ }
11780
+ function acceptedVector(vector2) {
11781
+ if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
11782
+ if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims).some((x) => x !== 0))
11783
+ return void 0;
11784
+ return [...vector2];
11785
+ }
11786
+ function normalized(vector2) {
11787
+ const norm = Math.hypot(...vector2) || 1;
11788
+ return vector2.map((x) => x / norm);
11789
+ }
11790
+ function fitChunks(chunks3) {
11791
+ const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
11792
+ if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
11793
+ if (usable.length <= maxChunks) return usable;
11794
+ const out = [];
11795
+ for (let g = 0; g < maxChunks; g++) {
11796
+ const group = usable.slice(
11797
+ Math.floor(g * usable.length / maxChunks),
11798
+ Math.floor((g + 1) * usable.length / maxChunks)
11799
+ );
11800
+ const dims = group[0].vector.length;
11801
+ const mean = new Array(dims).fill(0);
11802
+ for (const c of group) {
11803
+ const unit = normalized(c.vector);
11804
+ for (let d = 0; d < dims; d++) mean[d] += unit[d];
11805
+ }
11806
+ out.push({
11807
+ vector: normalized(mean),
11808
+ startOffset: group[0].startOffset,
11809
+ endOffset: group[group.length - 1].endOffset
11810
+ });
11811
+ }
11812
+ return out;
11813
+ }
11814
+
11815
+ // src/lib/chatStore/chatImports.ts
11816
+ var importBatch = 100;
11817
+ var importChunks = 200;
11818
+ var importPlaintextBytes = 39e5;
11819
+ function ms(date10, fallback = 1) {
11820
+ const value = date10?.getTime();
11821
+ return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
11822
+ }
11823
+ function bytes2(value) {
11824
+ return new TextEncoder().encode(JSON.stringify(value)).length;
11825
+ }
11826
+ function conversationRecord(conversation, messages) {
11827
+ const createdAt = ms(conversation.createdAt);
11828
+ const data = plain({
11829
+ title: conversation.title,
11830
+ projectId: conversation.projectId || void 0,
11831
+ pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
11832
+ lastActivityAt: Math.max(
11833
+ ms(conversation.updatedAt, createdAt),
11834
+ ...messages.map((m) => ms(m.createdAt))
11835
+ )
11836
+ });
11837
+ return {
11838
+ record: {
11839
+ kind: "conversation",
11840
+ id: conversation.conversationId,
11841
+ conversationId: "",
11842
+ sortKey: conversationSortKey(data, createdAt),
11843
+ createdAt,
11844
+ updatedAt: ms(conversation.updatedAt, createdAt),
11845
+ isDeleted: false,
11846
+ data
11847
+ }
11848
+ };
11849
+ }
11850
+ function messageRecord(message) {
11851
+ const {
11852
+ uniqueId: _uniqueId,
11853
+ messageId: _messageId,
11854
+ createdAt: _createdAt,
11855
+ updatedAt: _updatedAt,
11856
+ decryptionStatus: _status,
11857
+ chunks: chunks3,
11858
+ vector: vector2,
11859
+ ...fields
11860
+ } = message;
11861
+ const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
11862
+ const single = fitted ? void 0 : acceptedVector(vector2);
11863
+ const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
11864
+ const record2 = fitRecord({
11865
+ kind: "message",
11866
+ id: message.uniqueId,
11867
+ conversationId: message.conversationId,
11868
+ sortKey: message.messageId,
11869
+ createdAt: ms(message.createdAt),
11870
+ updatedAt: ms(message.updatedAt, ms(message.createdAt)),
11871
+ isDeleted: false,
11872
+ data: {
11873
+ ...messageData(fields),
11874
+ ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
11875
+ }
11876
+ });
11877
+ return {
11878
+ record: record2,
11879
+ ...embeddings2 ? { embeddings: embeddings2 } : {},
11880
+ ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
11881
+ };
11882
+ }
11883
+ function batches(records) {
11884
+ const out = [];
11885
+ let batch = [];
11886
+ let chunks3 = 0;
11887
+ let size = 0;
11888
+ for (const item of records) {
11889
+ const vectors = item.embeddings?.length ?? 0;
11890
+ const itemSize = bytes2(item.record);
11891
+ if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
11892
+ out.push(batch);
11893
+ batch = [];
11894
+ chunks3 = 0;
11895
+ size = 0;
11896
+ }
11897
+ batch.push(item);
11898
+ chunks3 += vectors;
11899
+ size += itemSize;
11900
+ }
11901
+ if (batch.length) out.push(batch);
11902
+ return out;
11903
+ }
11904
+
11636
11905
  // src/lib/memory/store/remotePersistence.ts
11637
11906
  init_portalLlm();
11638
11907
 
@@ -12375,7 +12644,7 @@ var ChatStoreError = class extends Error {
12375
12644
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
12376
12645
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
12377
12646
  var maxPayload = 2 * 1024 * 1024;
12378
- var storedDims = 1536;
12647
+ var storedDims2 = 1536;
12379
12648
  var maxRequestCiphertext = 8 * 1024 * 1024;
12380
12649
  var maxGetRefs = 50;
12381
12650
  var maxImportRecords = 100;
@@ -12443,24 +12712,24 @@ function vector(v) {
12443
12712
  for (let i = 0; i < v.length; i++) {
12444
12713
  const x = v[i];
12445
12714
  if (typeof x !== "number" || !Number.isFinite(x)) return false;
12446
- if (i < storedDims && x !== 0) nonZero = true;
12715
+ if (i < storedDims2 && x !== 0) nonZero = true;
12447
12716
  }
12448
12717
  return nonZero;
12449
12718
  }
12450
12719
  function vectorFields(write) {
12451
12720
  return {
12452
- ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims)) } : {},
12721
+ ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
12453
12722
  ...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
12454
12723
  };
12455
12724
  }
12456
- function text4(value) {
12725
+ function text5(value) {
12457
12726
  return typeof value === "string";
12458
12727
  }
12459
12728
  function timestamp(value) {
12460
12729
  return typeof value === "string" && Number.isFinite(Date.parse(value));
12461
12730
  }
12462
12731
  function presigned(value) {
12463
- 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))
12732
+ if (!object(value) || !text5(value.url) || !/^https:\/\//.test(value.url) || !text5(value.method) || !object(value.headers) || !Object.values(value.headers).every(text5) || !timestamp(value.expires_at))
12464
12733
  invalid();
12465
12734
  return {
12466
12735
  url: value.url,
@@ -12470,7 +12739,7 @@ function presigned(value) {
12470
12739
  };
12471
12740
  }
12472
12741
  function attachment(value) {
12473
- 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))
12742
+ if (!object(value) || !text5(value.attachment_id) || !attachmentIdPattern.test(value.attachment_id) || !integer(value.size_bytes, 1) || value.state !== "pending" && value.state !== "committed" || value.owner_kind !== void 0 && value.owner_kind !== "message" && value.owner_kind !== "summary" || value.owner_id !== void 0 && !id(value.owner_id) || !timestamp(value.created_at) || value.committed_at !== void 0 && !timestamp(value.committed_at))
12474
12743
  invalid();
12475
12744
  return {
12476
12745
  id: value.attachment_id,
@@ -12483,7 +12752,7 @@ function attachment(value) {
12483
12752
  };
12484
12753
  }
12485
12754
  function ref(value) {
12486
- if (!object(value) || !text4(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
12755
+ if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
12487
12756
  return { kind: value.kind, id: value.id };
12488
12757
  }
12489
12758
  function sameMetadata(a, b) {
@@ -12706,7 +12975,7 @@ async function createRemoteChatStore(options) {
12706
12975
  },
12707
12976
  async account(signal) {
12708
12977
  const value = await request("/account", {}, signal);
12709
- 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))
12978
+ if (!object(value) || value.account_id !== accountId || !text5(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count) || value.changes_cursor !== void 0 && (!text5(value.changes_cursor) || value.changes_cursor.length > 2048))
12710
12979
  invalid();
12711
12980
  if (value.key_id && value.key_id !== keyId)
12712
12981
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -12781,12 +13050,12 @@ async function createRemoteChatStore(options) {
12781
13050
  },
12782
13051
  async changes(cursor, options2) {
12783
13052
  const limit = options2?.limit ?? 100;
12784
- if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text4(cursor) || cursor.length > 2048))
13053
+ if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
12785
13054
  invalid();
12786
13055
  const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
12787
13056
  if (cursor) params.set("cursor", cursor);
12788
13057
  const value = await request(`/changes?${params}`, {}, options2?.signal);
12789
- 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))
13058
+ if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !text5(value.next_cursor) || value.changes_cursor !== void 0 && !text5(value.changes_cursor))
12790
13059
  invalid();
12791
13060
  const items = [];
12792
13061
  for (const item of value.items) items.push(await decode(item));
@@ -12803,7 +13072,7 @@ async function createRemoteChatStore(options) {
12803
13072
  if (!Array.isArray(embedding2) || !embeddings({
12804
13073
  record: { ...emptyMessage, isDeleted: false },
12805
13074
  embeddings: [embedding2]
12806
- }) || !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))
13075
+ }) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!text5(options2.embeddingModel) || options2.embeddingModel.length > 256))
12807
13076
  invalid();
12808
13077
  const value = await request(
12809
13078
  "/search",
@@ -12811,7 +13080,7 @@ async function createRemoteChatStore(options) {
12811
13080
  method: "POST",
12812
13081
  body: JSON.stringify({
12813
13082
  account_id: accountId,
12814
- embedding: embedding2.slice(0, storedDims),
13083
+ embedding: embedding2.slice(0, storedDims2),
12815
13084
  limit,
12816
13085
  ...kindsFilter ? { kinds: kindsFilter } : {},
12817
13086
  ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
@@ -12915,199 +13184,13 @@ var emptyMessage = {
12915
13184
  data: {}
12916
13185
  };
12917
13186
 
12918
- // src/lib/chatStore/vaultRecords.ts
12919
- var PINNED_SORT_BASE = 2 ** 51;
12920
- var recordBudgetBytes = 104e4;
12921
- var storedDims2 = 1536;
12922
- var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
12923
- var maxChunks = 16;
12924
- var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
12925
- var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
12926
- var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
12927
- function plain(value) {
12928
- return JSON.parse(JSON.stringify(value ?? {}));
12929
- }
12930
- function text5(value) {
12931
- return typeof value === "string" ? value : void 0;
12932
- }
12933
- function number(value) {
12934
- return typeof value === "number" ? value : void 0;
12935
- }
12936
- function conversationSortKey(data, createdAt) {
12937
- const pinnedAt = number(data.pinnedAt);
12938
- if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
12939
- return number(data.lastActivityAt) ?? createdAt;
12940
- }
12941
- function toConversation(record2) {
12942
- const pinnedAt = number(record2.data.pinnedAt);
12943
- const projectId = text5(record2.data.projectId);
12944
- return {
12945
- uniqueId: record2.id,
12946
- conversationId: record2.id,
12947
- title: text5(record2.data.title) ?? "",
12948
- ...projectId ? { projectId } : {},
12949
- createdAt: new Date(record2.createdAt),
12950
- updatedAt: new Date(record2.updatedAt),
12951
- isDeleted: record2.isDeleted,
12952
- pinnedAt: pinnedAt ? new Date(pinnedAt) : null
12953
- };
12954
- }
12955
- function messageData(options) {
12956
- return plain(
12957
- Object.fromEntries(
12958
- Object.entries(options).filter(
12959
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
12960
- )
12961
- )
12962
- );
12963
- }
12964
- function toMessage(record2) {
12965
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
12966
- return {
12967
- ...fields,
12968
- uniqueId: record2.id,
12969
- messageId: record2.sortKey,
12970
- conversationId: record2.conversationId,
12971
- createdAt: new Date(record2.createdAt),
12972
- updatedAt: new Date(record2.updatedAt)
12973
- };
12974
- }
12975
- function chunkOffsets(record2) {
12976
- const offsets = record2.data.chunkOffsets;
12977
- return Array.isArray(offsets) ? offsets : void 0;
12978
- }
12979
- function toSkeletons(records) {
12980
- const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
12981
- return records.map((r) => {
12982
- const parentMessageId = text5(r.data.parentMessageId);
12983
- const model = text5(r.data.model);
12984
- const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
12985
- return {
12986
- uniqueId: r.id,
12987
- messageId: r.sortKey,
12988
- conversationId: r.conversationId,
12989
- role: text5(r.data.role) ?? "",
12990
- createdAt: new Date(r.createdAt),
12991
- ...parentMessageId ? { parentMessageId } : {},
12992
- ...model ? { model } : {},
12993
- ...artifact ? { content: text5(r.data.content) ?? "" } : {}
12994
- };
12995
- });
12996
- }
12997
- function toSummary(record2) {
12998
- return {
12999
- uniqueId: record2.id,
13000
- conversationId: record2.id,
13001
- summary: text5(record2.data.summary) ?? "",
13002
- summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
13003
- tokenCount: number(record2.data.tokenCount) ?? 0,
13004
- createdAt: new Date(record2.createdAt),
13005
- updatedAt: new Date(record2.updatedAt)
13006
- };
13007
- }
13008
- function links(data) {
13009
- return Array.isArray(data.links) ? data.links : [];
13010
- }
13011
- function applyLinkOps(data, ops) {
13012
- let current = links(data);
13013
- for (const op of ops) {
13014
- if ("clear" in op) {
13015
- current = [];
13016
- continue;
13017
- }
13018
- const byId = new Map(current.map((l) => [l.memoryId, l]));
13019
- const turn = /* @__PURE__ */ new Set();
13020
- op.add.forEach((item, i) => {
13021
- if (!item.memoryId || turn.has(item.memoryId)) return;
13022
- turn.add(item.memoryId);
13023
- const known = byId.get(item.memoryId);
13024
- if (known && known.createdAt >= op.at + i) return;
13025
- byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
13026
- });
13027
- current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
13028
- }
13029
- return plain({ links: current });
13030
- }
13031
- function toLinks(record2) {
13032
- return links(record2.data).map((l) => ({
13033
- uniqueId: `${record2.id}:${l.memoryId}`,
13034
- conversationId: record2.id,
13035
- memoryId: l.memoryId,
13036
- score: l.score,
13037
- createdAt: new Date(l.createdAt)
13038
- }));
13039
- }
13040
- function bytes(value) {
13041
- return new TextEncoder().encode(JSON.stringify(value)).length;
13042
- }
13043
- function fitRecord(record2) {
13044
- if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
13045
- const data = { ...record2.data };
13046
- const truncated = [];
13047
- for (const field10 of droppable) {
13048
- if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
13049
- if (data[field10] === void 0) continue;
13050
- delete data[field10];
13051
- truncated.push(field10);
13052
- }
13053
- const content = text5(data.content) ?? "";
13054
- const over = bytes({ ...record2, data }) - recordBudgetBytes;
13055
- if (over > 0) {
13056
- const encoded = new TextEncoder().encode(content);
13057
- data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
13058
- truncated.push("content");
13059
- }
13060
- return { ...record2, data: { ...data, truncated } };
13061
- }
13062
- function acceptedVector(vector2) {
13063
- if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
13064
- if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
13065
- return void 0;
13066
- return [...vector2];
13067
- }
13068
- function normalized(vector2) {
13069
- const norm = Math.hypot(...vector2) || 1;
13070
- return vector2.map((x) => x / norm);
13071
- }
13072
- function fitChunks(chunks3) {
13073
- const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
13074
- if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
13075
- if (usable.length <= maxChunks) return usable;
13076
- const out = [];
13077
- for (let g = 0; g < maxChunks; g++) {
13078
- const group = usable.slice(
13079
- Math.floor(g * usable.length / maxChunks),
13080
- Math.floor((g + 1) * usable.length / maxChunks)
13081
- );
13082
- const dims = group[0].vector.length;
13083
- const mean = new Array(dims).fill(0);
13084
- for (const c of group) {
13085
- const unit = normalized(c.vector);
13086
- for (let d = 0; d < dims; d++) mean[d] += unit[d];
13087
- }
13088
- out.push({
13089
- vector: normalized(mean),
13090
- startOffset: group[0].startOffset,
13091
- endOffset: group[group.length - 1].endOffset
13092
- });
13093
- }
13094
- return out;
13095
- }
13096
-
13097
13187
  // src/lib/chatStore/migrateChats.ts
13098
13188
  var maxPasses = 5;
13099
13189
  var verifyBatch = 1e3;
13100
- var importBatch = 100;
13101
- var importChunks = 200;
13102
- var importPlaintextBytes = 39e5;
13103
13190
  var writeBatch = 25;
13104
13191
  function key(record2) {
13105
13192
  return `${record2.kind}/${record2.id}`;
13106
13193
  }
13107
- function ms(date10, fallback = 1) {
13108
- const value = date10?.getTime();
13109
- return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
13110
- }
13111
13194
  function sealed(value) {
13112
13195
  if (typeof value === "string") return isEncrypted(value);
13113
13196
  if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
@@ -13115,42 +13198,6 @@ function sealed(value) {
13115
13198
  return Object.values(value).some(sealed);
13116
13199
  return false;
13117
13200
  }
13118
- function bytes2(value) {
13119
- return new TextEncoder().encode(JSON.stringify(value)).length;
13120
- }
13121
- function messageRecord(message) {
13122
- const {
13123
- uniqueId: _uniqueId,
13124
- messageId: _messageId,
13125
- createdAt: _createdAt,
13126
- updatedAt: _updatedAt,
13127
- decryptionStatus: _status,
13128
- chunks: chunks3,
13129
- vector: vector2,
13130
- ...fields
13131
- } = message;
13132
- const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
13133
- const single = fitted ? void 0 : acceptedVector(vector2);
13134
- const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
13135
- const record2 = fitRecord({
13136
- kind: "message",
13137
- id: message.uniqueId,
13138
- conversationId: message.conversationId,
13139
- sortKey: message.messageId,
13140
- createdAt: ms(message.createdAt),
13141
- updatedAt: ms(message.updatedAt, ms(message.createdAt)),
13142
- isDeleted: false,
13143
- data: {
13144
- ...messageData(fields),
13145
- ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
13146
- }
13147
- });
13148
- return {
13149
- record: record2,
13150
- ...embeddings2 ? { embeddings: embeddings2 } : {},
13151
- ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
13152
- };
13153
- }
13154
13201
  async function readLocal(options) {
13155
13202
  const { database } = options;
13156
13203
  const ctx = {
@@ -13204,29 +13251,10 @@ async function readLocal(options) {
13204
13251
  const messages = await getMessagesOp(ctx, conversationId);
13205
13252
  const unreadableTitle = isEncrypted(conversation.title);
13206
13253
  if (unreadableTitle) out.untitled++;
13207
- const createdAt = ms(conversation.createdAt);
13208
- const data = plain({
13209
- title: unreadableTitle ? "" : conversation.title,
13210
- projectId: conversation.projectId || void 0,
13211
- pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
13212
- lastActivityAt: Math.max(
13213
- ms(conversation.updatedAt, createdAt),
13214
- ...messages.map((m) => ms(m.createdAt))
13215
- )
13216
- });
13217
13254
  out.conversations++;
13218
- out.records.push({
13219
- record: {
13220
- kind: "conversation",
13221
- id: conversationId,
13222
- conversationId: "",
13223
- sortKey: conversationSortKey(data, createdAt),
13224
- createdAt,
13225
- updatedAt: ms(conversation.updatedAt, createdAt),
13226
- isDeleted: false,
13227
- data
13228
- }
13229
- });
13255
+ out.records.push(
13256
+ conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
13257
+ );
13230
13258
  for (const message of messages) {
13231
13259
  if (message.decryptionStatus || sealed(message)) {
13232
13260
  skip("message", message.uniqueId, "unreadable");
@@ -13347,27 +13375,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
13347
13375
  };
13348
13376
  });
13349
13377
  }
13350
- function batches(records) {
13351
- const out = [];
13352
- let batch = [];
13353
- let chunks3 = 0;
13354
- let size = 0;
13355
- for (const item of records) {
13356
- const vectors = item.embeddings?.length ?? 0;
13357
- const itemSize = bytes2(item.record);
13358
- if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
13359
- out.push(batch);
13360
- batch = [];
13361
- chunks3 = 0;
13362
- size = 0;
13363
- }
13364
- batch.push(item);
13365
- chunks3 += vectors;
13366
- size += itemSize;
13367
- }
13368
- if (batch.length) out.push(batch);
13369
- return out;
13370
- }
13371
13378
  function fitVectors(records, available2, unembedded) {
13372
13379
  let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
13373
13380
  if (total <= available2) return records;
@@ -14448,6 +14455,45 @@ function createVaultChatBackend(options) {
14448
14455
  },
14449
14456
  flush,
14450
14457
  poll,
14458
+ async importChats(chats) {
14459
+ await ready();
14460
+ const seen = /* @__PURE__ */ new Set();
14461
+ const unique = (items) => items.filter(({ record: record2 }) => {
14462
+ const k = key2(record2.kind, record2.id);
14463
+ if (seen.has(k)) return false;
14464
+ seen.add(k);
14465
+ return true;
14466
+ });
14467
+ const valid = chats.filter((c) => validChatId(c.conversation.conversationId));
14468
+ const conversations = unique(
14469
+ valid.map((c) => conversationRecord(c.conversation, c.messages))
14470
+ );
14471
+ const messages = unique(
14472
+ valid.flatMap(
14473
+ (c) => c.messages.filter(
14474
+ (m) => m.conversationId === c.conversation.conversationId && validChatId(m.uniqueId) && Number.isSafeInteger(m.messageId)
14475
+ ).map((m) => messageRecord({ ...m, vector: void 0, chunks: void 0 }))
14476
+ )
14477
+ );
14478
+ let conversationCount = 0;
14479
+ let messageCount = 0;
14480
+ try {
14481
+ for (const batch of batches(conversations))
14482
+ conversationCount += await store.importRecords(batch);
14483
+ for (const batch of batches(messages)) messageCount += await store.importRecords(batch);
14484
+ } finally {
14485
+ for (const { record: record2 } of messages) checked.delete(key2("message", record2.id));
14486
+ await refresh(conversations.map(({ record: record2 }) => key2("conversation", record2.id))).catch(
14487
+ () => void 0
14488
+ );
14489
+ for (const { record: record2 } of conversations) threads.delete(record2.id);
14490
+ channel?.postMessage("changed");
14491
+ emit({ type: "conversations", origin: "local" });
14492
+ for (const { record: record2 } of conversations)
14493
+ emit({ type: "messages", conversationId: record2.id, origin: "local" });
14494
+ }
14495
+ return { conversations: conversationCount, messages: messageCount };
14496
+ },
14451
14497
  status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
14452
14498
  close() {
14453
14499
  closed = true;