@anuma/sdk 10.1.1 → 10.2.1

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.
@@ -9978,6 +9978,275 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
9978
9978
  });
9979
9979
  }
9980
9980
 
9981
+ // src/lib/chatStore/vaultRecords.ts
9982
+ var PINNED_SORT_BASE = 2 ** 51;
9983
+ var recordBudgetBytes = 104e4;
9984
+ var storedDims = 1536;
9985
+ var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
9986
+ var maxChunks = 16;
9987
+ var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
9988
+ var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
9989
+ var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
9990
+ function plain(value) {
9991
+ return JSON.parse(JSON.stringify(value ?? {}));
9992
+ }
9993
+ function text4(value) {
9994
+ return typeof value === "string" ? value : void 0;
9995
+ }
9996
+ function number(value) {
9997
+ return typeof value === "number" ? value : void 0;
9998
+ }
9999
+ function conversationSortKey(data, createdAt) {
10000
+ const pinnedAt = number(data.pinnedAt);
10001
+ if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
10002
+ return number(data.lastActivityAt) ?? createdAt;
10003
+ }
10004
+ function toConversation(record2) {
10005
+ const pinnedAt = number(record2.data.pinnedAt);
10006
+ const projectId = text4(record2.data.projectId);
10007
+ return {
10008
+ uniqueId: record2.id,
10009
+ conversationId: record2.id,
10010
+ title: text4(record2.data.title) ?? "",
10011
+ ...projectId ? { projectId } : {},
10012
+ createdAt: new Date(record2.createdAt),
10013
+ updatedAt: new Date(record2.updatedAt),
10014
+ isDeleted: record2.isDeleted,
10015
+ pinnedAt: pinnedAt ? new Date(pinnedAt) : null
10016
+ };
10017
+ }
10018
+ function messageData(options) {
10019
+ return plain(
10020
+ Object.fromEntries(
10021
+ Object.entries(options).filter(
10022
+ ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
10023
+ )
10024
+ )
10025
+ );
10026
+ }
10027
+ function toMessage(record2) {
10028
+ const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
10029
+ return {
10030
+ ...fields,
10031
+ uniqueId: record2.id,
10032
+ messageId: record2.sortKey,
10033
+ conversationId: record2.conversationId,
10034
+ createdAt: new Date(record2.createdAt),
10035
+ updatedAt: new Date(record2.updatedAt)
10036
+ };
10037
+ }
10038
+ function chunkOffsets(record2) {
10039
+ const offsets = record2.data.chunkOffsets;
10040
+ return Array.isArray(offsets) ? offsets : void 0;
10041
+ }
10042
+ function toSkeletons(records) {
10043
+ const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
10044
+ return records.map((r) => {
10045
+ const parentMessageId = text4(r.data.parentMessageId);
10046
+ const model = text4(r.data.model);
10047
+ const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
10048
+ return {
10049
+ uniqueId: r.id,
10050
+ messageId: r.sortKey,
10051
+ conversationId: r.conversationId,
10052
+ role: text4(r.data.role) ?? "",
10053
+ createdAt: new Date(r.createdAt),
10054
+ ...parentMessageId ? { parentMessageId } : {},
10055
+ ...model ? { model } : {},
10056
+ ...artifact ? { content: text4(r.data.content) ?? "" } : {}
10057
+ };
10058
+ });
10059
+ }
10060
+ function toSummary(record2) {
10061
+ return {
10062
+ uniqueId: record2.id,
10063
+ conversationId: record2.id,
10064
+ summary: text4(record2.data.summary) ?? "",
10065
+ summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
10066
+ tokenCount: number(record2.data.tokenCount) ?? 0,
10067
+ createdAt: new Date(record2.createdAt),
10068
+ updatedAt: new Date(record2.updatedAt)
10069
+ };
10070
+ }
10071
+ function links(data) {
10072
+ return Array.isArray(data.links) ? data.links : [];
10073
+ }
10074
+ function applyLinkOps(data, ops) {
10075
+ let current = links(data);
10076
+ for (const op of ops) {
10077
+ if ("clear" in op) {
10078
+ current = [];
10079
+ continue;
10080
+ }
10081
+ const byId = new Map(current.map((l) => [l.memoryId, l]));
10082
+ const turn = /* @__PURE__ */ new Set();
10083
+ op.add.forEach((item, i) => {
10084
+ if (!item.memoryId || turn.has(item.memoryId)) return;
10085
+ turn.add(item.memoryId);
10086
+ const known = byId.get(item.memoryId);
10087
+ if (known && known.createdAt >= op.at + i) return;
10088
+ byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
10089
+ });
10090
+ current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
10091
+ }
10092
+ return plain({ links: current });
10093
+ }
10094
+ function toLinks(record2) {
10095
+ return links(record2.data).map((l) => ({
10096
+ uniqueId: `${record2.id}:${l.memoryId}`,
10097
+ conversationId: record2.id,
10098
+ memoryId: l.memoryId,
10099
+ score: l.score,
10100
+ createdAt: new Date(l.createdAt)
10101
+ }));
10102
+ }
10103
+ function bytes(value) {
10104
+ return new TextEncoder().encode(JSON.stringify(value)).length;
10105
+ }
10106
+ function fitRecord(record2) {
10107
+ if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
10108
+ const data = { ...record2.data };
10109
+ const truncated = [];
10110
+ for (const field10 of droppable) {
10111
+ if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
10112
+ if (data[field10] === void 0) continue;
10113
+ delete data[field10];
10114
+ truncated.push(field10);
10115
+ }
10116
+ const content = text4(data.content) ?? "";
10117
+ const over = bytes({ ...record2, data }) - recordBudgetBytes;
10118
+ if (over > 0) {
10119
+ const encoded = new TextEncoder().encode(content);
10120
+ data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
10121
+ truncated.push("content");
10122
+ }
10123
+ return { ...record2, data: { ...data, truncated } };
10124
+ }
10125
+ function acceptedVector(vector2) {
10126
+ if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
10127
+ if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims).some((x) => x !== 0))
10128
+ return void 0;
10129
+ return [...vector2];
10130
+ }
10131
+ function normalized(vector2) {
10132
+ const norm = Math.hypot(...vector2) || 1;
10133
+ return vector2.map((x) => x / norm);
10134
+ }
10135
+ function fitChunks(chunks3) {
10136
+ const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
10137
+ if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
10138
+ if (usable.length <= maxChunks) return usable;
10139
+ const out = [];
10140
+ for (let g = 0; g < maxChunks; g++) {
10141
+ const group = usable.slice(
10142
+ Math.floor(g * usable.length / maxChunks),
10143
+ Math.floor((g + 1) * usable.length / maxChunks)
10144
+ );
10145
+ const dims = group[0].vector.length;
10146
+ const mean = new Array(dims).fill(0);
10147
+ for (const c of group) {
10148
+ const unit = normalized(c.vector);
10149
+ for (let d = 0; d < dims; d++) mean[d] += unit[d];
10150
+ }
10151
+ out.push({
10152
+ vector: normalized(mean),
10153
+ startOffset: group[0].startOffset,
10154
+ endOffset: group[group.length - 1].endOffset
10155
+ });
10156
+ }
10157
+ return out;
10158
+ }
10159
+
10160
+ // src/lib/chatStore/chatImports.ts
10161
+ var importBatch = 100;
10162
+ var importChunks = 200;
10163
+ var importPlaintextBytes = 39e5;
10164
+ function ms(date10, fallback = 1) {
10165
+ const value = date10?.getTime();
10166
+ return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
10167
+ }
10168
+ function bytes2(value) {
10169
+ return new TextEncoder().encode(JSON.stringify(value)).length;
10170
+ }
10171
+ function conversationRecord(conversation, messages) {
10172
+ const createdAt = ms(conversation.createdAt);
10173
+ const data = plain({
10174
+ title: conversation.title,
10175
+ projectId: conversation.projectId || void 0,
10176
+ pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
10177
+ lastActivityAt: Math.max(
10178
+ ms(conversation.updatedAt, createdAt),
10179
+ ...messages.map((m) => ms(m.createdAt))
10180
+ )
10181
+ });
10182
+ return {
10183
+ record: {
10184
+ kind: "conversation",
10185
+ id: conversation.conversationId,
10186
+ conversationId: "",
10187
+ sortKey: conversationSortKey(data, createdAt),
10188
+ createdAt,
10189
+ updatedAt: ms(conversation.updatedAt, createdAt),
10190
+ isDeleted: false,
10191
+ data
10192
+ }
10193
+ };
10194
+ }
10195
+ function messageRecord(message) {
10196
+ const {
10197
+ uniqueId: _uniqueId,
10198
+ messageId: _messageId,
10199
+ createdAt: _createdAt,
10200
+ updatedAt: _updatedAt,
10201
+ decryptionStatus: _status,
10202
+ chunks: chunks3,
10203
+ vector: vector2,
10204
+ ...fields
10205
+ } = message;
10206
+ const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
10207
+ const single = fitted ? void 0 : acceptedVector(vector2);
10208
+ const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
10209
+ const record2 = fitRecord({
10210
+ kind: "message",
10211
+ id: message.uniqueId,
10212
+ conversationId: message.conversationId,
10213
+ sortKey: message.messageId,
10214
+ createdAt: ms(message.createdAt),
10215
+ updatedAt: ms(message.updatedAt, ms(message.createdAt)),
10216
+ isDeleted: false,
10217
+ data: {
10218
+ ...messageData(fields),
10219
+ ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
10220
+ }
10221
+ });
10222
+ return {
10223
+ record: record2,
10224
+ ...embeddings2 ? { embeddings: embeddings2 } : {},
10225
+ ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
10226
+ };
10227
+ }
10228
+ function batches(records) {
10229
+ const out = [];
10230
+ let batch = [];
10231
+ let chunks3 = 0;
10232
+ let size = 0;
10233
+ for (const item of records) {
10234
+ const vectors = item.embeddings?.length ?? 0;
10235
+ const itemSize = bytes2(item.record);
10236
+ if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
10237
+ out.push(batch);
10238
+ batch = [];
10239
+ chunks3 = 0;
10240
+ size = 0;
10241
+ }
10242
+ batch.push(item);
10243
+ chunks3 += vectors;
10244
+ size += itemSize;
10245
+ }
10246
+ if (batch.length) out.push(batch);
10247
+ return out;
10248
+ }
10249
+
9981
10250
  // src/lib/db/entities/types.ts
