@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.
@@ -12204,17 +12204,19 @@ function createWebSearchPreProcessor(options = {}) {
12204
12204
 
12205
12205
  // src/lib/db/chat/summaryOperations.ts
12206
12206
  var import_watermelondb5 = require("@nozbe/watermelondb");
12207
- function createSummaryContext(database) {
12207
+ init_logger();
12208
+ function createSummaryContext(database, encryption = {}) {
12208
12209
  return {
12210
+ ...encryption,
12209
12211
  database,
12210
12212
  summariesCollection: database.get("conversation_summaries")
12211
12213
  };
12212
12214
  }
12213
- function modelToStored(record2) {
12215
+ function modelToStored(record2, summary) {
12214
12216
  return {
12215
12217
  uniqueId: record2.id,
12216
12218
  conversationId: record2.conversationId,
12217
- summary: record2.summary,
12219
+ summary,
12218
12220
  summarizedUpTo: record2.summarizedUpTo,
12219
12221
  tokenCount: record2.tokenCount,
12220
12222
  createdAt: record2.createdAt,
@@ -12224,28 +12226,62 @@ function modelToStored(record2) {
12224
12226
  async function getConversationSummaryOp(ctx, conversationId) {
12225
12227
  const results = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
12226
12228
  if (results.length === 0) return null;
12227
- return modelToStored(results[0]);
12229
+ const record2 = results[0];
12230
+ const stored2 = modelToStored(record2, record2.summary);
12231
+ if (ctx.walletAddress && isEncrypted(stored2.summary)) {
12232
+ if (ctx.signMessage) {
12233
+ try {
12234
+ await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
12235
+ } catch (error) {
12236
+ getLogger().warn("Failed to request the encryption key for the summary:", error);
12237
+ }
12238
+ }
12239
+ stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
12240
+ } else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
12241
+ try {
12242
+ const encryptedSummary = await encryptField(
12243
+ stored2.summary,
12244
+ ctx.walletAddress,
12245
+ ctx.signMessage,
12246
+ ctx.embeddedWalletSigner
12247
+ );
12248
+ await ctx.database.write(async () => {
12249
+ const current = await ctx.summariesCollection.query(import_watermelondb5.Q.where("id", record2.id)).fetch();
12250
+ if (current[0]?.summary === stored2.summary) {
12251
+ await current[0].update((rec) => {
12252
+ rec.summary = encryptedSummary;
12253
+ });
12254
+ }
12255
+ });
12256
+ } catch (error) {
12257
+ getLogger().warn("Failed to encrypt the legacy summary:", error);
12258
+ }
12259
+ }
12260
+ return stored2;
12228
12261
  }
12229
12262
  async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
12263
+ const revision2 = getConversationRevision(ctx.database, conversationId);
12230
12264
  let record2;
12265
+ const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
12231
12266
  await ctx.database.write(async () => {
12267
+ assertConversationRevision(ctx.database, conversationId, revision2);
12232
12268
  const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
12233
12269
  if (existing.length > 0) {
12234
12270
  record2 = await existing[0].update((rec) => {
12235
- rec.summary = summary;
12271
+ rec.summary = encryptedSummary;
12236
12272
  rec.summarizedUpTo = summarizedUpTo;
12237
12273
  rec.tokenCount = tokenCount;
12238
12274
  });
12239
12275
  } else {
12240
12276
  record2 = await ctx.summariesCollection.create((rec) => {
12241
12277
  rec.conversationId = conversationId;
12242
- rec.summary = summary;
12278
+ rec.summary = encryptedSummary;
12243
12279
  rec.summarizedUpTo = summarizedUpTo;
12244
12280
  rec.tokenCount = tokenCount;
12245
12281
  });
12246
12282
  }
12247
12283
  });
12248
- return modelToStored(record2);
12284
+ return modelToStored(record2, summary);
12249
12285
  }
12250
12286
  async function deleteConversationSummaryOp(ctx, conversationId) {
12251
12287
  await ctx.database.write(async () => {
@@ -12367,94 +12403,363 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
12367
12403
  });
12368
12404
  }
12369
12405
 
12370
- // src/lib/memory/store/remotePersistence.ts
12371
- init_portalLlm();
12372
-
12373
- // src/lib/db/entities/types.ts
12374
- var ENTITY_KINDS = [
12375
- "person",
12376
- "organization",
12377
- "place",
12378
- "event",
12379
- "product",
12380
- "thing",
12381
- "concept",
12382
- "other"
12383
- ];
12384
- function normalizeEntityName(name) {
12385
- return name.trim().toLowerCase();
12406
+ // src/lib/chatStore/vaultRecords.ts
12407
+ var PINNED_SORT_BASE = 2 ** 51;
12408
+ var recordBudgetBytes = 104e4;
12409
+ var storedDims = 1536;
12410
+ var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
12411
+ var maxChunks = 16;
12412
+ var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
12413
+ var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
12414
+ var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
12415
+ function plain(value) {
12416
+ return JSON.parse(JSON.stringify(value ?? {}));
12386
12417
  }
12387
- var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
12388
- function topicWeight(topic2) {
12389
- return topic2.source === "user" ? 1 : topic2.weight ?? 1;
12418
+ function text4(value) {
12419
+ return typeof value === "string" ? value : void 0;
12390
12420
  }
12391
- function primaryTopic(topics) {
12392
- let best = null;
12393
- for (const topic2 of topics ?? []) {
12394
- if (best === null || topicWeight(topic2) > topicWeight(best)) best = topic2;
12421
+ function number(value) {
12422
+ return typeof value === "number" ? value : void 0;
12423
+ }
12424
+ function conversationSortKey(data, createdAt) {
12425
+ const pinnedAt = number(data.pinnedAt);
12426
+ if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
12427
+ return number(data.lastActivityAt) ?? createdAt;
12428
+ }
12429
+ function toConversation(record2) {
12430
+ const pinnedAt = number(record2.data.pinnedAt);
12431
+ const projectId = text4(record2.data.projectId);
12432
+ return {
12433
+ uniqueId: record2.id,
12434
+ conversationId: record2.id,
12435
+ title: text4(record2.data.title) ?? "",
12436
+ ...projectId ? { projectId } : {},
12437
+ createdAt: new Date(record2.createdAt),
12438
+ updatedAt: new Date(record2.updatedAt),
12439
+ isDeleted: record2.isDeleted,
12440
+ pinnedAt: pinnedAt ? new Date(pinnedAt) : null
12441
+ };
12442
+ }
12443
+ function messageData(options) {
12444
+ return plain(
12445
+ Object.fromEntries(
12446
+ Object.entries(options).filter(
12447
+ ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
12448
+ )
12449
+ )
12450
+ );
12451
+ }
12452
+ function toMessage(record2) {
12453
+ const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
12454
+ return {
12455
+ ...fields,
12456
+ uniqueId: record2.id,
12457
+ messageId: record2.sortKey,
12458
+ conversationId: record2.conversationId,
12459
+ createdAt: new Date(record2.createdAt),
12460
+ updatedAt: new Date(record2.updatedAt)
12461
+ };
12462
+ }
12463
+ function chunkOffsets(record2) {
12464
+ const offsets = record2.data.chunkOffsets;
12465
+ return Array.isArray(offsets) ? offsets : void 0;
12466
+ }
12467
+ function toSkeletons(records) {
12468
+ const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
12469
+ return records.map((r) => {
12470
+ const parentMessageId = text4(r.data.parentMessageId);
12471
+ const model = text4(r.data.model);
12472
+ const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
12473
+ return {
12474
+ uniqueId: r.id,
12475
+ messageId: r.sortKey,
12476
+ conversationId: r.conversationId,
12477
+ role: text4(r.data.role) ?? "",
12478
+ createdAt: new Date(r.createdAt),
12479
+ ...parentMessageId ? { parentMessageId } : {},
12480
+ ...model ? { model } : {},
12481
+ ...artifact ? { content: text4(r.data.content) ?? "" } : {}
12482
+ };
12483
+ });
12484
+ }
12485
+ function toSummary(record2) {
12486
+ return {
12487
+ uniqueId: record2.id,
12488
+ conversationId: record2.id,
12489
+ summary: text4(record2.data.summary) ?? "",
12490
+ summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
12491
+ tokenCount: number(record2.data.tokenCount) ?? 0,
12492
+ createdAt: new Date(record2.createdAt),
12493
+ updatedAt: new Date(record2.updatedAt)
12494
+ };
12495
+ }
12496
+ function links(data) {
12497
+ return Array.isArray(data.links) ? data.links : [];
12498
+ }
12499
+ function applyLinkOps(data, ops) {
12500
+ let current = links(data);
12501
+ for (const op of ops) {
12502
+ if ("clear" in op) {
12503
+ current = [];
12504
+ continue;
12505
+ }
12506
+ const byId = new Map(current.map((l) => [l.memoryId, l]));
12507
+ const turn = /* @__PURE__ */ new Set();
12508
+ op.add.forEach((item, i) => {
12509
+ if (!item.memoryId || turn.has(item.memoryId)) return;
12510
+ turn.add(item.memoryId);
12511
+ const known = byId.get(item.memoryId);
12512
+ if (known && known.createdAt >= op.at + i) return;
12513
+ byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
12514
+ });
12515
+ current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
12395
12516
  }
12396
- return best;
12517
+ return plain({ links: current });
12397
12518
  }
12398
- function parseTopicWeight(value) {
12399
- return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
12519
+ function toLinks(record2) {
12520
+ return links(record2.data).map((l) => ({
12521
+ uniqueId: `${record2.id}:${l.memoryId}`,
12522
+ conversationId: record2.id,
12523
+ memoryId: l.memoryId,
12524
+ score: l.score,
12525
+ createdAt: new Date(l.createdAt)
12526
+ }));
12400
12527
  }
12401
- function serializeTopics(topics) {
12402
- return JSON.stringify(topics);
12528
+ function bytes(value) {
12529
+ return new TextEncoder().encode(JSON.stringify(value)).length;
12403
12530
  }
12404
- function parseTopics(value) {
12405
- if (typeof value !== "string" || value.length === 0) return null;
12406
- let parsed;
12407
- try {
12408
- parsed = JSON.parse(value);
12409
- } catch {
12410
- return null;
12531
+ function fitRecord(record2) {
12532
+ if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
12533
+ const data = { ...record2.data };
12534
+ const truncated = [];
12535
+ for (const field10 of droppable) {
12536
+ if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
12537
+ if (data[field10] === void 0) continue;
12538
+ delete data[field10];
12539
+ truncated.push(field10);
12411
12540
  }
12412
- if (!Array.isArray(parsed)) return null;
12541
+ const content = text4(data.content) ?? "";
12542
+ const over = bytes({ ...record2, data }) - recordBudgetBytes;
12543
+ if (over > 0) {
12544
+ const encoded = new TextEncoder().encode(content);
12545
+ data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
12546
+ truncated.push("content");
12547
+ }
12548
+ return { ...record2, data: { ...data, truncated } };
12549
+ }
12550
+ function acceptedVector(vector2) {
12551
+ if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
12552
+ if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims).some((x) => x !== 0))
12553
+ return void 0;
12554
+ return [...vector2];
12555
+ }
12556
+ function normalized(vector2) {
12557
+ const norm = Math.hypot(...vector2) || 1;
12558
+ return vector2.map((x) => x / norm);
12559
+ }
12560
+ function fitChunks(chunks3) {
12561
+ const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
12562
+ if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
12563
+ if (usable.length <= maxChunks) return usable;
12413
12564
  const out = [];
12414
- for (const raw of parsed) {
12415
- if (typeof raw !== "object" || raw === null) continue;
12416
- const { name, kind, source, weight } = raw;
12417
- if (typeof name !== "string" || name.trim().length === 0) continue;
12418
- const parsedWeight = parseTopicWeight(weight);
12565
+ for (let g = 0; g < maxChunks; g++) {
12566
+ const group = usable.slice(
12567
+ Math.floor(g * usable.length / maxChunks),
12568
+ Math.floor((g + 1) * usable.length / maxChunks)
12569
+ );
12570
+ const dims = group[0].vector.length;
12571
+ const mean = new Array(dims).fill(0);
12572
+ for (const c of group) {
12573
+ const unit = normalized(c.vector);
12574
+ for (let d = 0; d < dims; d++) mean[d] += unit[d];
12575
+ }
12419
12576
  out.push({
12420
- name,
12421
- ...typeof kind === "string" && kind.length > 0 ? { kind } : {},
12422
- source: source === "user" ? "user" : "auto",
12423
- ...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
12577
+ vector: normalized(mean),
12578
+ startOffset: group[0].startOffset,
12579
+ endOffset: group[group.length - 1].endOffset
12424
12580
  });
12425
12581
  }
12426
12582
  return out;
12427
12583
  }
12428
12584
 
12429
- // src/lib/memory/store/remoteTopics.ts
12430
- function topic(value) {
12431
- const t = value;
12432
- 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")
12433
- throw new Error("Invalid nearby topic");
12434
- return t;
12585
+ // src/lib/chatStore/chatImports.ts
12586
+ var importBatch = 100;
12587
+ var importChunks = 200;
12588
+ var importPlaintextBytes = 39e5;
12589
+ function ms(date10, fallback = 1) {
12590
+ const value = date10?.getTime();
12591
+ return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
12435
12592
  }
12436
- function createRemoteTopicPersistence(request) {
12593
+ function bytes2(value) {
12594
+ return new TextEncoder().encode(JSON.stringify(value)).length;
12595
+ }
12596
+ function conversationRecord(conversation, messages) {
12597
+ const createdAt = ms(conversation.createdAt);
12598
+ const data = plain({
12599
+ title: conversation.title,
12600
+ projectId: conversation.projectId || void 0,
12601
+ pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
12602
+ lastActivityAt: Math.max(
12603
+ ms(conversation.updatedAt, createdAt),
12604
+ ...messages.map((m) => ms(m.createdAt))
12605
+ )
12606
+ });
12437
12607
  return {
12438
- topics: async () => {
12439
- const out = [];
12440
- let cursor;
12441
- do {
12442
- const page = await request(
12443
- "/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
12444
- {}
12445
- );
12446
- if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
12447
- throw new Error("Invalid nearby topic page");
12448
- out.push(...page.items.map(topic));
12449
- cursor = page.next_cursor;
12450
- } while (cursor);
12451
- return out;
12452
- },
12453
- putTopic: async (value, expectedVersion) => {
12454
- if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
12455
- throw new Error("Expected topic version must be a nonnegative integer");
12456
- return topic(
12457
- await request("/topics", {
12608
+ record: {
12609
+ kind: "conversation",
12610
+ id: conversation.conversationId,
12611
+ conversationId: "",
12612
+ sortKey: conversationSortKey(data, createdAt),
12613
+ createdAt,
12614
+ updatedAt: ms(conversation.updatedAt, createdAt),
12615
+ isDeleted: false,
12616
+ data
12617
+ }
12618
+ };
12619
+ }
12620
+ function messageRecord(message) {
12621
+ const {
12622
+ uniqueId: _uniqueId,
12623
+ messageId: _messageId,
12624
+ createdAt: _createdAt,
12625
+ updatedAt: _updatedAt,
12626
+ decryptionStatus: _status,
12627
+ chunks: chunks3,
12628
+ vector: vector2,
12629
+ ...fields
12630
+ } = message;
12631
+ const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
12632
+ const single = fitted ? void 0 : acceptedVector(vector2);
12633
+ const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
12634
+ const record2 = fitRecord({
12635
+ kind: "message",
12636
+ id: message.uniqueId,
12637
+ conversationId: message.conversationId,
12638
+ sortKey: message.messageId,
12639
+ createdAt: ms(message.createdAt),
12640
+ updatedAt: ms(message.updatedAt, ms(message.createdAt)),
12641
+ isDeleted: false,
12642
+ data: {
12643
+ ...messageData(fields),
12644
+ ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
12645
+ }
12646
+ });
12647
+ return {
12648
+ record: record2,
12649
+ ...embeddings2 ? { embeddings: embeddings2 } : {},
12650
+ ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
12651
+ };
12652
+ }
12653
+ function batches(records) {
12654
+ const out = [];
12655
+ let batch = [];
12656
+ let chunks3 = 0;
12657
+ let size = 0;
12658
+ for (const item of records) {
12659
+ const vectors = item.embeddings?.length ?? 0;
12660
+ const itemSize = bytes2(item.record);
12661
+ if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
12662
+ out.push(batch);
12663
+ batch = [];
12664
+ chunks3 = 0;
12665
+ size = 0;
12666
+ }
12667
+ batch.push(item);
12668
+ chunks3 += vectors;
12669
+ size += itemSize;
12670
+ }
12671
+ if (batch.length) out.push(batch);
12672
+ return out;
12673
+ }
12674
+
12675
+ // src/lib/memory/store/remotePersistence.ts
12676
+ init_portalLlm();
12677
+
12678
+ // src/lib/db/entities/types.ts
12679
+ var ENTITY_KINDS = [
12680
+ "person",
12681
+ "organization",
12682
+ "place",
12683
+ "event",
12684
+ "product",
12685
+ "thing",
12686
+ "concept",
12687
+ "other"
12688
+ ];
12689
+ function normalizeEntityName(name) {
12690
+ return name.trim().toLowerCase();
12691
+ }
12692
+ var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
12693
+ function topicWeight(topic2) {
12694
+ return topic2.source === "user" ? 1 : topic2.weight ?? 1;
12695
+ }
12696
+ function primaryTopic(topics) {
12697
+ let best = null;
12698
+ for (const topic2 of topics ?? []) {
12699
+ if (best === null || topicWeight(topic2) > topicWeight(best)) best = topic2;
12700
+ }
12701
+ return best;
12702
+ }
12703
+ function parseTopicWeight(value) {
12704
+ return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
12705
+ }
12706
+ function serializeTopics(topics) {
12707
+ return JSON.stringify(topics);
12708
+ }
12709
+ function parseTopics(value) {
12710
+ if (typeof value !== "string" || value.length === 0) return null;
12711
+ let parsed;
12712
+ try {
12713
+ parsed = JSON.parse(value);
12714
+ } catch {
12715
+ return null;
12716
+ }
12717
+ if (!Array.isArray(parsed)) return null;
12718
+ const out = [];
12719
+ for (const raw of parsed) {
12720
+ if (typeof raw !== "object" || raw === null) continue;
12721
+ const { name, kind, source, weight } = raw;
12722
+ if (typeof name !== "string" || name.trim().length === 0) continue;
12723
+ const parsedWeight = parseTopicWeight(weight);
12724
+ out.push({
12725
+ name,
12726
+ ...typeof kind === "string" && kind.length > 0 ? { kind } : {},
12727
+ source: source === "user" ? "user" : "auto",
12728
+ ...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
12729
+ });
12730
+ }
12731
+ return out;
12732
+ }
12733
+
12734
+ // src/lib/memory/store/remoteTopics.ts
12735
+ function topic(value) {
12736
+ const t = value;
12737
+ 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")
12738
+ throw new Error("Invalid nearby topic");
12739
+ return t;
12740
+ }
12741
+ function createRemoteTopicPersistence(request) {
12742
+ return {
12743
+ topics: async () => {
12744
+ const out = [];
12745
+ let cursor;
12746
+ do {
12747
+ const page = await request(
12748
+ "/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
12749
+ {}
12750
+ );
12751
+ if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
12752
+ throw new Error("Invalid nearby topic page");
12753
+ out.push(...page.items.map(topic));
12754
+ cursor = page.next_cursor;
12755
+ } while (cursor);
12756
+ return out;
12757
+ },
12758
+ putTopic: async (value, expectedVersion) => {
12759
+ if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
12760
+ throw new Error("Expected topic version must be a nonnegative integer");
12761
+ return topic(
12762
+ await request("/topics", {
12458
12763
  method: "PUT",
12459
12764
  body: JSON.stringify({ topic: value, expected_version: expectedVersion })
12460
12765
  })
@@ -13109,7 +13414,7 @@ var ChatStoreError = class extends Error {
13109
13414
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
13110
13415
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
13111
13416
  var maxPayload = 2 * 1024 * 1024;
13112
- var storedDims = 1536;
13417
+ var storedDims2 = 1536;
13113
13418
  var maxRequestCiphertext = 8 * 1024 * 1024;
13114
13419
  var maxGetRefs = 50;
13115
13420
  var maxImportRecords = 100;
@@ -13177,24 +13482,24 @@ function vector(v) {
13177
13482
  for (let i = 0; i < v.length; i++) {
13178
13483
  const x = v[i];
13179
13484
  if (typeof x !== "number" || !Number.isFinite(x)) return false;
13180
- if (i < storedDims && x !== 0) nonZero = true;
13485
+ if (i < storedDims2 && x !== 0) nonZero = true;
13181
13486
  }
13182
13487
  return nonZero;
13183
13488
  }
13184
13489
  function vectorFields(write) {
13185
13490
  return {
13186
- ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims)) } : {},
13491
+ ...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
13187
13492
  ...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
13188
13493
  };
13189
13494
  }
13190
- function text4(value) {
13495
+ function text5(value) {
13191
13496
  return typeof value === "string";
13192
13497
  }
13193
13498
  function timestamp(value) {
13194
13499
  return typeof value === "string" && Number.isFinite(Date.parse(value));
13195
13500
  }
13196
13501
  function presigned(value) {
13197
- if (!object(value) || !text4(value.url) || !/^https:\/\//.test(value.url) || !text4(value.method) || !object(value.headers) || !Object.values(value.headers).every(text4) || !timestamp(value.expires_at))
13502
+ if (!object(value) || !text5(value.url) || !/^https:\/\//.test(value.url) || !text5(value.method) || !object(value.headers) || !Object.values(value.headers).every(text5) || !timestamp(value.expires_at))
13198
13503
  invalid();
13199
13504
  return {
13200
13505
  url: value.url,
@@ -13204,7 +13509,7 @@ function presigned(value) {
13204
13509
  };
13205
13510
  }
13206
13511
  function attachment(value) {
13207
- if (!object(value) || !text4(value.attachment_id) || !attachmentIdPattern.test(value.attachment_id) || !integer(value.size_bytes, 1) || value.state !== "pending" && value.state !== "committed" || value.owner_kind !== void 0 && value.owner_kind !== "message" && value.owner_kind !== "summary" || value.owner_id !== void 0 && !id(value.owner_id) || !timestamp(value.created_at) || value.committed_at !== void 0 && !timestamp(value.committed_at))
13512
+ if (!object(value) || !text5(value.attachment_id) || !attachmentIdPattern.test(value.attachment_id) || !integer(value.size_bytes, 1) || value.state !== "pending" && value.state !== "committed" || value.owner_kind !== void 0 && value.owner_kind !== "message" && value.owner_kind !== "summary" || value.owner_id !== void 0 && !id(value.owner_id) || !timestamp(value.created_at) || value.committed_at !== void 0 && !timestamp(value.committed_at))
13208
13513
  invalid();
13209
13514
  return {
13210
13515
  id: value.attachment_id,
@@ -13217,7 +13522,7 @@ function attachment(value) {
13217
13522
  };
13218
13523
  }
13219
13524
  function ref(value) {
13220
- if (!object(value) || !text4(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
13525
+ if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
13221
13526
  return { kind: value.kind, id: value.id };
13222
13527
  }
13223
13528
  function sameMetadata(a, b) {
@@ -13440,7 +13745,7 @@ async function createRemoteChatStore(options) {
13440
13745
  },
13441
13746
  async account(signal) {
13442
13747
  const value = await request("/account", {}, signal);
13443
- if (!object(value) || value.account_id !== accountId || !text4(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count) || value.changes_cursor !== void 0 && (!text4(value.changes_cursor) || value.changes_cursor.length > 2048))
13748
+ if (!object(value) || value.account_id !== accountId || !text5(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count) || value.changes_cursor !== void 0 && (!text5(value.changes_cursor) || value.changes_cursor.length > 2048))
13444
13749
  invalid();
13445
13750
  if (value.key_id && value.key_id !== keyId)
13446
13751
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -13485,363 +13790,177 @@ async function createRemoteChatStore(options) {
13485
13790
  return {
13486
13791
  kind: checked.kind,
13487
13792
  id: checked.id,
13488
- updated_at: r.updatedAt,
13489
- is_deleted: r.isDeleted
13490
- };
13491
- });
13492
- if (wireRevisions.length === 0) return [];
13493
- const value = await request(
13494
- "/verify",
13495
- {
13496
- method: "POST",
13497
- body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
13498
- },
13499
- signal
13500
- );
13501
- if (!object(value) || !Array.isArray(value.missing)) invalid();
13502
- const missing2 = value.missing.map(ref);
13503
- if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
13504
- return missing2;
13505
- },
13506
- async activate(signal) {
13507
- const value = await request(
13508
- "/account",
13509
- { method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
13510
- signal
13511
- );
13512
- if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
13513
- invalid();
13514
- return value.transitioned;
13515
- },
13516
- async changes(cursor, options2) {
13517
- const limit = options2?.limit ?? 100;
13518
- if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text4(cursor) || cursor.length > 2048))
13519
- invalid();
13520
- const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
13521
- if (cursor) params.set("cursor", cursor);
13522
- const value = await request(`/changes?${params}`, {}, options2?.signal);
13523
- 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))
13524
- invalid();
13525
- const items = [];
13526
- for (const item of value.items) items.push(await decode(item));
13527
- options2?.signal?.throwIfAborted();
13528
- return {
13529
- items,
13530
- ...value.next_cursor ? { nextCursor: value.next_cursor } : {},
13531
- changesCursor: value.changes_cursor ?? cursor ?? ""
13532
- };
13533
- },
13534
- async search(embedding2, options2) {
13535
- const limit = options2?.limit ?? 20;
13536
- const kindsFilter = options2?.kinds;
13537
- if (!Array.isArray(embedding2) || !embeddings({
13538
- record: { ...emptyMessage, isDeleted: false },
13539
- embeddings: [embedding2]
13540
- }) || !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))
13541
- invalid();
13542
- const value = await request(
13543
- "/search",
13544
- {
13545
- method: "POST",
13546
- body: JSON.stringify({
13547
- account_id: accountId,
13548
- embedding: embedding2.slice(0, storedDims),
13549
- limit,
13550
- ...kindsFilter ? { kinds: kindsFilter } : {},
13551
- ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
13552
- ...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
13553
- ...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
13554
- })
13555
- },
13556
- options2?.signal
13557
- );
13558
- if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
13559
- const hits = [];
13560
- for (const item of value.items) {
13561
- if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
13562
- invalid();
13563
- const snapshot = await decode(item);
13564
- 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)
13565
- invalid();
13566
- hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
13567
- }
13568
- options2?.signal?.throwIfAborted();
13569
- return hits;
13570
- },
13571
- async deleteAll(signal) {
13572
- const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
13573
- if (!object(value) || !integer(value.deleted)) invalid();
13574
- return value.deleted;
13575
- },
13576
- attachments: {
13577
- async create(sizeBytes, signal) {
13578
- if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
13579
- const value = await request(
13580
- "/attachments",
13581
- {
13582
- method: "POST",
13583
- body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
13584
- },
13585
- signal
13586
- );
13587
- if (!object(value)) invalid();
13588
- const created = attachment(value.attachment);
13589
- if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
13590
- return { attachment: created, upload: presigned(value.upload) };
13591
- },
13592
- async commit(attachmentId, owner, signal) {
13593
- if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
13594
- invalid();
13595
- const value = await request(
13596
- `/attachments/${attachmentId}/commit`,
13597
- {
13598
- method: "POST",
13599
- body: JSON.stringify({
13600
- account_id: accountId,
13601
- owner_kind: owner.kind,
13602
- owner_id: owner.id
13603
- })
13604
- },
13605
- signal
13606
- );
13607
- if (!object(value)) invalid();
13608
- const committed = attachment(value.attachment);
13609
- if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
13610
- invalid();
13611
- return committed;
13612
- },
13613
- async get(attachmentId, signal) {
13614
- if (!attachmentIdPattern.test(attachmentId)) invalid();
13615
- let value;
13616
- try {
13617
- value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
13618
- } catch (error) {
13619
- if (error instanceof ChatStoreError && error.status === 404) return null;
13620
- throw error;
13621
- }
13622
- if (!object(value)) invalid();
13623
- const found = attachment(value.attachment);
13624
- if (found.id !== attachmentId) invalid();
13625
- return {
13626
- attachment: found,
13627
- ...value.download !== void 0 ? { download: presigned(value.download) } : {}
13628
- };
13629
- },
13630
- async delete(attachmentId, signal) {
13631
- if (!attachmentIdPattern.test(attachmentId)) invalid();
13632
- await request(
13633
- `/attachments/${attachmentId}?account_id=${accountId}`,
13634
- { method: "DELETE" },
13635
- signal
13636
- );
13637
- }
13638
- }
13639
- };
13640
- }
13641
- var emptyMessage = {
13642
- kind: "message",
13643
- id: "query",
13644
- conversationId: "query",
13645
- sortKey: 0,
13646
- createdAt: 1,
13647
- updatedAt: 1,
13648
- isDeleted: false,
13649
- data: {}
13650
- };
13651
-
13652
- // src/lib/chatStore/vaultRecords.ts
13653
- var PINNED_SORT_BASE = 2 ** 51;
13654
- var recordBudgetBytes = 104e4;
13655
- var storedDims2 = 1536;
13656
- var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
13657
- var maxChunks = 16;
13658
- var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
13659
- var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
13660
- var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
13661
- function plain(value) {
13662
- return JSON.parse(JSON.stringify(value ?? {}));
13663
- }
13664
- function text5(value) {
13665
- return typeof value === "string" ? value : void 0;
13666
- }
13667
- function number(value) {
13668
- return typeof value === "number" ? value : void 0;
13669
- }
13670
- function conversationSortKey(data, createdAt) {
13671
- const pinnedAt = number(data.pinnedAt);
13672
- if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
13673
- return number(data.lastActivityAt) ?? createdAt;
13674
- }
13675
- function toConversation(record2) {
13676
- const pinnedAt = number(record2.data.pinnedAt);
13677
- const projectId = text5(record2.data.projectId);
13678
- return {
13679
- uniqueId: record2.id,
13680
- conversationId: record2.id,
13681
- title: text5(record2.data.title) ?? "",
13682
- ...projectId ? { projectId } : {},
13683
- createdAt: new Date(record2.createdAt),
13684
- updatedAt: new Date(record2.updatedAt),
13685
- isDeleted: record2.isDeleted,
13686
- pinnedAt: pinnedAt ? new Date(pinnedAt) : null
13687
- };
13688
- }
13689
- function messageData(options) {
13690
- return plain(
13691
- Object.fromEntries(
13692
- Object.entries(options).filter(
13693
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
13694
- )
13695
- )
13696
- );
13697
- }
13698
- function toMessage(record2) {
13699
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
13700
- return {
13701
- ...fields,
13702
- uniqueId: record2.id,
13703
- messageId: record2.sortKey,
13704
- conversationId: record2.conversationId,
13705
- createdAt: new Date(record2.createdAt),
13706
- updatedAt: new Date(record2.updatedAt)
13707
- };
13708
- }
13709
- function chunkOffsets(record2) {
13710
- const offsets = record2.data.chunkOffsets;
13711
- return Array.isArray(offsets) ? offsets : void 0;
13712
- }
13713
- function toSkeletons(records) {
13714
- const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
13715
- return records.map((r) => {
13716
- const parentMessageId = text5(r.data.parentMessageId);
13717
- const model = text5(r.data.model);
13718
- const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
13719
- return {
13720
- uniqueId: r.id,
13721
- messageId: r.sortKey,
13722
- conversationId: r.conversationId,
13723
- role: text5(r.data.role) ?? "",
13724
- createdAt: new Date(r.createdAt),
13725
- ...parentMessageId ? { parentMessageId } : {},
13726
- ...model ? { model } : {},
13727
- ...artifact ? { content: text5(r.data.content) ?? "" } : {}
13728
- };
13729
- });
13730
- }
13731
- function toSummary(record2) {
13732
- return {
13733
- uniqueId: record2.id,
13734
- conversationId: record2.id,
13735
- summary: text5(record2.data.summary) ?? "",
13736
- summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
13737
- tokenCount: number(record2.data.tokenCount) ?? 0,
13738
- createdAt: new Date(record2.createdAt),
13739
- updatedAt: new Date(record2.updatedAt)
13740
- };
13741
- }
13742
- function links(data) {
13743
- return Array.isArray(data.links) ? data.links : [];
13744
- }
13745
- function applyLinkOps(data, ops) {
13746
- let current = links(data);
13747
- for (const op of ops) {
13748
- if ("clear" in op) {
13749
- current = [];
13750
- continue;
13751
- }
13752
- const byId = new Map(current.map((l) => [l.memoryId, l]));
13753
- const turn = /* @__PURE__ */ new Set();
13754
- op.add.forEach((item, i) => {
13755
- if (!item.memoryId || turn.has(item.memoryId)) return;
13756
- turn.add(item.memoryId);
13757
- const known = byId.get(item.memoryId);
13758
- if (known && known.createdAt >= op.at + i) return;
13759
- byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
13760
- });
13761
- current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
13762
- }
13763
- return plain({ links: current });
13764
- }
13765
- function toLinks(record2) {
13766
- return links(record2.data).map((l) => ({
13767
- uniqueId: `${record2.id}:${l.memoryId}`,
13768
- conversationId: record2.id,
13769
- memoryId: l.memoryId,
13770
- score: l.score,
13771
- createdAt: new Date(l.createdAt)
13772
- }));
13773
- }
13774
- function bytes(value) {
13775
- return new TextEncoder().encode(JSON.stringify(value)).length;
13776
- }
13777
- function fitRecord(record2) {
13778
- if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
13779
- const data = { ...record2.data };
13780
- const truncated = [];
13781
- for (const field10 of droppable) {
13782
- if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
13783
- if (data[field10] === void 0) continue;
13784
- delete data[field10];
13785
- truncated.push(field10);
13786
- }
13787
- const content = text5(data.content) ?? "";
13788
- const over = bytes({ ...record2, data }) - recordBudgetBytes;
13789
- if (over > 0) {
13790
- const encoded = new TextEncoder().encode(content);
13791
- data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
13792
- truncated.push("content");
13793
- }
13794
- return { ...record2, data: { ...data, truncated } };
13795
- }
13796
- function acceptedVector(vector2) {
13797
- if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
13798
- if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
13799
- return void 0;
13800
- return [...vector2];
13801
- }
13802
- function normalized(vector2) {
13803
- const norm = Math.hypot(...vector2) || 1;
13804
- return vector2.map((x) => x / norm);
13805
- }
13806
- function fitChunks(chunks3) {
13807
- const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
13808
- if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
13809
- if (usable.length <= maxChunks) return usable;
13810
- const out = [];
13811
- for (let g = 0; g < maxChunks; g++) {
13812
- const group = usable.slice(
13813
- Math.floor(g * usable.length / maxChunks),
13814
- Math.floor((g + 1) * usable.length / maxChunks)
13815
- );
13816
- const dims = group[0].vector.length;
13817
- const mean = new Array(dims).fill(0);
13818
- for (const c of group) {
13819
- const unit = normalized(c.vector);
13820
- for (let d = 0; d < dims; d++) mean[d] += unit[d];
13793
+ updated_at: r.updatedAt,
13794
+ is_deleted: r.isDeleted
13795
+ };
13796
+ });
13797
+ if (wireRevisions.length === 0) return [];
13798
+ const value = await request(
13799
+ "/verify",
13800
+ {
13801
+ method: "POST",
13802
+ body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
13803
+ },
13804
+ signal
13805
+ );
13806
+ if (!object(value) || !Array.isArray(value.missing)) invalid();
13807
+ const missing2 = value.missing.map(ref);
13808
+ if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
13809
+ return missing2;
13810
+ },
13811
+ async activate(signal) {
13812
+ const value = await request(
13813
+ "/account",
13814
+ { method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
13815
+ signal
13816
+ );
13817
+ if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
13818
+ invalid();
13819
+ return value.transitioned;
13820
+ },
13821
+ async changes(cursor, options2) {
13822
+ const limit = options2?.limit ?? 100;
13823
+ if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
13824
+ invalid();
13825
+ const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
13826
+ if (cursor) params.set("cursor", cursor);
13827
+ const value = await request(`/changes?${params}`, {}, options2?.signal);
13828
+ if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !text5(value.next_cursor) || value.changes_cursor !== void 0 && !text5(value.changes_cursor))
13829
+ invalid();
13830
+ const items = [];
13831
+ for (const item of value.items) items.push(await decode(item));
13832
+ options2?.signal?.throwIfAborted();
13833
+ return {
13834
+ items,
13835
+ ...value.next_cursor ? { nextCursor: value.next_cursor } : {},
13836
+ changesCursor: value.changes_cursor ?? cursor ?? ""
13837
+ };
13838
+ },
13839
+ async search(embedding2, options2) {
13840
+ const limit = options2?.limit ?? 20;
13841
+ const kindsFilter = options2?.kinds;
13842
+ if (!Array.isArray(embedding2) || !embeddings({
13843
+ record: { ...emptyMessage, isDeleted: false },
13844
+ embeddings: [embedding2]
13845
+ }) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!text5(options2.embeddingModel) || options2.embeddingModel.length > 256))
13846
+ invalid();
13847
+ const value = await request(
13848
+ "/search",
13849
+ {
13850
+ method: "POST",
13851
+ body: JSON.stringify({
13852
+ account_id: accountId,
13853
+ embedding: embedding2.slice(0, storedDims2),
13854
+ limit,
13855
+ ...kindsFilter ? { kinds: kindsFilter } : {},
13856
+ ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
13857
+ ...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
13858
+ ...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
13859
+ })
13860
+ },
13861
+ options2?.signal
13862
+ );
13863
+ if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
13864
+ const hits = [];
13865
+ for (const item of value.items) {
13866
+ if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
13867
+ invalid();
13868
+ const snapshot = await decode(item);
13869
+ 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)
13870
+ invalid();
13871
+ hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
13872
+ }
13873
+ options2?.signal?.throwIfAborted();
13874
+ return hits;
13875
+ },
13876
+ async deleteAll(signal) {
13877
+ const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
13878
+ if (!object(value) || !integer(value.deleted)) invalid();
13879
+ return value.deleted;
13880
+ },
13881
+ attachments: {
13882
+ async create(sizeBytes, signal) {
13883
+ if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
13884
+ const value = await request(
13885
+ "/attachments",
13886
+ {
13887
+ method: "POST",
13888
+ body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
13889
+ },
13890
+ signal
13891
+ );
13892
+ if (!object(value)) invalid();
13893
+ const created = attachment(value.attachment);
13894
+ if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
13895
+ return { attachment: created, upload: presigned(value.upload) };
13896
+ },
13897
+ async commit(attachmentId, owner, signal) {
13898
+ if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
13899
+ invalid();
13900
+ const value = await request(
13901
+ `/attachments/${attachmentId}/commit`,
13902
+ {
13903
+ method: "POST",
13904
+ body: JSON.stringify({
13905
+ account_id: accountId,
13906
+ owner_kind: owner.kind,
13907
+ owner_id: owner.id
13908
+ })
13909
+ },
13910
+ signal
13911
+ );
13912
+ if (!object(value)) invalid();
13913
+ const committed = attachment(value.attachment);
13914
+ if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
13915
+ invalid();
13916
+ return committed;
13917
+ },
13918
+ async get(attachmentId, signal) {
13919
+ if (!attachmentIdPattern.test(attachmentId)) invalid();
13920
+ let value;
13921
+ try {
13922
+ value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
13923
+ } catch (error) {
13924
+ if (error instanceof ChatStoreError && error.status === 404) return null;
13925
+ throw error;
13926
+ }
13927
+ if (!object(value)) invalid();
13928
+ const found = attachment(value.attachment);
13929
+ if (found.id !== attachmentId) invalid();
13930
+ return {
13931
+ attachment: found,
13932
+ ...value.download !== void 0 ? { download: presigned(value.download) } : {}
13933
+ };
13934
+ },
13935
+ async delete(attachmentId, signal) {
13936
+ if (!attachmentIdPattern.test(attachmentId)) invalid();
13937
+ await request(
13938
+ `/attachments/${attachmentId}?account_id=${accountId}`,
13939
+ { method: "DELETE" },
13940
+ signal
13941
+ );
13942
+ }
13821
13943
  }
13822
- out.push({
13823
- vector: normalized(mean),
13824
- startOffset: group[0].startOffset,
13825
- endOffset: group[group.length - 1].endOffset
13826
- });
13827
- }
13828
- return out;
13944
+ };
13829
13945
  }
13946
+ var emptyMessage = {
13947
+ kind: "message",
13948
+ id: "query",
13949
+ conversationId: "query",
13950
+ sortKey: 0,
13951
+ createdAt: 1,
13952
+ updatedAt: 1,
13953
+ isDeleted: false,
13954
+ data: {}
13955
+ };
13830
13956
 
13831
13957
  // src/lib/chatStore/migrateChats.ts
13832
13958
  var maxPasses = 5;
13833
13959
  var verifyBatch = 1e3;
13834
- var importBatch = 100;
13835
- var importChunks = 200;
13836
- var importPlaintextBytes = 39e5;
13837
13960
  var writeBatch = 25;
13838
13961
  function key(record2) {
13839
13962
  return `${record2.kind}/${record2.id}`;
13840
13963
  }
13841
- function ms(date10, fallback = 1) {
13842
- const value = date10?.getTime();
13843
- return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
13844
- }
13845
13964
  function sealed(value) {
13846
13965
  if (typeof value === "string") return isEncrypted(value);
13847
13966
  if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
@@ -13849,42 +13968,6 @@ function sealed(value) {
13849
13968
  return Object.values(value).some(sealed);
13850
13969
  return false;
13851
13970
  }
13852
- function bytes2(value) {
13853
- return new TextEncoder().encode(JSON.stringify(value)).length;
13854
- }
13855
- function messageRecord(message) {
13856
- const {
13857
- uniqueId: _uniqueId,
13858
- messageId: _messageId,
13859
- createdAt: _createdAt,
13860
- updatedAt: _updatedAt,
13861
- decryptionStatus: _status,
13862
- chunks: chunks3,
13863
- vector: vector2,
13864
- ...fields
13865
- } = message;
13866
- const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
13867
- const single = fitted ? void 0 : acceptedVector(vector2);
13868
- const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
13869
- const record2 = fitRecord({
13870
- kind: "message",
13871
- id: message.uniqueId,
13872
- conversationId: message.conversationId,
13873
- sortKey: message.messageId,
13874
- createdAt: ms(message.createdAt),
13875
- updatedAt: ms(message.updatedAt, ms(message.createdAt)),
13876
- isDeleted: false,
13877
- data: {
13878
- ...messageData(fields),
13879
- ...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
13880
- }
13881
- });
13882
- return {
13883
- record: record2,
13884
- ...embeddings2 ? { embeddings: embeddings2 } : {},
13885
- ...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
13886
- };
13887
- }
13888
13971
  async function readLocal(options) {
13889
13972
  const { database } = options;
13890
13973
  const ctx = {
@@ -13895,7 +13978,7 @@ async function readLocal(options) {
13895
13978
  signMessage: options.signMessage,
13896
13979
  embeddedWalletSigner: options.embeddedWalletSigner
13897
13980
  };
13898
- const summaries = createSummaryContext(database);
13981
+ const summaries = createSummaryContext(database, ctx);
13899
13982
  const memory = {
13900
13983
  database,
13901
13984
  conversationMemoryCollection: database.get(ConversationMemory.table)
@@ -13938,29 +14021,10 @@ async function readLocal(options) {
13938
14021
  const messages = await getMessagesOp(ctx, conversationId);
13939
14022
  const unreadableTitle = isEncrypted(conversation.title);
13940
14023
  if (unreadableTitle) out.untitled++;
13941
- const createdAt = ms(conversation.createdAt);
13942
- const data = plain({
13943
- title: unreadableTitle ? "" : conversation.title,
13944
- projectId: conversation.projectId || void 0,
13945
- pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
13946
- lastActivityAt: Math.max(
13947
- ms(conversation.updatedAt, createdAt),
13948
- ...messages.map((m) => ms(m.createdAt))
13949
- )
13950
- });
13951
14024
  out.conversations++;
13952
- out.records.push({
13953
- record: {
13954
- kind: "conversation",
13955
- id: conversationId,
13956
- conversationId: "",
13957
- sortKey: conversationSortKey(data, createdAt),
13958
- createdAt,
13959
- updatedAt: ms(conversation.updatedAt, createdAt),
13960
- isDeleted: false,
13961
- data
13962
- }
13963
- });
14025
+ out.records.push(
14026
+ conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
14027
+ );
13964
14028
  for (const message of messages) {
13965
14029
  if (message.decryptionStatus || sealed(message)) {
13966
14030
  skip("message", message.uniqueId, "unreadable");
@@ -13976,7 +14040,9 @@ async function readLocal(options) {
13976
14040
  out.records.push(prepared);
13977
14041
  }
13978
14042
  const summary = await getConversationSummaryOp(summaries, conversationId);
13979
- if (summary)
14043
+ if (summary && isEncrypted(summary.summary)) {
14044
+ skip("summary", conversationId, "unreadable");
14045
+ } else if (summary)
13980
14046
  out.records.push({
13981
14047
  record: {
13982
14048
  kind: "summary",
@@ -14079,27 +14145,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
14079
14145
  };
14080
14146
  });
14081
14147
  }
14082
- function batches(records) {
14083
- const out = [];
14084
- let batch = [];
14085
- let chunks3 = 0;
14086
- let size = 0;
14087
- for (const item of records) {
14088
- const vectors = item.embeddings?.length ?? 0;
14089
- const itemSize = bytes2(item.record);
14090
- if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
14091
- out.push(batch);
14092
- batch = [];
14093
- chunks3 = 0;
14094
- size = 0;
14095
- }
14096
- batch.push(item);
14097
- chunks3 += vectors;
14098
- size += itemSize;
14099
- }
14100
- if (batch.length) out.push(batch);
14101
- return out;
14102
- }
14103
14148
  function fitVectors(records, available2, unembedded) {
14104
14149
  let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
14105
14150
  if (total <= available2) return records;
@@ -15180,6 +15225,45 @@ function createVaultChatBackend(options) {
15180
15225
  },
15181
15226
  flush,
15182
15227
  poll,
15228
+ async importChats(chats) {
15229
+ await ready();
15230
+ const seen = /* @__PURE__ */ new Set();
15231
+ const unique = (items) => items.filter(({ record: record2 }) => {
15232
+ const k = key2(record2.kind, record2.id);
15233
+ if (seen.has(k)) return false;
15234
+ seen.add(k);
15235
+ return true;
15236
+ });
15237
+ const valid = chats.filter((c) => validChatId(c.conversation.conversationId));
15238
+ const conversations = unique(
15239
+ valid.map((c) => conversationRecord(c.conversation, c.messages))
15240
+ );
15241
+ const messages = unique(
15242
+ valid.flatMap(
15243
+ (c) => c.messages.filter(
15244
+ (m) => m.conversationId === c.conversation.conversationId && validChatId(m.uniqueId) && Number.isSafeInteger(m.messageId)
15245
+ ).map((m) => messageRecord({ ...m, vector: void 0, chunks: void 0 }))
15246
+ )
15247
+ );
15248
+ let conversationCount = 0;
15249
+ let messageCount = 0;
15250
+ try {
15251
+ for (const batch of batches(conversations))
15252
+ conversationCount += await store.importRecords(batch);
15253
+ for (const batch of batches(messages)) messageCount += await store.importRecords(batch);
15254
+ } finally {
15255
+ for (const { record: record2 } of messages) checked.delete(key2("message", record2.id));
15256
+ await refresh(conversations.map(({ record: record2 }) => key2("conversation", record2.id))).catch(
15257
+ () => void 0
15258
+ );
15259
+ for (const { record: record2 } of conversations) threads.delete(record2.id);
15260
+ channel?.postMessage("changed");
15261
+ emit({ type: "conversations", origin: "local" });
15262
+ for (const { record: record2 } of conversations)
15263
+ emit({ type: "messages", conversationId: record2.id, origin: "local" });
15264
+ }
15265
+ return { conversations: conversationCount, messages: messageCount };
15266
+ },
15183
15267
  status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
15184
15268
  close() {
15185
15269
  closed = true;
@@ -17654,11 +17738,14 @@ var WatermelonChatStorageAdapter = class {
17654
17738
  return searchChunksOp(this.ctx, queryVector, options);
17655
17739
  }
17656
17740
  getSummary(conversationId) {
17657
- return getConversationSummaryOp(createSummaryContext(this.ctx.database), conversationId);
17741
+ return getConversationSummaryOp(
17742
+ createSummaryContext(this.ctx.database, this.ctx),
17743
+ conversationId
17744
+ );
17658
17745
  }
17659
17746
  upsertSummary(conversationId, summary, summarizedUpTo, tokenCount) {
17660
17747
  return upsertConversationSummaryOp(
17661
- createSummaryContext(this.ctx.database),
17748
+ createSummaryContext(this.ctx.database, this.ctx),
17662
17749
  conversationId,
17663
17750
  summary,
17664
17751
  summarizedUpTo,
@@ -36017,7 +36104,7 @@ async function summarizeHistoryAtRevision(options, revision2) {
36017
36104
  const cachedSummary = await summaryStore(options).getSummary(conversationId);
36018
36105
  return {
36019
36106
  messagesToConvert: messages,
36020
- summarySystemMessage: cachedSummary?.summary ? summaryToSystemMessage(cachedSummary.summary) : null
36107
+ summarySystemMessage: cachedSummary?.summary && !isEncrypted(cachedSummary.summary) ? summaryToSystemMessage(cachedSummary.summary) : null
36021
36108
  };
36022
36109
  } catch {
36023
36110
  return { messagesToConvert: messages, summarySystemMessage: null };
@@ -36072,14 +36159,15 @@ async function doSummarizeHistory(options, revision2) {
36072
36159
  } = options;
36073
36160
  try {
36074
36161
  const summaries = summaryStore(options);
36075
- const persistSummary = (summary, summarizedUpTo, tokenCount) => database.write(async (writer) => {
36162
+ const persistSummary = (summary, summarizedUpTo, tokenCount) => {
36076
36163
  assertConversationRevision(database, conversationId, revision2);
36077
- await writer.callWriter(
36078
- () => summaries.upsertSummary(conversationId, summary, summarizedUpTo, tokenCount)
36079
- );
36080
- });
36164
+ return summaries.upsertSummary(conversationId, summary, summarizedUpTo, tokenCount);
36165
+ };
36081
36166
  let cachedSummary = await summaries.getSummary(conversationId);
36082
36167
  assertConversationRevision(database, conversationId, revision2);
36168
+ if (cachedSummary && isEncrypted(cachedSummary.summary)) {
36169
+ throw new Error("The cached summary could not be decrypted");
36170
+ }
36083
36171
  const lastCompacted = lastCompactionTime.get(conversationId) ?? 0;
36084
36172
  const compactionCooledDown = Date.now() - lastCompacted > COMPACTION_COOLDOWN_MS;
36085
36173
  if (cachedSummary && cachedSummary.tokenCount > summaryTokenThreshold * MAX_SUMMARY_TOKEN_RATIO && compactionCooledDown) {