@anuma/sdk 10.1.0 → 10.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9780,17 +9780,18 @@ var xhrTransport = (options) => {
9780
9780
 
9781
9781
  // src/lib/db/chat/summaryOperations.ts
9782
9782
  import { Q as Q3 } from "@nozbe/watermelondb";
9783
- function createSummaryContext(database) {
9783
+ function createSummaryContext(database, encryption = {}) {
9784
9784
  return {
9785
+ ...encryption,
9785
9786
  database,
9786
9787
  summariesCollection: database.get("conversation_summaries")
9787
9788
  };
9788
9789
  }
9789
- function modelToStored(record2) {
9790
+ function modelToStored(record2, summary) {
9790
9791
  return {
9791
9792
  uniqueId: record2.id,
9792
9793
  conversationId: record2.conversationId,
9793
- summary: record2.summary,
9794
+ summary,
9794
9795
  summarizedUpTo: record2.summarizedUpTo,
9795
9796
  tokenCount: record2.tokenCount,
9796
9797
  createdAt: record2.createdAt,
@@ -9800,28 +9801,62 @@ function modelToStored(record2) {
9800
9801
  async function getConversationSummaryOp(ctx, conversationId) {
9801
9802
  const results = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
9802
9803
  if (results.length === 0) return null;
9803
- return modelToStored(results[0]);
9804
+ const record2 = results[0];
9805
+ const stored2 = modelToStored(record2, record2.summary);
9806
+ if (ctx.walletAddress && isEncrypted(stored2.summary)) {
9807
+ if (ctx.signMessage) {
9808
+ try {
9809
+ await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
9810
+ } catch (error) {
9811
+ getLogger().warn("Failed to request the encryption key for the summary:", error);
9812
+ }
9813
+ }
9814
+ stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
9815
+ } else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
9816
+ try {
9817
+ const encryptedSummary = await encryptField(
9818
+ stored2.summary,
9819
+ ctx.walletAddress,
9820
+ ctx.signMessage,
9821
+ ctx.embeddedWalletSigner
9822
+ );
9823
+ await ctx.database.write(async () => {
9824
+ const current = await ctx.summariesCollection.query(Q3.where("id", record2.id)).fetch();
9825
+ if (current[0]?.summary === stored2.summary) {
9826
+ await current[0].update((rec) => {
9827
+ rec.summary = encryptedSummary;
9828
+ });
9829
+ }
9830
+ });
9831
+ } catch (error) {
9832
+ getLogger().warn("Failed to encrypt the legacy summary:", error);
9833
+ }
9834
+ }
9835
+ return stored2;
9804
9836
  }
9805
9837
  async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
9838
+ const revision2 = getConversationRevision(ctx.database, conversationId);
9806
9839
  let record2;
9840
+ const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
9807
9841
  await ctx.database.write(async () => {
9842
+ assertConversationRevision(ctx.database, conversationId, revision2);
9808
9843
  const existing = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
9809
9844
  if (existing.length > 0) {
9810
9845
  record2 = await existing[0].update((rec) => {
9811
- rec.summary = summary;
9846
+ rec.summary = encryptedSummary;
9812
9847
  rec.summarizedUpTo = summarizedUpTo;
9813
9848
  rec.tokenCount = tokenCount;
9814
9849
  });
9815
9850
  } else {
9816
9851
  record2 = await ctx.summariesCollection.create((rec) => {
9817
9852
  rec.conversationId = conversationId;
9818
- rec.summary = summary;
9853
+ rec.summary = encryptedSummary;
9819
9854
  rec.summarizedUpTo = summarizedUpTo;
9820
9855
  rec.tokenCount = tokenCount;
9821
9856
  });
9822
9857
  }
9823
9858
  });
9824
- return modelToStored(record2);
9859
+ return modelToStored(record2, summary);
9825
9860
  }
9826
9861
  async function deleteConversationSummaryOp(ctx, conversationId) {
9827
9862
  await ctx.database.write(async () => {
@@ -9943,95 +9978,364 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
9943
9978
  });
9944
9979
  }
9945
9980
 
9946
- // src/lib/db/entities/types.ts
9947
- var ENTITY_KINDS = [
9948
- "person",
9949
- "organization",
9950
- "place",
9951
- "event",
9952
- "product",
9953
- "thing",
9954
- "concept",
9955
- "other"
9956
- ];
9957
- function normalizeEntityName(name) {
9958
- return name.trim().toLowerCase();
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 ?? {}));
9959
9992
  }
9960
- var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
9961
- function topicWeight(topic2) {
9962
- return topic2.source === "user" ? 1 : topic2.weight ?? 1;
9993
+ function text4(value) {
9994
+ return typeof value === "string" ? value : void 0;
9963
9995
  }
9964
- function primaryTopic(topics) {
9965
- let best = null;
9966
- for (const topic2 of topics ?? []) {
9967
- if (best === null || topicWeight(topic2) > topicWeight(best)) best = topic2;
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);
9968
10091
  }
9969
- return best;
10092
+ return plain({ links: current });
9970
10093
  }
9971
- function parseTopicWeight(value) {
9972
- return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
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
+ }));
9973
10102
  }
