@anuma/sdk 10.8.0 → 10.9.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.
@@ -6163,17 +6163,17 @@ async function createRemoteMemoryPersistence(options) {
6163
6163
  expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
6164
6164
  if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
6165
6165
  throw new Error("expectedVersion must be a nonnegative integer");
6166
- const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
6166
+ const conflict2 = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
6167
6167
  let existing;
6168
6168
  if (expectedVersion !== 0 && !snapshot) {
6169
6169
  try {
6170
6170
  existing = memoryRecord(await request(path, {}, signal));
6171
6171
  } catch (error) {
6172
- if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
6172
+ if (error instanceof RemoteMemoryError && error.status === 404) throw conflict2();
6173
6173
  throw error;
6174
6174
  }
6175
6175
  }
6176
- if (existing && existing.version !== expectedVersion) throw conflict();
6176
+ if (existing && existing.version !== expectedVersion) throw conflict2();
6177
6177
  const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
6178
6178
  const reusableContent = snapshot?.encryptedContent ?? existing?.memory.content;
6179
6179
  const content = reusableContent && (snapshot?.content ?? decoded?.memory.content) === memory.content ? reusableContent : await encryptField2(memory.content);
@@ -11331,118 +11331,19 @@ function createWebSearchPreProcessor(options = {}) {
11331
11331
  };
11332
11332
  }
11333
11333
 
11334
- // src/lib/db/chat/summaryOperations.ts
11335
- import { Q as Q3 } from "@nozbe/watermelondb";
11336
- function createSummaryContext(database, encryption = {}) {
11337
- return {
11338
- ...encryption,
11339
- database,
11340
- summariesCollection: database.get("conversation_summaries")
11341
- };
11342
- }
11343
- function modelToStored(record2, summary) {
11344
- return {
11345
- uniqueId: record2.id,
11346
- conversationId: record2.conversationId,
11347
- summary,
11348
- summarizedUpTo: record2.summarizedUpTo,
11349
- tokenCount: record2.tokenCount,
11350
- createdAt: record2.createdAt,
11351
- updatedAt: record2.updatedAt
11352
- };
11353
- }
11354
- async function getConversationSummaryOp(ctx, conversationId) {
11355
- const results = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
11356
- if (results.length === 0) return null;
11357
- const record2 = results[0];
11358
- const stored2 = modelToStored(record2, record2.summary);
11359
- if (ctx.walletAddress && isEncrypted(stored2.summary)) {
11360
- if (ctx.signMessage) {
11361
- try {
11362
- await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
11363
- } catch (error) {
11364
- getLogger().warn("Failed to request the encryption key for the summary:", error);
11365
- }
11366
- }
11367
- stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
11368
- } else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
11369
- try {
11370
- const encryptedSummary = await encryptField(
11371
- stored2.summary,
11372
- ctx.walletAddress,
11373
- ctx.signMessage,
11374
- ctx.embeddedWalletSigner
11375
- );
11376
- await ctx.database.write(async () => {
11377
- const current = await ctx.summariesCollection.query(Q3.where("id", record2.id)).fetch();
11378
- if (current[0]?.summary === stored2.summary) {
11379
- await current[0].update((rec) => {
11380
- rec.summary = encryptedSummary;
11381
- });
11382
- }
11383
- });
11384
- } catch (error) {
11385
- getLogger().warn("Failed to encrypt the legacy summary:", error);
11386
- }
11334
+ // src/lib/chatStore/types.ts
11335
+ var ChatStoreError = class extends Error {
11336
+ constructor(message, status, code, retryAfterMs) {
11337
+ super(message);
11338
+ this.status = status;
11339
+ this.code = code;
11340
+ this.retryAfterMs = retryAfterMs;
11341
+ this.name = "ChatStoreError";
11387
11342
  }
11388
- return stored2;
11389
- }
11390
- async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
11391
- const revision2 = getConversationRevision(ctx.database, conversationId);
11392
- let record2;
11393
- const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
11394
- await ctx.database.write(async () => {
11395
- assertConversationRevision(ctx.database, conversationId, revision2);
11396
- const existing = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
11397
- if (existing.length > 0) {
11398
- record2 = await existing[0].update((rec) => {
11399
- rec.summary = encryptedSummary;
11400
- rec.summarizedUpTo = summarizedUpTo;
11401
- rec.tokenCount = tokenCount;
11402
- });
11403
- } else {
11404
- record2 = await ctx.summariesCollection.create((rec) => {
11405
- rec.conversationId = conversationId;
11406
- rec.summary = encryptedSummary;
11407
- rec.summarizedUpTo = summarizedUpTo;
11408
- rec.tokenCount = tokenCount;
11409
- });
11410
- }
11411
- });
11412
- return modelToStored(record2, summary);
11413
- }
11414
- async function deleteConversationSummaryOp(ctx, conversationId) {
11415
- await ctx.database.write(async () => {
11416
- const existing = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
11417
- for (const record2 of existing) {
11418
- await record2.destroyPermanently();
11419
- }
11420
- });
11421
- }
11422
-
11423
- // src/lib/db/conversationMemory/models.ts
11424
- import { Model as Model3 } from "@nozbe/watermelondb";
11425
- import { date as date2, field as field2, readonly, text as text3 } from "@nozbe/watermelondb/decorators";
11426
- var ConversationMemory = class extends Model3 {
11427
11343
  };