9982
10251
  var ENTITY_KINDS = [
9983
10252
  "person",
@@ -10716,7 +10985,7 @@ var ChatStoreError = class extends Error {
10716
10985
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
10717
10986
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
10718
10987
  var maxPayload = 2 * 1024 * 1024;
10719
- var storedDims = 1536;
10988
+ var storedDims2 = 1536;
10720
10989
  var maxRequestCiphertext = 8 * 1024 * 1024;
10721
10990
  var maxGetRefs = 50;
10722
10991
  var maxImportRecords = 100;
@@ -10784,24 +11053,24 @@ function vector(v) {
10784
11053
  for (let i = 0; i < v.length; i++) {
10785
11054
  const x = v[i];
10786
11055
  if (typeof x !== "number" || !Number.isFinite(x)) return false;
10787
- if (i < storedDims && x !== 0) nonZero = true;
11056
+ if (i < storedDims2 && x !== 0) nonZero = true;
10788
11057
  }
10789
11058
  return nonZero;
10790
11059
  }
10791
11060
  function vectorFields(write) {
10792
11061
  return {
10793
- ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims)) } : {},
11062
+ ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
10794
11063
  ...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
10795
11064
  };
10796
11065
  }
10797
- function text4(value) {
11066
+ function text5(value) {
10798
11067
  return typeof value === "string";
10799
11068
  }
10800
11069
  function timestamp(value) {
10801
11070
  return typeof value === "string" && Number.isFinite(Date.parse(value));
10802
11071
  }
10803
11072
  function presigned(value) {
10804
- 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))
11073
+ 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))
10805
11074
  invalid();