9974
- function serializeTopics(topics) {
9975
- return JSON.stringify(topics);
10103
+ function bytes(value) {
10104
+ return new TextEncoder().encode(JSON.stringify(value)).length;
9976
10105
  }
9977
- function parseTopics(value) {
9978
- if (typeof value !== "string" || value.length === 0) return null;
9979
- let parsed;
9980
- try {
9981
- parsed = JSON.parse(value);
9982
- } catch {
9983
- return null;
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);
9984
10115
  }
9985
- if (!Array.isArray(parsed)) return null;
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;
9986
10139
  const out = [];
9987
- for (const raw of parsed) {
9988
- if (typeof raw !== "object" || raw === null) continue;
9989
- const { name, kind, source, weight } = raw;
9990
- if (typeof name !== "string" || name.trim().length === 0) continue;
9991
- const parsedWeight = parseTopicWeight(weight);
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
+ }
9992
10151
  out.push({
9993
- name,
9994
- ...typeof kind === "string" && kind.length > 0 ? { kind } : {},
9995
- source: source === "user" ? "user" : "auto",
9996
- ...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
10152
+ vector: normalized(mean),
10153
+ startOffset: group[0].startOffset,
10154
+ endOffset: group[group.length - 1].endOffset
9997
10155
  });
9998
10156
  }
9999
10157
  return out;
10000
10158
  }
10001
10159
 
10002
- // src/lib/memory/store/remoteTopics.ts
10003
- function topic(value) {
10004
- const t = value;
10005
- if (!t || typeof t.name !== "string" || !t.name || !Number.isSafeInteger(t.version) || t.version < 1 || typeof t.is_deleted !== "boolean" || typeof t.server_updated_at !== "string" || t.kind !== void 0 && typeof t.kind !== "string")
10006
- throw new Error("Invalid nearby topic");
10007
- return t;
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;
10008
10167
  }