11428
- ConversationMemory.table = "conversation_memory";
11429
- ConversationMemory.associations = {};
11430
- __decorateClass([
11431
- text3("conversation_id")
11432
- ], ConversationMemory.prototype, "conversationId", 2);
11433
- __decorateClass([
11434
- text3("memory_id")
11435
- ], ConversationMemory.prototype, "memoryId", 2);
11436
- __decorateClass([
11437
- field2("score")
11438
- ], ConversationMemory.prototype, "score", 2);
11439
- __decorateClass([
11440
- readonly,
11441
- date2("created_at")
11442
- ], ConversationMemory.prototype, "createdAt", 2);
11443
11344
 
11444
11345
  // src/lib/db/conversationMemory/operations.ts
11445
- import { Q as Q4 } from "@nozbe/watermelondb";
11346
+ import { Q as Q3 } from "@nozbe/watermelondb";
11446
11347
  var MAX_PER_CONVERSATION = 200;
11447
11348
  function conversationMemoryToStored(row) {
11448
11349
  return {
@@ -11457,7 +11358,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
11457
11358
  if (!conversationId || items.length === 0) return;
11458
11359
  const now = Date.now();
11459
11360
  await ctx.database.write(async () => {
11460
- const existing = await ctx.conversationMemoryCollection.query(Q4.where("conversation_id", conversationId), Q4.sortBy("created_at", Q4.asc)).fetch();
11361
+ const existing = await ctx.conversationMemoryCollection.query(Q3.where("conversation_id", conversationId), Q3.sortBy("created_at", Q3.asc)).fetch();
11461
11362
  const seen = new Set(existing.map((r) => r.memoryId));
11462
11363
  const batchSeen = /* @__PURE__ */ new Set();
11463
11364
  const deduped = [];
@@ -11494,7 +11395,7 @@ async function recordConversationMemoriesOp(ctx, conversationId, items, now = Da
11494
11395
  if (!conversationId || turn.size === 0) return;
11495
11396
  const kept = new Map([...turn].slice(-MAX_PER_CONVERSATION));
11496
11397
  await ctx.database.write(async () => {
11497
- const existing = await ctx.conversationMemoryCollection.query(Q4.where("conversation_id", conversationId), Q4.sortBy("created_at", Q4.asc)).fetch();
11398
+ const existing = await ctx.conversationMemoryCollection.query(Q3.where("conversation_id", conversationId), Q3.sortBy("created_at", Q3.asc)).fetch();
11498
11399
  const earlier = existing.filter((r) => !turn.has(r.memoryId));
11499
11400
  const linked = new Set(existing.map((r) => r.memoryId));
11500
11401
  await ctx.database.batch(
@@ -11519,13 +11420,13 @@ async function recordConversationMemoriesOp(ctx, conversationId, items, now = Da
11519
11420
  }
11520
11421
  async function getConversationMemoriesOp(ctx, conversationId) {
11521
11422
  if (!conversationId) return [];
11522
- const rows = await ctx.conversationMemoryCollection.query(Q4.where("conversation_id", conversationId), Q4.sortBy("created_at", Q4.asc)).fetch();
11423
+ const rows = await ctx.conversationMemoryCollection.query(Q3.where("conversation_id", conversationId), Q3.sortBy("created_at", Q3.asc)).fetch();
11523
11424
  return rows.map(conversationMemoryToStored);
11524
11425
  }
11525
11426
  async function clearConversationMemoriesOp(ctx, conversationId) {
11526
11427
  if (!conversationId) return;
11527
11428
  await ctx.database.write(async () => {
11528
- const rows = await ctx.conversationMemoryCollection.query(Q4.where("conversation_id", conversationId)).fetch();
11429
+ const rows = await ctx.conversationMemoryCollection.query(Q3.where("conversation_id", conversationId)).fetch();
11529
11430
  if (rows.length === 0) return;
11530
11431
  await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
11531
11432
  });
@@ -11540,15 +11441,37 @@ var maxChunks = 16;
11540
11441
  var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
11541
11442
  var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
11542
11443
  var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
11444
+ var maxBubbles = 3;
11445
+ var maxTurnIdBytes = 128;
11446
+ var maxBubbleBytes = 16384;
11447
+ var anumaOrigins = /* @__PURE__ */ new Set(["intro", "reply"]);
11543
11448
  function plain(value) {
11544
11449
  return JSON.parse(JSON.stringify(value ?? {}));
11545
11450
  }
11546
- function text4(value) {
11451
+ function text3(value) {
11547
11452
  return typeof value === "string" ? value : void 0;
11548
11453
  }
11549
11454
  function number(value) {
11550
11455
  return typeof value === "number" ? value : void 0;
11551
11456
  }
11457
+ function readAnumaTurn(value) {
11458
+ if (!isObject(value)) return void 0;
11459
+ const { turnId, bubbles, origin } = value;
11460
+ if (typeof turnId !== "string" || turnId.length === 0 || new TextEncoder().encode(turnId).length > maxTurnIdBytes)
11461
+ return void 0;
11462
+ if (bubbles !== void 0 && (!Array.isArray(bubbles) || bubbles.length < 1 || bubbles.length > maxBubbles || !bubbles.every((b) => typeof b === "string") || bubbles.reduce((sum, b) => sum + new TextEncoder().encode(b).length, 0) > maxBubbleBytes))
11463
+ return void 0;
11464
+ if (origin !== void 0 && (typeof origin !== "string" || !anumaOrigins.has(origin)))
11465
+ return void 0;
11466
+ return {
11467
+ turnId,
11468
+ ...bubbles !== void 0 ? { bubbles: [...bubbles] } : {},
11469
+ ...origin !== void 0 ? { origin } : {}
11470
+ };
11471
+ }
11472
+ function isObject(value) {
11473
+ return value !== null && typeof value === "object" && !Array.isArray(value);
11474
+ }
11552
11475
  function conversationSortKey(data, createdAt) {
11553
11476
  const pinnedAt = number(data.pinnedAt);
11554
11477
  if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
@@ -11569,12 +11492,12 @@ function conversationContext(data) {
11569
11492
  }
11570
11493
  function toConversation(record2) {
11571
11494
  const pinnedAt = number(record2.data.pinnedAt);
11572
- const projectId = text4(record2.data.projectId);
11495
+ const projectId = text3(record2.data.projectId);
11573
11496
  const context = conversationContext(record2.data);
11574
11497
  return {
11575
11498
  uniqueId: record2.id,
11576
11499
  conversationId: record2.id,
11577
- title: text4(record2.data.title) ?? "",
11500
+ title: text3(record2.data.title) ?? "",
11578
11501
  ...projectId ? { projectId } : {},
11579
11502
  createdAt: new Date(record2.createdAt),
11580
11503
  updatedAt: new Date(record2.updatedAt),
@@ -11583,18 +11506,28 @@ function toConversation(record2) {
11583
11506
  ...context ? { context } : {}
11584
11507
  };
11585
11508
  }
11509
+ function anumaTurnData(value) {
11510
+ if (value === void 0) return void 0;
11511
+ const turn = readAnumaTurn(value);
11512
+ if (!turn) throw new ChatStoreError("Invalid Anuma turn", 0, "invalid_record");
11513
+ return turn;
11514
+ }
11586
11515
  function messageData(options) {
11587
- return plain(
11588
- Object.fromEntries(
11516
+ const anuma = anumaTurnData(options.anuma);
11517
+ return plain({
11518
+ ...Object.fromEntries(
11589
11519
  Object.entries(options).filter(
11590
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
11520
+ ([key3, value]) => key3 !== "anuma" && !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
11591
11521
  )
11592
- )
11593
- );
11522
+ ),
11523
+ ...anuma ? { anuma } : {}
11524
+ });
11594
11525
  }
11595
11526
  function toMessage(record2) {
11596
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
11527
+ const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } = record2.data;
11528
+ const anuma = readAnumaTurn(rawAnuma);
11597
11529
  return {
11530
+ ...anuma ? { anuma } : {},
11598
11531
  ...fields,
11599
11532
  uniqueId: record2.id,
11600
11533
  messageId: record2.sortKey,
@@ -11608,20 +11541,20 @@ function chunkOffsets(record2) {
11608
11541
  return Array.isArray(offsets) ? offsets : void 0;
11609
11542
  }
11610
11543
  function toSkeletons(records) {
11611
- const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
11544
+ const roleById = new Map(records.map((r) => [r.id, text3(r.data.role)]));
11612
11545
  return records.map((r) => {
11613
- const parentMessageId = text4(r.data.parentMessageId);
11614
- const model = text4(r.data.model);
11546
+ const parentMessageId = text3(r.data.parentMessageId);
11547
+ const model = text3(r.data.model);
11615
11548
  const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
11616
11549
  return {
11617
11550
  uniqueId: r.id,
11618
11551
  messageId: r.sortKey,
11619
11552
  conversationId: r.conversationId,
11620
- role: text4(r.data.role) ?? "",
11553
+ role: text3(r.data.role) ?? "",
11621
11554
  createdAt: new Date(r.createdAt),
11622
11555
  ...parentMessageId ? { parentMessageId } : {},
11623
11556
  ...model ? { model } : {},
11624
- ...artifact ? { content: text4(r.data.content) ?? "" } : {}
11557
+ ...artifact ? { content: text3(r.data.content) ?? "" } : {}
11625
11558
  };
11626
11559
  });
11627
11560
  }
@@ -11629,8 +11562,8 @@ function toSummary(record2) {
11629
11562
  return {
11630
11563
  uniqueId: record2.id,
11631
11564
  conversationId: record2.id,
11632
- summary: text4(record2.data.summary) ?? "",
11633
- summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
11565
+ summary: text3(record2.data.summary) ?? "",
11566
+ summarizedUpTo: text3(record2.data.summarizedUpTo) ?? "",
11634
11567
  tokenCount: number(record2.data.tokenCount) ?? 0,
11635
11568
  createdAt: new Date(record2.createdAt),
11636
11569
  updatedAt: new Date(record2.updatedAt)
@@ -11681,7 +11614,7 @@ function fitRecord(record2) {
11681
11614
  delete data[field10];
11682
11615
  truncated.push(field10);
11683
11616
  }
11684
- const content = text4(data.content) ?? "";
11617
+ const content = text3(data.content) ?? "";
11685
11618
  const over = bytes({ ...record2, data }) - recordBudgetBytes;
11686
11619
  if (over > 0) {
11687
11620
  const encoded = new TextEncoder().encode(content);
@@ -11725,6 +11658,215 @@ function fitChunks(chunks3) {
11725
11658
  return out;
11726
11659
  }
11727
11660
 
11661
+ // src/lib/chatStore/anuma.ts
11662
+ var ANUMA_CONVERSATION_ID = "anuma-1on1";
11663
+ var maxAttempts = 3;
11664
+ function anumaTurnContent(bubbles) {
11665
+ return bubbles.join("\n\n");
11666
+ }
11667
+ function anumaLastReadSortKey(conversation) {
11668
+ const record2 = conversation && "record" in conversation ? conversation.record : conversation;
11669
+ const state = record2?.data.anuma;
11670
+ if (!isObject(state)) return 0;
11671
+ const sortKey = state.lastReadSortKey;
11672
+ return Number.isSafeInteger(sortKey) && sortKey > 0 ? sortKey : 0;
11673
+ }
11674
+ function conflict(error) {
11675
+ return error instanceof ChatStoreError && error.code === "version_conflict";
11676
+ }
11677
+ function live(snapshot) {
11678
+ if (snapshot?.record.isDeleted)
11679
+ throw new ChatStoreError("Anuma conversation was deleted", 409, "conversation_deleted");
11680
+ return snapshot;
11681
+ }
11682
+ async function ensureAnumaConversation(store, options = {}) {
11683
+ const existing = live(await store.get("conversation", ANUMA_CONVERSATION_ID, options.signal));
11684
+ if (existing) return existing;
11685
+ const at = (options.now ?? Date.now)();
11686
+ const data = plain({ title: "Anuma", lastActivityAt: at, anuma: { lastReadSortKey: 0 } });
11687
+ try {
11688
+ const [created] = await store.putMany(
11689
+ [
11690
+ {
11691
+ expectedVersion: 0,
11692
+ record: {
11693
+ kind: "conversation",
11694
+ id: ANUMA_CONVERSATION_ID,
11695
+ conversationId: "",
11696
+ sortKey: conversationSortKey(data, at),
11697
+ createdAt: at,
11698
+ updatedAt: at,
11699
+ isDeleted: false,
11700
+ data
11701
+ }
11702
+ }
11703
+ ],
11704
+ options.signal
11705
+ );
11706
+ return created;
11707
+ } catch (error) {
11708
+ if (!conflict(error)) throw error;
11709
+ const winner = live(await store.get("conversation", ANUMA_CONVERSATION_ID, options.signal));
11710
+ if (!winner) throw error;
11711
+ return winner;
11712
+ }
11713
+ }
11714
+ async function markAnumaRead(store, sortKey, options = {}) {
11715
+ if (!Number.isSafeInteger(sortKey) || sortKey < 0)
11716
+ throw new ChatStoreError("Invalid Anuma read marker", 0, "invalid_record");
11717
+ const now = options.now ?? Date.now;
11718
+ for (let attempt = 1; ; attempt++) {
11719
+ const current = await ensureAnumaConversation(store, options);
11720
+ const read = anumaLastReadSortKey(current);
11721
+ if (sortKey <= read) return current;
11722
+ const record2 = current.record;
11723
+ const state = isObject(record2.data.anuma) ? record2.data.anuma : {};
11724
+ const data = plain({ ...record2.data, anuma: { ...state, lastReadSortKey: sortKey } });
11725
+ try {
11726
+ const [written] = await store.putMany(
11727
+ [
11728
+ {
11729
+ expectedVersion: current.version,
11730
+ record: {
11731
+ ...record2,
11732
+ data,
11733
+ sortKey: conversationSortKey(data, record2.createdAt),
11734
+ updatedAt: Math.max(record2.updatedAt, now())
11735
+ }
11736
+ }
11737
+ ],
11738
+ options.signal
11739
+ );
11740
+ return written;
11741
+ } catch (error) {
11742
+ if (!conflict(error) || attempt >= maxAttempts) throw error;
11743
+ }
11744
+ }
11745
+ }
11746
+ function countUnreadAnumaTurns(messages, lastReadSortKey) {
11747
+ const answered = Math.max(
11748
+ 0,
11749
+ ...messages.filter((m) => m.role === "user").map((m) => m.messageId)
11750
+ );
11751
+ const floor = Math.max(lastReadSortKey, answered);
11752
+ const turns = /* @__PURE__ */ new Set();
11753
+ for (const m of messages) {
11754
+ if (m.role !== "assistant" || m.messageId <= floor) continue;
11755
+ turns.add(m.anuma?.turnId ? `turn:${m.anuma.turnId}` : `message:${m.uniqueId}`);
11756
+ }
11757
+ return turns.size;
11758
+ }
11759
+
11760
+ // src/lib/db/chat/summaryOperations.ts
11761
+ import { Q as Q4 } from "@nozbe/watermelondb";
11762
+ function createSummaryContext(database, encryption = {}) {
11763
+ return {
11764
+ ...encryption,
11765
+ database,
11766
+ summariesCollection: database.get("conversation_summaries")
11767
+ };
11768
+ }
11769
+ function modelToStored(record2, summary) {
11770
+ return {
11771
+ uniqueId: record2.id,
11772
+ conversationId: record2.conversationId,
11773
+ summary,
11774
+ summarizedUpTo: record2.summarizedUpTo,
11775
+ tokenCount: record2.tokenCount,
11776
+ createdAt: record2.createdAt,
11777
+ updatedAt: record2.updatedAt
11778
+ };
11779
+ }
11780
+ async function getConversationSummaryOp(ctx, conversationId) {
11781
+ const results = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
11782
+ if (results.length === 0) return null;
11783
+ const record2 = results[0];
11784
+ const stored2 = modelToStored(record2, record2.summary);
11785
+ if (ctx.walletAddress && isEncrypted(stored2.summary)) {
11786
+ if (ctx.signMessage) {
11787
+ try {
11788
+ await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
11789
+ } catch (error) {
11790
+ getLogger().warn("Failed to request the encryption key for the summary:", error);
11791
+ }
11792
+ }
11793
+ stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
11794
+ } else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
11795
+ try {
11796
+ const encryptedSummary = await encryptField(
11797
+ stored2.summary,
11798
+ ctx.walletAddress,
11799
+ ctx.signMessage,
11800
+ ctx.embeddedWalletSigner
11801
+ );
11802
+ await ctx.database.write(async () => {
11803
+ const current = await ctx.summariesCollection.query(Q4.where("id", record2.id)).fetch();
11804
+ if (current[0]?.summary === stored2.summary) {
11805
+ await current[0].update((rec) => {
11806
+ rec.summary = encryptedSummary;
11807
+ });
11808
+ }
11809
+ });
11810
+ } catch (error) {
11811
+ getLogger().warn("Failed to encrypt the legacy summary:", error);
11812
+ }
11813
+ }
11814
+ return stored2;
11815
+ }
11816
+ async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
11817
+ const revision2 = getConversationRevision(ctx.database, conversationId);
11818
+ let record2;
11819
+ const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
11820
+ await ctx.database.write(async () => {
11821
+ assertConversationRevision(ctx.database, conversationId, revision2);
11822
+ const existing = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
11823
+ if (existing.length > 0) {
11824
+ record2 = await existing[0].update((rec) => {
11825
+ rec.summary = encryptedSummary;
11826
+ rec.summarizedUpTo = summarizedUpTo;
11827
+ rec.tokenCount = tokenCount;
11828
+ });
11829
+ } else {
11830
+ record2 = await ctx.summariesCollection.create((rec) => {
11831
+ rec.conversationId = conversationId;
11832
+ rec.summary = encryptedSummary;
11833
+ rec.summarizedUpTo = summarizedUpTo;
11834
+ rec.tokenCount = tokenCount;
11835
+ });
11836
+ }
11837
+ });
11838
+ return modelToStored(record2, summary);
11839
+ }
11840
+ async function deleteConversationSummaryOp(ctx, conversationId) {
11841
+ await ctx.database.write(async () => {
11842
+ const existing = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
11843
+ for (const record2 of existing) {
11844
+ await record2.destroyPermanently();
11845
+ }
11846
+ });
11847
+ }
11848
+
11849
+ // src/lib/db/conversationMemory/models.ts
11850
+ import { Model as Model3 } from "@nozbe/watermelondb";
11851
+ import { date as date2, field as field2, readonly, text as text4 } from "@nozbe/watermelondb/decorators";
11852
+ var ConversationMemory = class extends Model3 {
11853
+ };
11854
+ ConversationMemory.table = "conversation_memory";
11855
+ ConversationMemory.associations = {};
11856
+ __decorateClass([
11857
+ text4("conversation_id")
11858
+ ], ConversationMemory.prototype, "conversationId", 2);
11859
+ __decorateClass([
11860
+ text4("memory_id")
11861
+ ], ConversationMemory.prototype, "memoryId", 2);
11862
+ __decorateClass([
11863
+ field2("score")
11864
+ ], ConversationMemory.prototype, "score", 2);
11865
+ __decorateClass([
11866
+ readonly,
11867
+ date2("created_at")
11868
+ ], ConversationMemory.prototype, "createdAt", 2);
11869
+
11728
11870
  // src/lib/chatStore/chatImports.ts
11729
11871
  var importBatch = 100;
11730
11872
  var importChunks = 200;
@@ -11816,17 +11958,6 @@ function batches(records) {
11816
11958
  return out;
11817
11959
  }
11818
11960
 
11819
- // src/lib/chatStore/types.ts
11820
- var ChatStoreError = class extends Error {
11821
- constructor(message, status, code, retryAfterMs) {
11822
- super(message);
11823
- this.status = status;
11824
- this.code = code;
11825
- this.retryAfterMs = retryAfterMs;
11826
- this.name = "ChatStoreError";
11827
- }
11828
- };
11829
-
11830
11961
  // src/lib/chatStore/remote.ts
11831
11962
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links", "setting"]);
11832
11963
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
@@ -12551,10 +12682,10 @@ async function deletedSinceUpload(store, journal, local, signal) {
12551
12682
  const present = /* @__PURE__ */ new Set([...local.records.map((r) => key(r.record)), ...local.skipped.keys()]);
12552
12683
  const gone = [...journal.keys].filter((k) => !present.has(k));
12553
12684
  if (gone.length === 0) return [];
12554
- const live = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
12555
- const tombstoning = new Set(live.map((s) => key(s.record)));
12685
+ const live2 = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
12686
+ const tombstoning = new Set(live2.map((s) => key(s.record)));
12556
12687
  await journal.drop(gone.filter((k) => !tombstoning.has(k)));
12557
- return live.map(({ record: record2, version }) => {
12688
+ return live2.map(({ record: record2, version }) => {
12558
12689
  const empty = emptied[record2.kind];
12559
12690
  return {
12560
12691
  record: {
@@ -13214,12 +13345,13 @@ var resumableFields = [
13214
13345
  "error",
13215
13346
  "thoughtProcess",
13216
13347
  "thinking",
13217
- "toolCallEvents"
13348
+ "toolCallEvents",
13349
+ "anuma"
13218
13350
  ];
13219
13351
  function resumedFields(options) {
13220
13352
  return plain(
13221
13353
  Object.fromEntries(
13222
- resumableFields.filter((f) => options[f] !== void 0).map((f) => [f, options[f]])
13354
+ resumableFields.filter((f) => options[f] !== void 0).map((f) => [f, f === "anuma" ? anumaTurnData(options.anuma) : options[f]])
13223
13355
  )
13224
13356
  );
13225
13357
  }
@@ -13873,7 +14005,7 @@ function createVaultChatBackend(options) {
13873
14005
  },
13874
14006
  async getConversations(query) {
13875
14007
  await available2();
13876
- return all("conversation").map(toConversation).filter(
14008
+ return all("conversation").filter((record2) => record2.id !== ANUMA_CONVERSATION_ID).map(toConversation).filter(
13877
14009
  (c) => query?.projectId === void 0 || (query.projectId === null ? !c.projectId : c.projectId === query.projectId)
13878
14010
  ).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
13879
14011
  },
@@ -13916,6 +14048,7 @@ function createVaultChatBackend(options) {
13916
14048
  return !!record2 && !record2.isDeleted;
13917
14049
  },
13918
14050
  async deleteConversation(conversationId) {
14051
+ if (conversationId === ANUMA_CONVERSATION_ID) return false;
13919
14052
  const record2 = await conversation(conversationId);
13920
14053
  if (!record2 || record2.isDeleted) return false;
13921
14054
  for (const [k, patch] of pending)
@@ -17986,7 +18119,7 @@ async function countActiveVaultMemoriesOp(ctx) {
17986
18119
  return ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx)).fetchCount();
17987
18120
  }
17988
18121
  async function getVaultMemoryCountsOp(ctx) {
17989
- const [live, archived, quarantined] = await Promise.all([
18122
+ const [live2, archived, quarantined] = await Promise.all([
17990
18123
  countActiveVaultMemoriesOp(ctx),
17991
18124
  ctx.vaultMemoryCollection.query(
17992
18125
  ...baseVaultConditions(ctx, { includeArchived: true }),
@@ -17997,7 +18130,7 @@ async function getVaultMemoryCountsOp(ctx) {
17997
18130
  Q9.where("trust_tier", "quarantined")
17998
18131
  ).fetchCount()
17999
18132
  ]);
18000
- return { live, archived, quarantined };
18133
+ return { live: live2, archived, quarantined };
18001
18134
  }
18002
18135
  async function getActiveVaultMemoryIdsOp(ctx, ids) {
18003
18136
  if (ids.length === 0) return /* @__PURE__ */ new Set();
@@ -19369,12 +19502,12 @@ var WalletPoller = class {
19369
19502
  * @param maxAttempts - Maximum polling attempts before giving up (default: 60)
19370
19503
  * @returns Stop function to cancel polling
19371
19504
  */
19372
- startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS) {
19505
+ startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts2 = DEFAULT_MAX_ATTEMPTS) {
19373
19506
  this.stop();
19374
19507
  this.attempts = 0;
19375
19508
  const poll = async () => {
19376
19509
  this.attempts++;
19377
- if (this.attempts > maxAttempts) {
19510
+ if (this.attempts > maxAttempts2) {
19378
19511
  this.stop();
19379
19512
  return;
19380
19513
  }
@@ -27141,13 +27274,13 @@ function createRemoteMemoryStore(options) {
27141
27274
  });
27142
27275
  return run;
27143
27276
  };
27144
- const live = async (id2) => {
27277
+ const live2 = async (id2) => {
27145
27278
  const record2 = await persistence.get(id2);
27146
27279
  return record2 && !record2.memory.is_deleted ? record2 : null;
27147
27280
  };
27148
27281
  const mutateLocked = async (id2, change, edit, writeOptions) => {
27149
27282
  writeOptions?.signal?.throwIfAborted();
27150
- const record2 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live(id2);
27283
+ const record2 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live2(id2);
27151
27284
  if (!record2) return null;
27152
27285
  if (record2.memory.is_deleted) return null;
27153
27286
  if (writeOptions?.canWrite && !await writeOptions.canWrite())
@@ -27945,7 +28078,7 @@ function createRemoteMemoryStore(options) {
27945
28078
  }, clear);
27946
28079
  return snapshot.then((topics) => structuredClone(topics));
27947
28080
  },
27948
- get: async (id2) => asStored(await live(id2)),
28081
+ get: async (id2) => asStored(await live2(id2)),
27949
28082
  listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
27950
28083
  (record2) => stored(record2.memory)
27951
28084
  ),
@@ -28030,7 +28163,7 @@ function createRemoteMemoryStore(options) {
28030
28163
  return serialized(
28031
28164
  first,
28032
28165
  () => serialized(second, async () => {
28033
- const [old, next] = await Promise.all([live(id2), live(supersededById)]);
28166
+ const [old, next] = await Promise.all([live2(id2), live2(supersededById)]);
28034
28167
  if (!old || !next || old.memory.superseded_by || next.memory.superseded_by) return false;
28035
28168
  if (old.memory.kind !== void 0 && old.memory.kind !== null) return false;
28036
28169
  const saved = await persistence.putMany([
@@ -28051,7 +28184,7 @@ function createRemoteMemoryStore(options) {
28051
28184
  (memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
28052
28185
  ),
28053
28186
  restore: (id2) => serialized(id2, async () => {
28054
- const record2 = await live(id2);
28187
+ const record2 = await live2(id2);
28055
28188
  if (!record2) return false;
28056
28189
  if (record2.memory.archived_at === void 0 || record2.memory.archived_at === null)
28057
28190
  return true;
@@ -39661,11 +39794,11 @@ function usePhoneCalls(options = {}) {
39661
39794
  pollRunIdRef.current = runId;
39662
39795
  setIsPolling(true);
39663
39796
  const intervalMs = pollOptions.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
39664
- const maxAttempts = pollOptions.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS;
39797
+ const maxAttempts2 = pollOptions.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS;
39665
39798
  const stopWhenCompleted = pollOptions.stopWhenCompleted ?? true;
39666
39799
  let latestCall = null;
39667
39800
  try {
39668
- for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
39801
+ for (let attempt = 0; attempt < maxAttempts2; attempt += 1) {
39669
39802
  if (pollRunIdRef.current !== runId) {
39670
39803
  break;
39671
39804
  }
@@ -39695,7 +39828,7 @@ function usePhoneCalls(options = {}) {
39695
39828
  break;
39696
39829
  }
39697
39830
  }
39698
- if (attempt < maxAttempts - 1) {
39831
+ if (attempt < maxAttempts2 - 1) {
39699
39832
  await wait2(intervalMs);
39700
39833
  }
39701
39834
  }
@@ -41213,6 +41346,7 @@ function useWalletBinding(options = {}) {
41213
41346
  };
41214
41347
  }
41215
41348
  export {
41349
+ ANUMA_CONVERSATION_ID,
41216
41350
  Anuma,
41217
41351
  AnumaJsxError,
41218
41352
  AnumaShadowIsolationProvider,
@@ -41317,6 +41451,8 @@ export {
41317
41451
  WordProcessor,
41318
41452
  ZipProcessor,
41319
41453
  addConversationMemoriesOp,
41454
+ anumaLastReadSortKey,
41455
+ anumaTurnContent,
41320
41456
  appFileToStored,
41321
41457
  archiveVaultMemoryOp,
41322
41458
  assembleMemoryContext,
@@ -41356,6 +41492,7 @@ export {
41356
41492
  consoleLogger,
41357
41493
  conversationMemoryToStored,
41358
41494
  cosineInt8,
41495
+ countUnreadAnumaTurns,
41359
41496
  createAutoExtractor,
41360
41497
  createChunkVectorCache,
41361
41498
  createCryptoPricePreProcessor,
@@ -41425,6 +41562,7 @@ export {
41425
41562
  encryptDataBytes,
41426
41563
  encryptDataWithKey,
41427
41564
  encryptToolCallEventsOp,
41565
+ ensureAnumaConversation,
41428
41566
  ensureDefaultFoldersOp,
41429
41567
  expandToolSetsAdditive,
41430
41568
  exportElementToPdf,
@@ -41535,6 +41673,7 @@ export {
41535
41673
  listActiveStreams,
41536
41674
  loadSettings,
41537
41675
  localChatBackend,
41676
+ markAnumaRead,
41538
41677
  maskScopedEmbeddingCache,
41539
41678
  maxVaultAttachmentBytes,
41540
41679
  mediaToStored,
@@ -41560,6 +41699,7 @@ export {
41560
41699
  quantizeEmbedding,
41561
41700
  queueManager,
41562
41701
  rankProfileCandidates,
41702
+ readAnumaTurn,
41563
41703
  readEncryptedFile,
41564
41704
  recall,
41565
41705
  reencryptMemoryField,