10806
11075
  return {
10807
11076
  url: value.url,
@@ -10811,7 +11080,7 @@ function presigned(value) {
10811
11080
  };
10812
11081
  }
10813
11082
  function attachment(value) {
10814
- 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))
11083
+ 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))
10815
11084
  invalid();
10816
11085
  return {
10817
11086
  id: value.attachment_id,
@@ -10824,7 +11093,7 @@ function attachment(value) {
10824
11093
  };
10825
11094
  }
10826
11095
  function ref(value) {
10827
- if (!object(value) || !text4(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
11096
+ if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
10828
11097
  return { kind: value.kind, id: value.id };
10829
11098
  }
10830
11099
  function sameMetadata(a, b) {
@@ -11047,7 +11316,7 @@ async function createRemoteChatStore(options) {
11047
11316
  },
11048
11317
  async account(signal) {
11049
11318
  const value = await request("/account", {}, signal);
11050
- 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))
11319
+ 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))
11051
11320
  invalid();
11052
11321
  if (value.key_id && value.key_id !== keyId)
11053
11322
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -11122,12 +11391,12 @@ async function createRemoteChatStore(options) {
11122
11391
  },
11123
11392
  async changes(cursor, options2) {
11124
11393
  const limit = options2?.limit ?? 100;
11125
- if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text4(cursor) || cursor.length > 2048))
11394
+ if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
11126
11395
  invalid();