10009
- function createRemoteTopicPersistence(request) {
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
+ });
10010
10182
  return {
10011
- topics: async () => {
10012
- const out = [];
10013
- let cursor;
10014
- do {
10015
- const page = await request(
10016
- "/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
10017
- {}
10018
- );
10019
- if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
10020
- throw new Error("Invalid nearby topic page");
10021
- out.push(...page.items.map(topic));
10022
- cursor = page.next_cursor;
10023
- } while (cursor);
10024
- return out;
10025
- },
10026
- putTopic: async (value, expectedVersion) => {
10027
- if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
10028
- throw new Error("Expected topic version must be a nonnegative integer");
10029
- return topic(
10030
- await request("/topics", {
10031
- method: "PUT",
10032
- body: JSON.stringify({ topic: value, expected_version: expectedVersion })
10033
- })
10034
- );
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
+
10250
+ // src/lib/db/entities/types.ts
10251
+ var ENTITY_KINDS = [
10252
+ "person",
10253
+ "organization",
10254
+ "place",
10255
+ "event",
10256
+ "product",
10257
+ "thing",
10258
+ "concept",
10259
+ "other"
10260
+ ];
10261
+ function normalizeEntityName(name) {
10262
+ return name.trim().toLowerCase();
10263
+ }
10264
+ var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
10265
+ function topicWeight(topic2) {
10266
+ return topic2.source === "user" ? 1 : topic2.weight ?? 1;
10267
+ }
10268
+ function primaryTopic(topics) {
10269
+ let best = null;
10270
+ for (const topic2 of topics ?? []) {
10271
+ if (best === null || topicWeight(topic2) > topicWeight(best)) best = topic2;
10272
+ }
10273
+ return best;
10274
+ }
10275
+ function parseTopicWeight(value) {
10276
+ return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
10277
+ }
10278
+ function serializeTopics(topics) {
10279
+ return JSON.stringify(topics);
10280
+ }
10281
+ function parseTopics(value) {
10282
+ if (typeof value !== "string" || value.length === 0) return null;
10283
+ let parsed;
10284
+ try {
10285
+ parsed = JSON.parse(value);
10286
+ } catch {
10287
+ return null;
10288
+ }
10289
+ if (!Array.isArray(parsed)) return null;
10290
+ const out = [];
10291
+ for (const raw of parsed) {
10292
+ if (typeof raw !== "object" || raw === null) continue;
10293
+ const { name, kind, source, weight } = raw;
10294
+ if (typeof name !== "string" || name.trim().length === 0) continue;
10295
+ const parsedWeight = parseTopicWeight(weight);
10296
+ out.push({
10297
+ name,
10298
+ ...typeof kind === "string" && kind.length > 0 ? { kind } : {},
10299
+ source: source === "user" ? "user" : "auto",
10300
+ ...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
10301
+ });
10302
+ }
10303
+ return out;
10304
+ }
10305
+
10306
+ // src/lib/memory/store/remoteTopics.ts
10307
+ function topic(value) {
10308
+ const t = value;
10309
+ if (!t || typeof t.name !== "string" || !t.name || !Number.isSafeInteger(t.version) || t.version < 1 || typeof t.is_deleted !== "boolean" || typeof t.server_updated_at !== "string" || t.kind !== void 0 && typeof t.kind !== "string")
10310
+ throw new Error("Invalid nearby topic");
10311
+ return t;
10312
+ }
10313
+ function createRemoteTopicPersistence(request) {
10314
+ return {
10315
+ topics: async () => {
10316
+ const out = [];
10317
+ let cursor;
10318
+ do {
10319
+ const page = await request(
10320
+ "/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
10321
+ {}
10322
+ );
10323
+ if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
10324
+ throw new Error("Invalid nearby topic page");
10325
+ out.push(...page.items.map(topic));
10326
+ cursor = page.next_cursor;
10327
+ } while (cursor);
10328
+ return out;
10329
+ },
10330
+ putTopic: async (value, expectedVersion) => {
10331
+ if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
10332
+ throw new Error("Expected topic version must be a nonnegative integer");
10333
+ return topic(
10334
+ await request("/topics", {
10335
+ method: "PUT",
10336
+ body: JSON.stringify({ topic: value, expected_version: expectedVersion })
10337
+ })
10338
+ );
10035
10339
  },
10036
10340
  importTopics: async (topics, signal) => {
10037
10341
  for (let i = 0; i < topics.length; i += 50) {
@@ -10681,7 +10985,7 @@ var ChatStoreError = class extends Error {
10681
10985
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
10682
10986
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
10683
10987
  var maxPayload = 2 * 1024 * 1024;
10684
- var storedDims = 1536;
10988
+ var storedDims2 = 1536;
10685
10989
  var maxRequestCiphertext = 8 * 1024 * 1024;
10686
10990
  var maxGetRefs = 50;
10687
10991
  var maxImportRecords = 100;
@@ -10749,24 +11053,24 @@ function vector(v) {
10749
11053
  for (let i = 0; i < v.length; i++) {
10750
11054
  const x = v[i];
10751
11055
  if (typeof x !== "number" || !Number.isFinite(x)) return false;
10752
- if (i < storedDims && x !== 0) nonZero = true;
11056
+ if (i < storedDims2 && x !== 0) nonZero = true;
10753
11057
  }
10754
11058
  return nonZero;
10755
11059
  }
10756
11060
  function vectorFields(write) {
10757
11061
  return {
10758
- ...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)) } : {},
10759
11063
  ...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
10760
11064
  };
10761
11065
  }
10762
- function text4(value) {
11066
+ function text5(value) {
10763
11067
  return typeof value === "string";
10764
11068
  }
10765
11069
  function timestamp(value) {
10766
11070
  return typeof value === "string" && Number.isFinite(Date.parse(value));
10767
11071
  }
10768
11072
  function presigned(value) {
10769
- 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))
10770
11074
  invalid();
10771
11075
  return {
10772
11076
  url: value.url,
@@ -10776,7 +11080,7 @@ function presigned(value) {
10776
11080
  };
10777
11081
  }
10778
11082
  function attachment(value) {
10779
- 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))
10780
11084
  invalid();
10781
11085
  return {
10782
11086
  id: value.attachment_id,
@@ -10789,7 +11093,7 @@ function attachment(value) {
10789
11093
  };
10790
11094
  }
10791
11095
  function ref(value) {
10792
- 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();
10793
11097
  return { kind: value.kind, id: value.id };
10794
11098
  }
10795
11099
  function sameMetadata(a, b) {
@@ -11012,7 +11316,7 @@ async function createRemoteChatStore(options) {
11012
11316
  },
11013
11317
  async account(signal) {
11014
11318
  const value = await request("/account", {}, signal);
11015
- 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))
11016
11320
  invalid();
11017
11321
  if (value.key_id && value.key_id !== keyId)
11018
11322
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -11056,364 +11360,178 @@ async function createRemoteChatStore(options) {
11056
11360
  asked.add(`${checked.kind}/${checked.id}`);
11057
11361
  return {
11058
11362
  kind: checked.kind,
11059
- id: checked.id,
11060
- updated_at: r.updatedAt,
11061
- is_deleted: r.isDeleted
11062
- };
11063
- });
11064
- if (wireRevisions.length === 0) return [];
11065
- const value = await request(
11066
- "/verify",
11067
- {
11068
- method: "POST",
11069
- body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
11070
- },
11071
- signal
11072
- );
11073
- if (!object(value) || !Array.isArray(value.missing)) invalid();
11074
- const missing2 = value.missing.map(ref);
11075
- if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
11076
- return missing2;
11077
- },
11078
- async activate(signal) {
11079
- const value = await request(
11080
- "/account",
11081
- { method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
11082
- signal
11083
- );
11084
- if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
11085
- invalid();
11086
- return value.transitioned;
11087
- },
11088
- async changes(cursor, options2) {
11089
- const limit = options2?.limit ?? 100;
11090
- if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text4(cursor) || cursor.length > 2048))
11091
- invalid();
11092
- const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
11093
- if (cursor) params.set("cursor", cursor);
11094
- const value = await request(`/changes?${params}`, {}, options2?.signal);
11095
- 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))
11096
- invalid();
11097
- const items = [];
11098
- for (const item of value.items) items.push(await decode(item));
11099
- options2?.signal?.throwIfAborted();
11100
- return {
11101
- items,
11102
- ...value.next_cursor ? { nextCursor: value.next_cursor } : {},
11103
- changesCursor: value.changes_cursor ?? cursor ?? ""
11104
- };
11105
- },
11106
- async search(embedding2, options2) {
11107
- const limit = options2?.limit ?? 20;
11108
- const kindsFilter = options2?.kinds;
11109
- if (!Array.isArray(embedding2) || !embeddings({
11110
- record: { ...emptyMessage, isDeleted: false },
11111
- embeddings: [embedding2]
11112
- }) || !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))
11113
- invalid();
11114
- const value = await request(
11115
- "/search",
11116
- {
11117
- method: "POST",
11118
- body: JSON.stringify({
11119
- account_id: accountId,
11120
- embedding: embedding2.slice(0, storedDims),
11121
- limit,
11122
- ...kindsFilter ? { kinds: kindsFilter } : {},
11123
- ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
11124
- ...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
11125
- ...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
11126
- })
11127
- },
11128
- options2?.signal
11129
- );
11130
- if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
11131
- const hits = [];
11132
- for (const item of value.items) {
11133
- if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
11134
- invalid();
11135
- const snapshot = await decode(item);
11136
- if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId || snapshot.record.conversationId === options2?.excludeConversationId)
11137
- invalid();
11138
- hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
11139
- }
11140
- options2?.signal?.throwIfAborted();
11141
- return hits;
11142
- },
11143
- async deleteAll(signal) {
11144
- const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
11145
- if (!object(value) || !integer(value.deleted)) invalid();
11146
- return value.deleted;
11147
- },
11148
- attachments: {
11149
- async create(sizeBytes, signal) {
11150
- if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
11151
- const value = await request(
11152
- "/attachments",
11153
- {
11154
- method: "POST",
11155
- body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
11156
- },
11157
- signal
11158
- );
11159
- if (!object(value)) invalid();
11160
- const created = attachment(value.attachment);
11161
- if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
11162
- return { attachment: created, upload: presigned(value.upload) };
11163
- },
11164
- async commit(attachmentId, owner, signal) {
11165
- if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
11166
- invalid();
11167
- const value = await request(
11168
- `/attachments/${attachmentId}/commit`,
11169
- {
11170
- method: "POST",
11171
- body: JSON.stringify({
11172
- account_id: accountId,
11173
- owner_kind: owner.kind,
11174
- owner_id: owner.id
11175
- })
11176
- },
11177
- signal
11178
- );
11179
- if (!object(value)) invalid();
11180
- const committed = attachment(value.attachment);
11181
- if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
11182
- invalid();
11183
- return committed;
11184
- },
11185
- async get(attachmentId, signal) {
11186
- if (!attachmentIdPattern.test(attachmentId)) invalid();
11187
- let value;
11188
- try {
11189
- value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
11190
- } catch (error) {
11191
- if (error instanceof ChatStoreError && error.status === 404) return null;
11192
- throw error;
11193
- }
11194
- if (!object(value)) invalid();
11195
- const found = attachment(value.attachment);
11196
- if (found.id !== attachmentId) invalid();
11197
- return {
11198
- attachment: found,
11199
- ...value.download !== void 0 ? { download: presigned(value.download) } : {}
11200
- };
11201
- },
11202
- async delete(attachmentId, signal) {
11203
- if (!attachmentIdPattern.test(attachmentId)) invalid();
11204
- await request(
11205
- `/attachments/${attachmentId}?account_id=${accountId}`,
11206
- { method: "DELETE" },
11207
- signal
11208
- );
11209
- }
11210
- }
11211
- };
11212
- }
11213
- var emptyMessage = {
11214
- kind: "message",
11215
- id: "query",
11216
- conversationId: "query",
11217
- sortKey: 0,
11218
- createdAt: 1,
11219
- updatedAt: 1,
11220
- isDeleted: false,
11221
- data: {}
11222
- };
11223
-
11224
- // src/lib/chatStore/vaultRecords.ts
11225
- var PINNED_SORT_BASE = 2 ** 51;
11226
- var recordBudgetBytes = 104e4;
11227
- var storedDims2 = 1536;
11228
- var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
11229
- var maxChunks = 16;
11230
- var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
11231
- var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
11232
- var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
11233
- function plain(value) {
11234
- return JSON.parse(JSON.stringify(value ?? {}));
11235
- }
11236
- function text5(value) {
11237
- return typeof value === "string" ? value : void 0;
11238
- }
11239
- function number(value) {
11240
- return typeof value === "number" ? value : void 0;
11241
- }
11242
- function conversationSortKey(data, createdAt) {
11243
- const pinnedAt = number(data.pinnedAt);
11244
- if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
11245
- return number(data.lastActivityAt) ?? createdAt;
11246
- }
11247
- function toConversation(record2) {
11248
- const pinnedAt = number(record2.data.pinnedAt);
11249
- const projectId = text5(record2.data.projectId);
11250
- return {
11251
- uniqueId: record2.id,
11252
- conversationId: record2.id,
11253
- title: text5(record2.data.title) ?? "",
11254
- ...projectId ? { projectId } : {},
11255
- createdAt: new Date(record2.createdAt),
11256
- updatedAt: new Date(record2.updatedAt),
11257
- isDeleted: record2.isDeleted,
11258
- pinnedAt: pinnedAt ? new Date(pinnedAt) : null
11259
- };
11260
- }
11261
- function messageData(options) {
11262
- return plain(
11263
- Object.fromEntries(
11264
- Object.entries(options).filter(
11265
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
11266
- )
11267
- )
11268
- );
11269
- }
11270
- function toMessage(record2) {
11271
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
11272
- return {
11273
- ...fields,
11274
- uniqueId: record2.id,
11275
- messageId: record2.sortKey,
11276
- conversationId: record2.conversationId,
11277
- createdAt: new Date(record2.createdAt),
11278
- updatedAt: new Date(record2.updatedAt)
11279
- };
11280
- }
11281
- function chunkOffsets(record2) {
11282
- const offsets = record2.data.chunkOffsets;
11283
- return Array.isArray(offsets) ? offsets : void 0;
11284
- }
11285
- function toSkeletons(records) {
11286
- const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
11287
- return records.map((r) => {
11288
- const parentMessageId = text5(r.data.parentMessageId);
11289
- const model = text5(r.data.model);
11290
- const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
11291
- return {
11292
- uniqueId: r.id,
11293
- messageId: r.sortKey,
11294
- conversationId: r.conversationId,
11295
- role: text5(r.data.role) ?? "",
11296
- createdAt: new Date(r.createdAt),
11297
- ...parentMessageId ? { parentMessageId } : {},
11298
- ...model ? { model } : {},
11299
- ...artifact ? { content: text5(r.data.content) ?? "" } : {}
11300
- };
11301
- });
11302
- }
11303
- function toSummary(record2) {
11304
- return {
11305
- uniqueId: record2.id,
11306
- conversationId: record2.id,
11307
- summary: text5(record2.data.summary) ?? "",
11308
- summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
11309
- tokenCount: number(record2.data.tokenCount) ?? 0,
11310
- createdAt: new Date(record2.createdAt),
11311
- updatedAt: new Date(record2.updatedAt)
11312
- };
11313
- }
11314
- function links(data) {
11315
- return Array.isArray(data.links) ? data.links : [];
11316
- }
11317
- function applyLinkOps(data, ops) {
11318
- let current = links(data);
11319
- for (const op of ops) {
11320
- if ("clear" in op) {
11321
- current = [];
11322
- continue;
11323
- }
11324
- const byId = new Map(current.map((l) => [l.memoryId, l]));
11325
- const turn = /* @__PURE__ */ new Set();
11326
- op.add.forEach((item, i) => {
11327
- if (!item.memoryId || turn.has(item.memoryId)) return;
11328
- turn.add(item.memoryId);
11329
- const known = byId.get(item.memoryId);
11330
- if (known && known.createdAt >= op.at + i) return;
11331
- byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
11332
- });
11333
- current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
11334
- }
11335
- return plain({ links: current });
11336
- }
11337
- function toLinks(record2) {
11338
- return links(record2.data).map((l) => ({
11339
- uniqueId: `${record2.id}:${l.memoryId}`,
11340
- conversationId: record2.id,
11341
- memoryId: l.memoryId,
11342
- score: l.score,
11343
- createdAt: new Date(l.createdAt)
11344
- }));
11345
- }
11346
- function bytes(value) {
11347
- return new TextEncoder().encode(JSON.stringify(value)).length;
11348
- }
11349
- function fitRecord(record2) {
11350
- if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
11351
- const data = { ...record2.data };
11352
- const truncated = [];
11353
- for (const field10 of droppable) {
11354
- if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
11355
- if (data[field10] === void 0) continue;
11356
- delete data[field10];
11357
- truncated.push(field10);
11358
- }
11359
- const content = text5(data.content) ?? "";
11360
- const over = bytes({ ...record2, data }) - recordBudgetBytes;
11361
- if (over > 0) {
11362
- const encoded = new TextEncoder().encode(content);
11363
- data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
11364
- truncated.push("content");
11365
- }
11366
- return { ...record2, data: { ...data, truncated } };
11367
- }
11368
- function acceptedVector(vector2) {
11369
- if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
11370
- if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
11371
- return void 0;
11372
- return [...vector2];
11373
- }
11374
- function normalized(vector2) {
11375
- const norm = Math.hypot(...vector2) || 1;
11376
- return vector2.map((x) => x / norm);
11377
- }
11378
- function fitChunks(chunks3) {
11379
- const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
11380
- if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
11381
- if (usable.length <= maxChunks) return usable;
11382
- const out = [];
11383
- for (let g = 0; g < maxChunks; g++) {
11384
- const group = usable.slice(
11385
- Math.floor(g * usable.length / maxChunks),
11386
- Math.floor((g + 1) * usable.length / maxChunks)
11387
- );
11388
- const dims = group[0].vector.length;
11389
- const mean = new Array(dims).fill(0);
11390
- for (const c of group) {
11391
- const unit = normalized(c.vector);
11392
- for (let d = 0; d < dims; d++) mean[d] += unit[d];
11363
+ id: checked.id,
11364
+ updated_at: r.updatedAt,
11365
+ is_deleted: r.isDeleted
11366
+ };
11367
+ });
11368
+ if (wireRevisions.length === 0) return [];
11369
+ const value = await request(
11370
+ "/verify",
11371
+ {
11372
+ method: "POST",
11373
+ body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
11374
+ },
11375
+ signal
11376
+ );
11377
+ if (!object(value) || !Array.isArray(value.missing)) invalid();
11378
+ const missing2 = value.missing.map(ref);
11379
+ if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
11380
+ return missing2;
11381
+ },
11382
+ async activate(signal) {
11383
+ const value = await request(
11384
+ "/account",
11385
+ { method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
11386
+ signal
11387
+ );
11388
+ if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
11389
+ invalid();
11390
+ return value.transitioned;
11391
+ },
11392
+ async changes(cursor, options2) {
11393
+ const limit = options2?.limit ?? 100;
11394
+ if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
11395
+ invalid();
11396
+ const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
11397
+ if (cursor) params.set("cursor", cursor);
11398
+ const value = await request(`/changes?${params}`, {}, options2?.signal);
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))
11400
+ invalid();
11401
+ const items = [];
11402
+ for (const item of value.items) items.push(await decode(item));
11403
+ options2?.signal?.throwIfAborted();
11404
+ return {
11405
+ items,
11406
+ ...value.next_cursor ? { nextCursor: value.next_cursor } : {},
11407
+ changesCursor: value.changes_cursor ?? cursor ?? ""
11408
+ };
11409
+ },
11410
+ async search(embedding2, options2) {
11411
+ const limit = options2?.limit ?? 20;
11412
+ const kindsFilter = options2?.kinds;
11413
+ if (!Array.isArray(embedding2) || !embeddings({
11414
+ record: { ...emptyMessage, isDeleted: false },
11415
+ embeddings: [embedding2]
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))
11417
+ invalid();
11418
+ const value = await request(
11419
+ "/search",
11420
+ {
11421
+ method: "POST",
11422
+ body: JSON.stringify({
11423
+ account_id: accountId,
11424
+ embedding: embedding2.slice(0, storedDims2),
11425
+ limit,
11426
+ ...kindsFilter ? { kinds: kindsFilter } : {},
11427
+ ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
11428
+ ...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
11429
+ ...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
11430
+ })
11431
+ },
11432
+ options2?.signal
11433
+ );
11434
+ if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
11435
+ const hits = [];
11436
+ for (const item of value.items) {
11437
+ if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
11438
+ invalid();
11439
+ const snapshot = await decode(item);
11440
+ if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId || snapshot.record.conversationId === options2?.excludeConversationId)
11441
+ invalid();
11442
+ hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
11443
+ }
11444
+ options2?.signal?.throwIfAborted();
11445
+ return hits;
11446
+ },
11447
+ async deleteAll(signal) {
11448
+ const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
11449
+ if (!object(value) || !integer(value.deleted)) invalid();
11450
+ return value.deleted;
11451
+ },
11452
+ attachments: {
11453
+ async create(sizeBytes, signal) {
11454
+ if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
11455
+ const value = await request(
11456
+ "/attachments",
11457
+ {
11458
+ method: "POST",
11459
+ body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
11460
+ },
11461
+ signal
11462
+ );
11463
+ if (!object(value)) invalid();
11464
+ const created = attachment(value.attachment);
11465
+ if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
11466
+ return { attachment: created, upload: presigned(value.upload) };
11467
+ },
11468
+ async commit(attachmentId, owner, signal) {
11469
+ if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
11470
+ invalid();
11471
+ const value = await request(
11472
+ `/attachments/${attachmentId}/commit`,
11473
+ {
11474
+ method: "POST",
11475
+ body: JSON.stringify({
11476
+ account_id: accountId,
11477
+ owner_kind: owner.kind,
11478
+ owner_id: owner.id
11479
+ })
11480
+ },
11481
+ signal
11482
+ );
11483
+ if (!object(value)) invalid();
11484
+ const committed = attachment(value.attachment);
11485
+ if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
11486
+ invalid();
11487
+ return committed;
11488
+ },
11489
+ async get(attachmentId, signal) {
11490
+ if (!attachmentIdPattern.test(attachmentId)) invalid();
11491
+ let value;
11492
+ try {
11493
+ value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
11494
+ } catch (error) {
11495
+ if (error instanceof ChatStoreError && error.status === 404) return null;
11496
+ throw error;
11497
+ }
11498
+ if (!object(value)) invalid();
11499
+ const found = attachment(value.attachment);
11500
+ if (found.id !== attachmentId) invalid();
11501
+ return {
11502
+ attachment: found,
11503
+ ...value.download !== void 0 ? { download: presigned(value.download) } : {}
11504
+ };
11505
+ },
11506
+ async delete(attachmentId, signal) {
11507
+ if (!attachmentIdPattern.test(attachmentId)) invalid();
11508
+ await request(
11509
+ `/attachments/${attachmentId}?account_id=${accountId}`,
11510
+ { method: "DELETE" },
11511
+ signal
11512
+ );
11513
+ }
11393
11514
  }
11394
- out.push({
11395
- vector: normalized(mean),
11396
- startOffset: group[0].startOffset,
11397
- endOffset: group[group.length - 1].endOffset
11398
- });
11399
- }
11400
- return out;
11515
+ };
11401
11516
  }
11517
+ var emptyMessage = {
11518
+ kind: "message",
11519
+ id: "query",
11520
+ conversationId: "query",
11521
+ sortKey: 0,
11522
+ createdAt: 1,
11523
+ updatedAt: 1,
11524
+ isDeleted: false,
11525
+ data: {}
11526
+ };
11402
11527
 
11403
11528
  // src/lib/chatStore/migrateChats.ts
11404
11529
  var maxPasses = 5;
11405
11530
  var verifyBatch = 1e3;
11406
- var importBatch = 100;
11407
- var importChunks = 200;
11408
- var importPlaintextBytes = 39e5;
11409
11531
  var writeBatch = 25;
11410
11532
  function key(record2) {
11411
11533
  return `${record2.kind}/${record2.id}`;
11412
11534
  }
11413
- function ms(date10, fallback = 1) {
11414
- const value = date10?.getTime();
11415
- return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
11416
- }
11417
11535
  function sealed(value) {
11418
11536
  if (typeof value === "string") return isEncrypted(value);
11419
11537
  if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
@@ -11421,42 +11539,6 @@ function sealed(value) {
11421
11539
  return Object.values(value).some(sealed);
11422
11540
  return false;
11423
11541
  }
11424
- function bytes2(value) {
11425
- return new TextEncoder().encode(JSON.stringify(value)).length;
11426
- }
11427
- function messageRecord(message) {
11428
- const {
11429
- uniqueId: _uniqueId,
11430
- messageId: _messageId,
11431
- createdAt: _createdAt,
11432
- updatedAt: _updatedAt,
11433
- decryptionStatus: _status,
11434
- chunks: chunks3,
11435
- vector: vector2,
11436
- ...fields
11437
- } = message;
11438
- const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
11439
- const single = fitted ? void 0 : acceptedVector(vector2);
11440
- const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
11441
- const record2 = fitRecord({
11442
- kind: "message",
11443
- id: message.uniqueId,
11444
- conversationId: message.conversationId,
11445
- sortKey: message.messageId,
11446
- createdAt: ms(message.createdAt),
11447
- updatedAt: ms(message.updatedAt, ms(message.createdAt)),
11448
- isDeleted: false,
11449
- data: {
11450
- ...messageData(fields),
11451
- ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
11452
- }
11453
- });
11454
- return {
11455
- record: record2,
11456
- ...embeddings2 ? { embeddings: embeddings2 } : {},
11457
- ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
11458
- };
11459
- }
11460
11542
  async function readLocal(options) {
11461
11543
  const { database } = options;
11462
11544
  const ctx = {
@@ -11467,7 +11549,7 @@ async function readLocal(options) {
11467
11549
  signMessage: options.signMessage,
11468
11550
  embeddedWalletSigner: options.embeddedWalletSigner
11469
11551
  };
11470
- const summaries = createSummaryContext(database);
11552
+ const summaries = createSummaryContext(database, ctx);
11471
11553
  const memory = {
11472
11554
  database,
11473
11555
  conversationMemoryCollection: database.get(ConversationMemory.table)
@@ -11510,29 +11592,10 @@ async function readLocal(options) {
11510
11592
  const messages = await getMessagesOp(ctx, conversationId);
11511
11593
  const unreadableTitle = isEncrypted(conversation.title);
11512
11594
  if (unreadableTitle) out.untitled++;
11513
- const createdAt = ms(conversation.createdAt);
11514
- const data = plain({
11515
- title: unreadableTitle ? "" : conversation.title,
11516
- projectId: conversation.projectId || void 0,
11517
- pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
11518
- lastActivityAt: Math.max(
11519
- ms(conversation.updatedAt, createdAt),
11520
- ...messages.map((m) => ms(m.createdAt))
11521
- )
11522
- });
11523
11595
  out.conversations++;
11524
- out.records.push({
11525
- record: {
11526
- kind: "conversation",
11527
- id: conversationId,
11528
- conversationId: "",
11529
- sortKey: conversationSortKey(data, createdAt),
11530
- createdAt,
11531
- updatedAt: ms(conversation.updatedAt, createdAt),
11532
- isDeleted: false,
11533
- data
11534
- }
11535
- });
11596
+ out.records.push(
11597
+ conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
11598
+ );
11536
11599
  for (const message of messages) {
11537
11600
  if (message.decryptionStatus || sealed(message)) {
11538
11601
  skip("message", message.uniqueId, "unreadable");
@@ -11548,7 +11611,9 @@ async function readLocal(options) {
11548
11611
  out.records.push(prepared);
11549
11612
  }
11550
11613
  const summary = await getConversationSummaryOp(summaries, conversationId);
11551
- if (summary)
11614
+ if (summary && isEncrypted(summary.summary)) {
11615
+ skip("summary", conversationId, "unreadable");
11616
+ } else if (summary)
11552
11617
  out.records.push({
11553
11618
  record: {
11554
11619
  kind: "summary",
@@ -11651,27 +11716,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
11651
11716
  };
11652
11717
  });
11653
11718
  }
11654
- function batches(records) {
11655
- const out = [];
11656
- let batch = [];
11657
- let chunks3 = 0;
11658
- let size = 0;
11659
- for (const item of records) {
11660
- const vectors = item.embeddings?.length ?? 0;
11661
- const itemSize = bytes2(item.record);
11662
- if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
11663
- out.push(batch);
11664
- batch = [];
11665
- chunks3 = 0;
11666
- size = 0;
11667
- }
11668
- batch.push(item);
11669
- chunks3 += vectors;
11670
- size += itemSize;
11671
- }
11672
- if (batch.length) out.push(batch);
11673
- return out;
11674
- }
11675
11719
  function fitVectors(records, available2, unembedded) {
11676
11720
  let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
11677
11721
  if (total <= available2) return records;
@@ -12752,6 +12796,45 @@ function createVaultChatBackend(options) {
12752
12796
  },
12753
12797
  flush,
12754
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
+ },
12755
12838
  status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
12756
12839
  close() {
12757
12840
  closed = true;
@@ -27274,11 +27357,14 @@ var WatermelonChatStorageAdapter = class {
27274
27357
  return searchChunksOp(this.ctx, queryVector, options);
27275
27358
  }
27276
27359
  getSummary(conversationId) {
27277
- return getConversationSummaryOp(createSummaryContext(this.ctx.database), conversationId);
27360
+ return getConversationSummaryOp(
27361
+ createSummaryContext(this.ctx.database, this.ctx),
27362
+ conversationId
27363
+ );
27278
27364
  }
27279
27365
  upsertSummary(conversationId, summary, summarizedUpTo, tokenCount) {
27280
27366
  return upsertConversationSummaryOp(
27281
- createSummaryContext(this.ctx.database),
27367
+ createSummaryContext(this.ctx.database, this.ctx),
27282
27368
  conversationId,
27283
27369
  summary,
27284
27370
  summarizedUpTo,
@@ -29413,7 +29499,7 @@ async function summarizeHistoryAtRevision(options, revision2) {
29413
29499
  const cachedSummary = await summaryStore(options).getSummary(conversationId);
29414
29500
  return {
29415
29501
  messagesToConvert: messages,
29416
- summarySystemMessage: cachedSummary?.summary ? summaryToSystemMessage(cachedSummary.summary) : null
29502
+ summarySystemMessage: cachedSummary?.summary && !isEncrypted(cachedSummary.summary) ? summaryToSystemMessage(cachedSummary.summary) : null
29417
29503
  };
29418
29504
  } catch {
29419
29505
  return { messagesToConvert: messages, summarySystemMessage: null };
@@ -29468,14 +29554,15 @@ async function doSummarizeHistory(options, revision2) {
29468
29554
  } = options;
29469
29555
  try {
29470
29556
  const summaries = summaryStore(options);
29471
- const persistSummary = (summary, summarizedUpTo, tokenCount) => database.write(async (writer) => {
29557
+ const persistSummary = (summary, summarizedUpTo, tokenCount) => {
29472
29558
  assertConversationRevision(database, conversationId, revision2);
29473
- await writer.callWriter(
29474
- () => summaries.upsertSummary(conversationId, summary, summarizedUpTo, tokenCount)
29475
- );
29476
- });
29559
+ return summaries.upsertSummary(conversationId, summary, summarizedUpTo, tokenCount);
29560
+ };
29477
29561
  let cachedSummary = await summaries.getSummary(conversationId);
29478
29562
  assertConversationRevision(database, conversationId, revision2);
29563
+ if (cachedSummary && isEncrypted(cachedSummary.summary)) {
29564
+ throw new Error("The cached summary could not be decrypted");
29565
+ }
29479
29566
  const lastCompacted = lastCompactionTime.get(conversationId) ?? 0;
29480
29567
  const compactionCooledDown = Date.now() - lastCompacted > COMPACTION_COOLDOWN_MS;
29481
29568
  if (cachedSummary && cachedSummary.tokenCount > summaryTokenThreshold * MAX_SUMMARY_TOKEN_RATIO && compactionCooledDown) {