11127
11396
  const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
11128
11397
  if (cursor) params.set("cursor", cursor);
11129
11398
  const value = await request(`/changes?${params}`, {}, options2?.signal);
11130
- 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))
11399
+ 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))
11131
11400
  invalid();
11132
11401
  const items = [];
11133
11402
  for (const item of value.items) items.push(await decode(item));
@@ -11144,7 +11413,7 @@ async function createRemoteChatStore(options) {
11144
11413
  if (!Array.isArray(embedding2) || !embeddings({
11145
11414
  record: { ...emptyMessage, isDeleted: false },
11146
11415
  embeddings: [embedding2]
11147
- }) || !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))
11416
+ }) || !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))
11148
11417
  invalid();
11149
11418
  const value = await request(
11150
11419
  "/search",
@@ -11152,7 +11421,7 @@ async function createRemoteChatStore(options) {
11152
11421
  method: "POST",
11153
11422
  body: JSON.stringify({
11154
11423
  account_id: accountId,
11155
- embedding: embedding2.slice(0, storedDims),
11424
+ embedding: embedding2.slice(0, storedDims2),
11156
11425
  limit,
11157
11426
  ...kindsFilter ? { kinds: kindsFilter } : {},
11158
11427
  ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
@@ -11256,199 +11525,13 @@ var emptyMessage = {
11256
11525
  data: {}
11257
11526
  };
11258
11527
 
11259
- // src/lib/chatStore/vaultRecords.ts
11260
- var PINNED_SORT_BASE = 2 ** 51;
11261
- var recordBudgetBytes = 104e4;
11262
- var storedDims2 = 1536;
11263
- var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
11264
- var maxChunks = 16;
11265
- var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
11266
- var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
11267
- var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
11268
- function plain(value) {
11269
- return JSON.parse(JSON.stringify(value ?? {}));
11270
- }
11271
- function text5(value) {
11272
- return typeof value === "string" ? value : void 0;
11273
- }
11274
- function number(value) {
11275
- return typeof value === "number" ? value : void 0;
11276
- }
11277
- function conversationSortKey(data, createdAt) {
11278
- const pinnedAt = number(data.pinnedAt);
11279
- if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
11280
- return number(data.lastActivityAt) ?? createdAt;
11281
- }
11282
- function toConversation(record2) {
11283
- const pinnedAt = number(record2.data.pinnedAt);
11284
- const projectId = text5(record2.data.projectId);
11285
- return {
11286
- uniqueId: record2.id,
11287
- conversationId: record2.id,
11288
- title: text5(record2.data.title) ?? "",
11289
- ...projectId ? { projectId } : {},
11290
- createdAt: new Date(record2.createdAt),
11291
- updatedAt: new Date(record2.updatedAt),
11292
- isDeleted: record2.isDeleted,
11293
- pinnedAt: pinnedAt ? new Date(pinnedAt) : null
11294
- };
11295
- }
11296
- function messageData(options) {
11297
- return plain(
11298
- Object.fromEntries(
11299
- Object.entries(options).filter(
11300
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
11301
- )
11302
- )
11303
- );
11304
- }
11305
- function toMessage(record2) {
11306
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
11307
- return {
11308
- ...fields,
11309
- uniqueId: record2.id,
11310
- messageId: record2.sortKey,
11311
- conversationId: record2.conversationId,
11312
- createdAt: new Date(record2.createdAt),
11313
- updatedAt: new Date(record2.updatedAt)
11314
- };
11315
- }
11316
- function chunkOffsets(record2) {
11317
- const offsets = record2.data.chunkOffsets;
11318
- return Array.isArray(offsets) ? offsets : void 0;
11319
- }
11320
- function toSkeletons(records) {
11321
- const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
11322
- return records.map((r) => {
11323
- const parentMessageId = text5(r.data.parentMessageId);
11324
- const model = text5(r.data.model);
11325
- const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
11326
- return {
11327
- uniqueId: r.id,
11328
- messageId: r.sortKey,
11329
- conversationId: r.conversationId,
11330
- role: text5(r.data.role) ?? "",
11331
- createdAt: new Date(r.createdAt),
11332
- ...parentMessageId ? { parentMessageId } : {},
11333
- ...model ? { model } : {},
11334
- ...artifact ? { content: text5(r.data.content) ?? "" } : {}
11335
- };
11336
- });
11337
- }
11338
- function toSummary(record2) {
11339
- return {
11340
- uniqueId: record2.id,
11341
- conversationId: record2.id,
11342
- summary: text5(record2.data.summary) ?? "",
11343
- summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
11344
- tokenCount: number(record2.data.tokenCount) ?? 0,
11345
- createdAt: new Date(record2.createdAt),
11346
- updatedAt: new Date(record2.updatedAt)
11347
- };
11348
- }
11349
- function links(data) {
11350
- return Array.isArray(data.links) ? data.links : [];
11351
- }
11352
- function applyLinkOps(data, ops) {
11353
- let current = links(data);
11354
- for (const op of ops) {
11355
- if ("clear" in op) {
11356
- current = [];
11357
- continue;
11358
- }
11359
- const byId = new Map(current.map((l) => [l.memoryId, l]));
11360
- const turn = /* @__PURE__ */ new Set();
11361
- op.add.forEach((item, i) => {
11362
- if (!item.memoryId || turn.has(item.memoryId)) return;
11363
- turn.add(item.memoryId);
11364
- const known = byId.get(item.memoryId);
11365
- if (known && known.createdAt >= op.at + i) return;
11366
- byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
11367
- });
11368
- current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
11369
- }
11370
- return plain({ links: current });
11371
- }
11372
- function toLinks(record2) {
11373
- return links(record2.data).map((l) => ({
11374
- uniqueId: `${record2.id}:${l.memoryId}`,
11375
- conversationId: record2.id,
11376
- memoryId: l.memoryId,
11377
- score: l.score,
11378
- createdAt: new Date(l.createdAt)
11379
- }));
11380
- }
11381
- function bytes(value) {
11382
- return new TextEncoder().encode(JSON.stringify(value)).length;
11383
- }
11384
- function fitRecord(record2) {
11385
- if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
11386
- const data = { ...record2.data };
11387
- const truncated = [];
11388
- for (const field10 of droppable) {
11389
- if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
11390
- if (data[field10] === void 0) continue;
11391
- delete data[field10];
11392
- truncated.push(field10);
11393
- }
11394
- const content = text5(data.content) ?? "";
11395
- const over = bytes({ ...record2, data }) - recordBudgetBytes;
11396
- if (over > 0) {
11397
- const encoded = new TextEncoder().encode(content);
11398
- data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
11399
- truncated.push("content");
11400
- }
11401
- return { ...record2, data: { ...data, truncated } };
11402
- }
11403
- function acceptedVector(vector2) {
11404
- if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
11405
- if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
11406
- return void 0;
11407
- return [...vector2];
11408
- }
11409
- function normalized(vector2) {
11410
- const norm = Math.hypot(...vector2) || 1;
11411
- return vector2.map((x) => x / norm);
11412
- }
11413
- function fitChunks(chunks3) {
11414
- const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
11415
- if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
11416
- if (usable.length <= maxChunks) return usable;
11417
- const out = [];
11418
- for (let g = 0; g < maxChunks; g++) {
11419
- const group = usable.slice(
11420
- Math.floor(g * usable.length / maxChunks),
11421
- Math.floor((g + 1) * usable.length / maxChunks)
11422
- );
11423
- const dims = group[0].vector.length;
11424
- const mean = new Array(dims).fill(0);
11425
- for (const c of group) {
11426
- const unit = normalized(c.vector);
11427
- for (let d = 0; d < dims; d++) mean[d] += unit[d];
11428
- }
11429
- out.push({
11430
- vector: normalized(mean),
11431
- startOffset: group[0].startOffset,
11432
- endOffset: group[group.length - 1].endOffset
11433
- });
11434
- }
11435
- return out;
11436
- }
11437
-
11438
11528
  // src/lib/chatStore/migrateChats.ts
11439
11529
  var maxPasses = 5;
11440
11530
  var verifyBatch = 1e3;
11441
- var importBatch = 100;
11442
- var importChunks = 200;
11443
- var importPlaintextBytes = 39e5;
11444
11531
  var writeBatch = 25;
11445
11532
  function key(record2) {
11446
11533
  return `${record2.kind}/${record2.id}`;
11447
11534
  }
11448
- function ms(date10, fallback = 1) {
11449
- const value = date10?.getTime();
11450
- return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
11451
- }
11452
11535
  function sealed(value) {
11453
11536
  if (typeof value === "string") return isEncrypted(value);
11454
11537
  if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
@@ -11456,42 +11539,6 @@ function sealed(value) {
11456
11539
  return Object.values(value).some(sealed);
11457
11540
  return false;
11458
11541
  }
11459
- function bytes2(value) {
11460
- return new TextEncoder().encode(JSON.stringify(value)).length;
11461
- }
11462
- function messageRecord(message) {
11463
- const {
11464
- uniqueId: _uniqueId,
11465
- messageId: _messageId,
11466
- createdAt: _createdAt,
11467
- updatedAt: _updatedAt,
11468
- decryptionStatus: _status,
11469
- chunks: chunks3,
11470
- vector: vector2,
11471
- ...fields
11472
- } = message;
11473
- const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
11474
- const single = fitted ? void 0 : acceptedVector(vector2);
11475
- const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
11476
- const record2 = fitRecord({
11477
- kind: "message",
11478
- id: message.uniqueId,
11479
- conversationId: message.conversationId,
11480
- sortKey: message.messageId,
11481
- createdAt: ms(message.createdAt),
11482
- updatedAt: ms(message.updatedAt, ms(message.createdAt)),
11483
- isDeleted: false,
11484
- data: {
11485
- ...messageData(fields),
11486
- ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
11487
- }
11488
- });
11489
- return {
11490
- record: record2,
11491
- ...embeddings2 ? { embeddings: embeddings2 } : {},
11492
- ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
11493
- };
11494
- }
11495
11542
  async function readLocal(options) {
11496
11543
  const { database } = options;
11497
11544
  const ctx = {
@@ -11545,29 +11592,10 @@ async function readLocal(options) {
11545
11592
  const messages = await getMessagesOp(ctx, conversationId);
11546
11593
  const unreadableTitle = isEncrypted(conversation.title);
11547
11594
  if (unreadableTitle) out.untitled++;
11548
- const createdAt = ms(conversation.createdAt);
11549
- const data = plain({
11550
- title: unreadableTitle ? "" : conversation.title,
11551
- projectId: conversation.projectId || void 0,
11552
- pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
11553
- lastActivityAt: Math.max(
11554
- ms(conversation.updatedAt, createdAt),
11555
- ...messages.map((m) => ms(m.createdAt))
11556
- )
11557
- });
11558
11595
  out.conversations++;
11559
- out.records.push({
11560
- record: {
11561
- kind: "conversation",
11562
- id: conversationId,
11563
- conversationId: "",
11564
- sortKey: conversationSortKey(data, createdAt),
11565
- createdAt,
11566
- updatedAt: ms(conversation.updatedAt, createdAt),
11567
- isDeleted: false,
11568
- data
11569
- }
11570
- });
11596
+ out.records.push(
11597
+ conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
11598
+ );
11571
11599
  for (const message of messages) {
11572
11600
  if (message.decryptionStatus || sealed(message)) {
11573
11601
  skip("message", message.uniqueId, "unreadable");
@@ -11688,27 +11716,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
11688
11716
  };
11689
11717
  });
11690
11718
  }
11691
- function batches(records) {
11692
- const out = [];
11693
- let batch = [];
11694
- let chunks3 = 0;
11695
- let size = 0;
11696
- for (const item of records) {
11697
- const vectors = item.embeddings?.length ?? 0;
11698
- const itemSize = bytes2(item.record);
11699
- if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
11700
- out.push(batch);
11701
- batch = [];
11702
- chunks3 = 0;
11703
- size = 0;
11704
- }
11705
- batch.push(item);
11706
- chunks3 += vectors;
11707
- size += itemSize;
11708
- }
11709
- if (batch.length) out.push(batch);
11710
- return out;
11711
- }
11712
11719
  function fitVectors(records, available2, unembedded) {
11713
11720
  let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
11714
11721
  if (total <= available2) return records;
@@ -12789,6 +12796,45 @@ function createVaultChatBackend(options) {
12789
12796
  },
12790
12797
  flush,
12791
12798
  poll,
12799
+ async importChats(chats) {
12800
+ await ready();
12801
+ const seen = /* @__PURE__ */ new Set();
12802
+ const unique = (items) => items.filter(({ record: record2 }) => {
12803
+ const k = key2(record2.kind, record2.id);
12804
+ if (seen.has(k)) return false;
12805
+ seen.add(k);
12806
+ return true;
12807
+ });
12808
+ const valid = chats.filter((c) => validChatId(c.conversation.conversationId));
12809
+ const conversations = unique(
12810
+ valid.map((c) => conversationRecord(c.conversation, c.messages))
12811
+ );
12812
+ const messages = unique(
12813
+ valid.flatMap(
12814
+ (c) => c.messages.filter(
12815
+ (m) => m.conversationId === c.conversation.conversationId && validChatId(m.uniqueId) && Number.isSafeInteger(m.messageId)
12816
+ ).map((m) => messageRecord({ ...m, vector: void 0, chunks: void 0 }))
12817
+ )
12818
+ );
12819
+ let conversationCount = 0;
12820
+ let messageCount = 0;
12821
+ try {
12822
+ for (const batch of batches(conversations))
12823
+ conversationCount += await store.importRecords(batch);
12824
+ for (const batch of batches(messages)) messageCount += await store.importRecords(batch);
12825
+ } finally {
12826
+ for (const { record: record2 } of messages) checked.delete(key2("message", record2.id));
12827
+ await refresh(conversations.map(({ record: record2 }) => key2("conversation", record2.id))).catch(
12828
+ () => void 0
12829
+ );
12830
+ for (const { record: record2 } of conversations) threads.delete(record2.id);
12831
+ channel?.postMessage("changed");
12832
+ emit({ type: "conversations", origin: "local" });
12833
+ for (const { record: record2 } of conversations)
12834
+ emit({ type: "messages", conversationId: record2.id, origin: "local" });
12835
+ }
12836
+ return { conversations: conversationCount, messages: messageCount };
12837
+ },
12792
12838
  status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
12793
12839
  close() {
12794
12840
  closed = true;