@anuma/sdk 10.7.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.
@@ -880,17 +880,17 @@ async function callPortalJsonCompletion(req) {
880
880
  if (autoUpgraded) endpoint = endpointForTransport(endpoint, transport);
881
881
  assertTransportMatchesEndpoint(transport, endpoint);
882
882
  }
883
- const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
883
+ const maxAttempts2 = Math.max(1, req.maxAttempts ?? 3);
884
884
  const startedAt = Date.now();
885
885
  const deadlineAt = req.totalTimeoutMs === void 0 ? void 0 : startedAt + req.totalTimeoutMs;
886
886
  const overBudget = () => deadlineAt !== void 0 && Date.now() >= deadlineAt;
887
887
  let lastFailure;
888
888
  let reinforce = false;
889
889
  const giveUp = () => {
890
- req.onFailure?.(lastFailure ?? { reason: "network", attempts: maxAttempts });
890
+ req.onFailure?.(lastFailure ?? { reason: "network", attempts: maxAttempts2 });
891
891
  return null;
892
892
  };
893
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
893
+ for (let attempt = 1; attempt <= maxAttempts2; attempt++) {
894
894
  if (attempt > 1 && overBudget()) {
895
895
  log.warn(`[${req.tag}] over time budget before attempt ${attempt}, giving up`);
896
896
  lastFailure = { reason: "time-budget-exhausted", attempts: attempt - 1 };
@@ -922,20 +922,20 @@ async function callPortalJsonCompletion(req) {
922
922
  log.warn(`[${req.tag}] ${outcome2.reason}`);
923
923
  return giveUp();
924
924
  }
925
- if (attempt >= maxAttempts) {
926
- log.warn(`[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts}, giving up`);
925
+ if (attempt >= maxAttempts2) {
926
+ log.warn(`[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts2}, giving up`);
927
927
  break;
928
928
  }
929
929
  const backoff = (req.backoffMs ?? defaultBackoffMs)(attempt);
930
930
  const delay = Math.max(backoff, outcome2.retryAfterMs ?? 0);
931
931
  if (overBudget() || req.totalTimeoutMs !== void 0 && Date.now() - startedAt + delay >= req.totalTimeoutMs) {
932
932
  log.warn(
933
- `[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts}, over time budget, giving up`
933
+ `[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts2}, over time budget, giving up`
934
934
  );
935
935
  lastFailure = { reason: "time-budget-exhausted", attempts: attempt };
936
936
  break;
937
937
  }
938
- log.warn(`[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts}, retrying`);
938
+ log.warn(`[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts2}, retrying`);
939
939
  if (delay > 0) await sleep2(delay);
940
940
  }
941
941
  return giveUp();
@@ -1419,6 +1419,7 @@ CARRY FORWARD UNCHANGED DETAILS (every "update" and "supersede"): a memory can h
1419
1419
  // src/expo/index.ts
1420
1420
  var index_exports = {};
1421
1421
  __export(index_exports, {
1422
+ ANUMA_CONVERSATION_ID: () => ANUMA_CONVERSATION_ID,
1422
1423
  CHUNKS_DISCARDED_ORIGIN: () => CHUNKS_DISCARDED_ORIGIN,
1423
1424
  ChatConversation: () => Conversation,
1424
1425
  ChatMessage: () => Message,
@@ -1478,6 +1479,8 @@ __export(index_exports, {
1478
1479
  WALLET_PAYMENT_TOOL_NAME: () => WALLET_PAYMENT_TOOL_NAME,
1479
1480
  WalletPoller: () => WalletPoller,
1480
1481
  addConversationMemoriesOp: () => addConversationMemoriesOp,
1482
+ anumaLastReadSortKey: () => anumaLastReadSortKey,
1483
+ anumaTurnContent: () => anumaTurnContent,
1481
1484
  archiveVaultMemoryOp: () => archiveVaultMemoryOp,
1482
1485
  assembleMemoryContext: () => assembleMemoryContext,
1483
1486
  attachFileContextToLastUserMessage: () => attachFileContextToLastUserMessage,
@@ -1511,6 +1514,7 @@ __export(index_exports, {
1511
1514
  consoleLogger: () => consoleLogger,
1512
1515
  conversationMemoryToStored: () => conversationMemoryToStored,
1513
1516
  cosineInt8: () => cosineInt8,
1517
+ countUnreadAnumaTurns: () => countUnreadAnumaTurns,
1514
1518
  createAutoExtractor: () => createAutoExtractor,
1515
1519
  createChunkVectorCache: () => createChunkVectorCache,
1516
1520
  createCryptoPricePreProcessor: () => createCryptoPricePreProcessor,
@@ -1559,6 +1563,7 @@ __export(index_exports, {
1559
1563
  embedMessage: () => embedMessage,
1560
1564
  encodeChunkVector: () => encodeChunkVector,
1561
1565
  encryptToolCallEventsOp: () => encryptToolCallEventsOp,
1566
+ ensureAnumaConversation: () => ensureAnumaConversation,
1562
1567
  ensureDefaultFoldersOp: () => ensureDefaultFoldersOp,
1563
1568
  exchangeNotionCode: () => exchangeNotionCode,
1564
1569
  extractAndLinkEntitiesForMemoriesOp: () => extractAndLinkEntitiesForMemoriesOp,
@@ -1599,6 +1604,7 @@ __export(index_exports, {
1599
1604
  isRerankerAvailable: () => isRerankerAvailable,
1600
1605
  loadSettings: () => loadSettings,
1601
1606
  localChatBackend: () => localChatBackend,
1607
+ markAnumaRead: () => markAnumaRead,
1602
1608
  maskScopedEmbeddingCache: () => maskScopedEmbeddingCache,
1603
1609
  maxVaultAttachmentBytes: () => maxVaultAttachmentBytes,
1604
1610
  memoryCipher: () => memoryCipher,
@@ -1614,6 +1620,7 @@ __export(index_exports, {
1614
1620
  quantizeEmbedding: () => quantizeEmbedding,
1615
1621
  queueManager: () => queueManager,
1616
1622
  rankProfileCandidates: () => rankProfileCandidates,
1623
+ readAnumaTurn: () => readAnumaTurn,
1617
1624
  recall: () => recall,
1618
1625
  reencryptMemoryField: () => reencryptMemoryField,
1619
1626
  reflect: () => reflect,
@@ -11591,119 +11598,19 @@ var xhrTransport = (options) => {
11591
11598
  return { stream: createStream() };
11592
11599
  };
11593
11600
 
11594
- // src/lib/db/chat/summaryOperations.ts
11595
- var import_watermelondb5 = require("@nozbe/watermelondb");
11596
- init_logger();
11597
- function createSummaryContext(database, encryption = {}) {
11598
- return {
11599
- ...encryption,
11600
- database,
11601
- summariesCollection: database.get("conversation_summaries")
11602
- };
11603
- }
11604
- function modelToStored(record2, summary) {
11605
- return {
11606
- uniqueId: record2.id,
11607
- conversationId: record2.conversationId,
11608
- summary,
11609
- summarizedUpTo: record2.summarizedUpTo,
11610
- tokenCount: record2.tokenCount,
11611
- createdAt: record2.createdAt,
11612
- updatedAt: record2.updatedAt
11613
- };
11614
- }
11615
- async function getConversationSummaryOp(ctx, conversationId) {
11616
- const results = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
11617
- if (results.length === 0) return null;
11618
- const record2 = results[0];
11619
- const stored2 = modelToStored(record2, record2.summary);
11620
- if (ctx.walletAddress && isEncrypted(stored2.summary)) {
11621
- if (ctx.signMessage) {
11622
- try {
11623
- await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
11624
- } catch (error) {
11625
- getLogger().warn("Failed to request the encryption key for the summary:", error);
11626
- }
11627
- }
11628
- stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
11629
- } else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
11630
- try {
11631
- const encryptedSummary = await encryptField(
11632
- stored2.summary,
11633
- ctx.walletAddress,
11634
- ctx.signMessage,
11635
- ctx.embeddedWalletSigner
11636
- );
11637
- await ctx.database.write(async () => {
11638
- const current = await ctx.summariesCollection.query(import_watermelondb5.Q.where("id", record2.id)).fetch();
11639
- if (current[0]?.summary === stored2.summary) {
11640
- await current[0].update((rec) => {
11641
- rec.summary = encryptedSummary;
11642
- });
11643
- }
11644
- });
11645
- } catch (error) {
11646
- getLogger().warn("Failed to encrypt the legacy summary:", error);
11647
- }
11601
+ // src/lib/chatStore/types.ts
11602
+ var ChatStoreError = class extends Error {
11603
+ constructor(message, status, code, retryAfterMs) {
11604
+ super(message);
11605
+ this.status = status;
11606
+ this.code = code;
11607
+ this.retryAfterMs = retryAfterMs;
11608
+ this.name = "ChatStoreError";
11648
11609
  }
11649
- return stored2;
11650
- }
11651
- async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
11652
- const revision2 = getConversationRevision(ctx.database, conversationId);
11653
- let record2;
11654
- const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
11655
- await ctx.database.write(async () => {
11656
- assertConversationRevision(ctx.database, conversationId, revision2);
11657
- const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
11658
- if (existing.length > 0) {
11659
- record2 = await existing[0].update((rec) => {
11660
- rec.summary = encryptedSummary;
11661
- rec.summarizedUpTo = summarizedUpTo;
11662
- rec.tokenCount = tokenCount;
11663
- });
11664
- } else {
11665
- record2 = await ctx.summariesCollection.create((rec) => {
11666
- rec.conversationId = conversationId;
11667
- rec.summary = encryptedSummary;
11668
- rec.summarizedUpTo = summarizedUpTo;
11669
- rec.tokenCount = tokenCount;
11670
- });
11671
- }
11672
- });
11673
- return modelToStored(record2, summary);
11674
- }
11675
- async function deleteConversationSummaryOp(ctx, conversationId) {
11676
- await ctx.database.write(async () => {
11677
- const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
11678
- for (const record2 of existing) {
11679
- await record2.destroyPermanently();
11680
- }
11681
- });
11682
- }
11683
-
11684
- // src/lib/db/conversationMemory/models.ts
11685
- var import_watermelondb6 = require("@nozbe/watermelondb");
11686
- var import_decorators2 = require("@nozbe/watermelondb/decorators");
11687
- var ConversationMemory = class extends import_watermelondb6.Model {
11688
11610
  };
11689
- ConversationMemory.table = "conversation_memory";
11690
- ConversationMemory.associations = {};
11691
- __decorateClass([
11692
- (0, import_decorators2.text)("conversation_id")
11693
- ], ConversationMemory.prototype, "conversationId", 2);
11694
- __decorateClass([
11695
- (0, import_decorators2.text)("memory_id")
11696
- ], ConversationMemory.prototype, "memoryId", 2);
11697
- __decorateClass([
11698
- (0, import_decorators2.field)("score")
11699
- ], ConversationMemory.prototype, "score", 2);
11700
- __decorateClass([
11701
- import_decorators2.readonly,
11702
- (0, import_decorators2.date)("created_at")
11703
- ], ConversationMemory.prototype, "createdAt", 2);
11704
11611
 
11705
11612
  // src/lib/db/conversationMemory/operations.ts
11706
- var import_watermelondb7 = require("@nozbe/watermelondb");
11613
+ var import_watermelondb5 = require("@nozbe/watermelondb");
11707
11614
  var MAX_PER_CONVERSATION = 200;
11708
11615
  function conversationMemoryToStored(row) {
11709
11616
  return {
@@ -11718,7 +11625,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
11718
11625
  if (!conversationId || items.length === 0) return;
11719
11626
  const now = Date.now();
11720
11627
  await ctx.database.write(async () => {
11721
- const existing = await ctx.conversationMemoryCollection.query(import_watermelondb7.Q.where("conversation_id", conversationId), import_watermelondb7.Q.sortBy("created_at", import_watermelondb7.Q.asc)).fetch();
11628
+ const existing = await ctx.conversationMemoryCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.sortBy("created_at", import_watermelondb5.Q.asc)).fetch();
11722
11629
  const seen = new Set(existing.map((r) => r.memoryId));
11723
11630
  const batchSeen = /* @__PURE__ */ new Set();
11724
11631
  const deduped = [];
@@ -11755,7 +11662,7 @@ async function recordConversationMemoriesOp(ctx, conversationId, items, now = Da
11755
11662
  if (!conversationId || turn.size === 0) return;
11756
11663
  const kept = new Map([...turn].slice(-MAX_PER_CONVERSATION));
11757
11664
  await ctx.database.write(async () => {
11758
- const existing = await ctx.conversationMemoryCollection.query(import_watermelondb7.Q.where("conversation_id", conversationId), import_watermelondb7.Q.sortBy("created_at", import_watermelondb7.Q.asc)).fetch();
11665
+ const existing = await ctx.conversationMemoryCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.sortBy("created_at", import_watermelondb5.Q.asc)).fetch();
11759
11666
  const earlier = existing.filter((r) => !turn.has(r.memoryId));
11760
11667
  const linked = new Set(existing.map((r) => r.memoryId));
11761
11668
  await ctx.database.batch(
@@ -11780,13 +11687,13 @@ async function recordConversationMemoriesOp(ctx, conversationId, items, now = Da
11780
11687
  }
11781
11688
  async function getConversationMemoriesOp(ctx, conversationId) {
11782
11689
  if (!conversationId) return [];
11783
- const rows = await ctx.conversationMemoryCollection.query(import_watermelondb7.Q.where("conversation_id", conversationId), import_watermelondb7.Q.sortBy("created_at", import_watermelondb7.Q.asc)).fetch();
11690
+ const rows = await ctx.conversationMemoryCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.sortBy("created_at", import_watermelondb5.Q.asc)).fetch();
11784
11691
  return rows.map(conversationMemoryToStored);
11785
11692
  }
11786
11693
  async function clearConversationMemoriesOp(ctx, conversationId) {
11787
11694
  if (!conversationId) return;
11788
11695
  await ctx.database.write(async () => {
11789
- const rows = await ctx.conversationMemoryCollection.query(import_watermelondb7.Q.where("conversation_id", conversationId)).fetch();
11696
+ const rows = await ctx.conversationMemoryCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
11790
11697
  if (rows.length === 0) return;
11791
11698
  await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
11792
11699
  });
@@ -11801,46 +11708,93 @@ var maxChunks = 16;
11801
11708
  var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
11802
11709
  var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
11803
11710
  var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
11711
+ var maxBubbles = 3;
11712
+ var maxTurnIdBytes = 128;
11713
+ var maxBubbleBytes = 16384;
11714
+ var anumaOrigins = /* @__PURE__ */ new Set(["intro", "reply"]);
11804
11715
  function plain(value) {
11805
11716
  return JSON.parse(JSON.stringify(value ?? {}));
11806
11717
  }
11807
- function text4(value) {
11718
+ function text3(value) {
11808
11719
  return typeof value === "string" ? value : void 0;
11809
11720
  }
11810
11721
  function number(value) {
11811
11722
  return typeof value === "number" ? value : void 0;
11812
11723
  }
11724
+ function readAnumaTurn(value) {
11725
+ if (!isObject(value)) return void 0;
11726
+ const { turnId, bubbles, origin } = value;
11727
+ if (typeof turnId !== "string" || turnId.length === 0 || new TextEncoder().encode(turnId).length > maxTurnIdBytes)
11728
+ return void 0;
11729
+ 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))
11730
+ return void 0;
11731
+ if (origin !== void 0 && (typeof origin !== "string" || !anumaOrigins.has(origin)))
11732
+ return void 0;
11733
+ return {
11734
+ turnId,
11735
+ ...bubbles !== void 0 ? { bubbles: [...bubbles] } : {},
11736
+ ...origin !== void 0 ? { origin } : {}
11737
+ };
11738
+ }
11739
+ function isObject(value) {
11740
+ return value !== null && typeof value === "object" && !Array.isArray(value);
11741
+ }
11813
11742
  function conversationSortKey(data, createdAt) {
11814
11743
  const pinnedAt = number(data.pinnedAt);
11815
11744
  if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
11816
11745
  return number(data.lastActivityAt) ?? createdAt;
11817
11746
  }
11747
+ var CONTEXT_FIELD_PREFIX = "context.";
11748
+ function contextField(key3) {
11749
+ return `${CONTEXT_FIELD_PREFIX}${key3}`;
11750
+ }
11751
+ function contextFields(context) {
11752
+ return plain(
11753
+ Object.fromEntries(Object.entries(context ?? {}).map(([k, value]) => [contextField(k), value]))
11754
+ );
11755
+ }
11756
+ function conversationContext(data) {
11757
+ const entries = Object.entries(data).filter(([field10]) => field10.startsWith(CONTEXT_FIELD_PREFIX)).map(([field10, value]) => [field10.slice(CONTEXT_FIELD_PREFIX.length), value]);
11758
+ return entries.length > 0 ? plain(Object.fromEntries(entries)) : void 0;
11759
+ }
11818
11760
  function toConversation(record2) {
11819
11761
  const pinnedAt = number(record2.data.pinnedAt);
11820
- const projectId = text4(record2.data.projectId);
11762
+ const projectId = text3(record2.data.projectId);
11763
+ const context = conversationContext(record2.data);
11821
11764
  return {
11822
11765
  uniqueId: record2.id,
11823
11766
  conversationId: record2.id,
11824
- title: text4(record2.data.title) ?? "",
11767
+ title: text3(record2.data.title) ?? "",
11825
11768
  ...projectId ? { projectId } : {},
11826
11769
  createdAt: new Date(record2.createdAt),
11827
11770
  updatedAt: new Date(record2.updatedAt),
11828
11771
  isDeleted: record2.isDeleted,
11829
- pinnedAt: pinnedAt ? new Date(pinnedAt) : null
11772
+ pinnedAt: pinnedAt ? new Date(pinnedAt) : null,
11773
+ ...context ? { context } : {}
11830
11774
  };
11831
11775
  }
11776
+ function anumaTurnData(value) {
11777
+ if (value === void 0) return void 0;
11778
+ const turn = readAnumaTurn(value);
11779
+ if (!turn) throw new ChatStoreError("Invalid Anuma turn", 0, "invalid_record");
11780
+ return turn;
11781
+ }
11832
11782
  function messageData(options) {
11833
- return plain(
11834
- Object.fromEntries(
11783
+ const anuma = anumaTurnData(options.anuma);
11784
+ return plain({
11785
+ ...Object.fromEntries(
11835
11786
  Object.entries(options).filter(
11836
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
11787
+ ([key3, value]) => key3 !== "anuma" && !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
11837
11788
  )
11838
- )
11839
- );
11789
+ ),
11790
+ ...anuma ? { anuma } : {}
11791
+ });
11840
11792
  }
11841
11793
  function toMessage(record2) {
11842
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
11794
+ const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } = record2.data;
11795
+ const anuma = readAnumaTurn(rawAnuma);
11843
11796
  return {
11797
+ ...anuma ? { anuma } : {},
11844
11798
  ...fields,
11845
11799
  uniqueId: record2.id,
11846
11800
  messageId: record2.sortKey,
@@ -11854,20 +11808,20 @@ function chunkOffsets(record2) {
11854
11808
  return Array.isArray(offsets) ? offsets : void 0;
11855
11809
  }
11856
11810
  function toSkeletons(records) {
11857
- const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
11811
+ const roleById = new Map(records.map((r) => [r.id, text3(r.data.role)]));
11858
11812
  return records.map((r) => {
11859
- const parentMessageId = text4(r.data.parentMessageId);
11860
- const model = text4(r.data.model);
11813
+ const parentMessageId = text3(r.data.parentMessageId);
11814
+ const model = text3(r.data.model);
11861
11815
  const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
11862
11816
  return {
11863
11817
  uniqueId: r.id,
11864
11818
  messageId: r.sortKey,
11865
11819
  conversationId: r.conversationId,
11866
- role: text4(r.data.role) ?? "",
11820
+ role: text3(r.data.role) ?? "",
11867
11821
  createdAt: new Date(r.createdAt),
11868
11822
  ...parentMessageId ? { parentMessageId } : {},
11869
11823
  ...model ? { model } : {},
11870
- ...artifact ? { content: text4(r.data.content) ?? "" } : {}
11824
+ ...artifact ? { content: text3(r.data.content) ?? "" } : {}
11871
11825
  };
11872
11826
  });
11873
11827
  }
@@ -11875,8 +11829,8 @@ function toSummary(record2) {
11875
11829
  return {
11876
11830
  uniqueId: record2.id,
11877
11831
  conversationId: record2.id,
11878
- summary: text4(record2.data.summary) ?? "",
11879
- summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
11832
+ summary: text3(record2.data.summary) ?? "",
11833
+ summarizedUpTo: text3(record2.data.summarizedUpTo) ?? "",
11880
11834
  tokenCount: number(record2.data.tokenCount) ?? 0,
11881
11835
  createdAt: new Date(record2.createdAt),
11882
11836
  updatedAt: new Date(record2.updatedAt)
@@ -11927,7 +11881,7 @@ function fitRecord(record2) {
11927
11881
  delete data[field10];
11928
11882
  truncated.push(field10);
11929
11883
  }
11930
- const content = text4(data.content) ?? "";
11884
+ const content = text3(data.content) ?? "";
11931
11885
  const over = bytes({ ...record2, data }) - recordBudgetBytes;
11932
11886
  if (over > 0) {
11933
11887
  const encoded = new TextEncoder().encode(content);
@@ -11971,6 +11925,216 @@ function fitChunks(chunks3) {
11971
11925
  return out;
11972
11926
  }
11973
11927
 
11928
+ // src/lib/chatStore/anuma.ts
11929
+ var ANUMA_CONVERSATION_ID = "anuma-1on1";
11930
+ var maxAttempts = 3;
11931
+ function anumaTurnContent(bubbles) {
11932
+ return bubbles.join("\n\n");
11933
+ }
11934
+ function anumaLastReadSortKey(conversation) {
11935
+ const record2 = conversation && "record" in conversation ? conversation.record : conversation;
11936
+ const state = record2?.data.anuma;
11937
+ if (!isObject(state)) return 0;
11938
+ const sortKey = state.lastReadSortKey;
11939
+ return Number.isSafeInteger(sortKey) && sortKey > 0 ? sortKey : 0;
11940
+ }
11941
+ function conflict(error) {
11942
+ return error instanceof ChatStoreError && error.code === "version_conflict";
11943
+ }
11944
+ function live(snapshot) {
11945
+ if (snapshot?.record.isDeleted)
11946
+ throw new ChatStoreError("Anuma conversation was deleted", 409, "conversation_deleted");
11947
+ return snapshot;
11948
+ }
11949
+ async function ensureAnumaConversation(store, options = {}) {
11950
+ const existing = live(await store.get("conversation", ANUMA_CONVERSATION_ID, options.signal));
11951
+ if (existing) return existing;
11952
+ const at = (options.now ?? Date.now)();
11953
+ const data = plain({ title: "Anuma", lastActivityAt: at, anuma: { lastReadSortKey: 0 } });
11954
+ try {
11955
+ const [created] = await store.putMany(
11956
+ [
11957
+ {
11958
+ expectedVersion: 0,
11959
+ record: {
11960
+ kind: "conversation",
11961
+ id: ANUMA_CONVERSATION_ID,
11962
+ conversationId: "",
11963
+ sortKey: conversationSortKey(data, at),
11964
+ createdAt: at,
11965
+ updatedAt: at,
11966
+ isDeleted: false,
11967
+ data
11968
+ }
11969
+ }
11970
+ ],
11971
+ options.signal
11972
+ );
11973
+ return created;
11974
+ } catch (error) {
11975
+ if (!conflict(error)) throw error;
11976
+ const winner = live(await store.get("conversation", ANUMA_CONVERSATION_ID, options.signal));
11977
+ if (!winner) throw error;
11978
+ return winner;
11979
+ }
11980
+ }
11981
+ async function markAnumaRead(store, sortKey, options = {}) {
11982
+ if (!Number.isSafeInteger(sortKey) || sortKey < 0)
11983
+ throw new ChatStoreError("Invalid Anuma read marker", 0, "invalid_record");
11984
+ const now = options.now ?? Date.now;
11985
+ for (let attempt = 1; ; attempt++) {
11986
+ const current = await ensureAnumaConversation(store, options);
11987
+ const read = anumaLastReadSortKey(current);
11988
+ if (sortKey <= read) return current;
11989
+ const record2 = current.record;
11990
+ const state = isObject(record2.data.anuma) ? record2.data.anuma : {};
11991
+ const data = plain({ ...record2.data, anuma: { ...state, lastReadSortKey: sortKey } });
11992
+ try {
11993
+ const [written] = await store.putMany(
11994
+ [
11995
+ {
11996
+ expectedVersion: current.version,
11997
+ record: {
11998
+ ...record2,
11999
+ data,
12000
+ sortKey: conversationSortKey(data, record2.createdAt),
12001
+ updatedAt: Math.max(record2.updatedAt, now())
12002
+ }
12003
+ }
12004
+ ],
12005
+ options.signal
12006
+ );
12007
+ return written;
12008
+ } catch (error) {
12009
+ if (!conflict(error) || attempt >= maxAttempts) throw error;
12010
+ }
12011
+ }
12012
+ }
12013
+ function countUnreadAnumaTurns(messages, lastReadSortKey) {
12014
+ const answered = Math.max(
12015
+ 0,
12016
+ ...messages.filter((m) => m.role === "user").map((m) => m.messageId)
12017
+ );
12018
+ const floor = Math.max(lastReadSortKey, answered);
12019
+ const turns = /* @__PURE__ */ new Set();
12020
+ for (const m of messages) {
12021
+ if (m.role !== "assistant" || m.messageId <= floor) continue;
12022
+ turns.add(m.anuma?.turnId ? `turn:${m.anuma.turnId}` : `message:${m.uniqueId}`);
12023
+ }
12024
+ return turns.size;
12025
+ }
12026
+
12027
+ // src/lib/db/chat/summaryOperations.ts
12028
+ var import_watermelondb6 = require("@nozbe/watermelondb");
12029
+ init_logger();
12030
+ function createSummaryContext(database, encryption = {}) {
12031
+ return {
12032
+ ...encryption,
12033
+ database,
12034
+ summariesCollection: database.get("conversation_summaries")
12035
+ };
12036
+ }
12037
+ function modelToStored(record2, summary) {
12038
+ return {
12039
+ uniqueId: record2.id,
12040
+ conversationId: record2.conversationId,
12041
+ summary,
12042
+ summarizedUpTo: record2.summarizedUpTo,
12043
+ tokenCount: record2.tokenCount,
12044
+ createdAt: record2.createdAt,
12045
+ updatedAt: record2.updatedAt
12046
+ };
12047
+ }
12048
+ async function getConversationSummaryOp(ctx, conversationId) {
12049
+ const results = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
12050
+ if (results.length === 0) return null;
12051
+ const record2 = results[0];
12052
+ const stored2 = modelToStored(record2, record2.summary);
12053
+ if (ctx.walletAddress && isEncrypted(stored2.summary)) {
12054
+ if (ctx.signMessage) {
12055
+ try {
12056
+ await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
12057
+ } catch (error) {
12058
+ getLogger().warn("Failed to request the encryption key for the summary:", error);
12059
+ }
12060
+ }
12061
+ stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
12062
+ } else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
12063
+ try {
12064
+ const encryptedSummary = await encryptField(
12065
+ stored2.summary,
12066
+ ctx.walletAddress,
12067
+ ctx.signMessage,
12068
+ ctx.embeddedWalletSigner
12069
+ );
12070
+ await ctx.database.write(async () => {
12071
+ const current = await ctx.summariesCollection.query(import_watermelondb6.Q.where("id", record2.id)).fetch();
12072
+ if (current[0]?.summary === stored2.summary) {
12073
+ await current[0].update((rec) => {
12074
+ rec.summary = encryptedSummary;
12075
+ });
12076
+ }
12077
+ });
12078
+ } catch (error) {
12079
+ getLogger().warn("Failed to encrypt the legacy summary:", error);
12080
+ }
12081
+ }
12082
+ return stored2;
12083
+ }
12084
+ async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
12085
+ const revision2 = getConversationRevision(ctx.database, conversationId);
12086
+ let record2;
12087
+ const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
12088
+ await ctx.database.write(async () => {
12089
+ assertConversationRevision(ctx.database, conversationId, revision2);
12090
+ const existing = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
12091
+ if (existing.length > 0) {
12092
+ record2 = await existing[0].update((rec) => {
12093
+ rec.summary = encryptedSummary;
12094
+ rec.summarizedUpTo = summarizedUpTo;
12095
+ rec.tokenCount = tokenCount;
12096
+ });
12097
+ } else {
12098
+ record2 = await ctx.summariesCollection.create((rec) => {
12099
+ rec.conversationId = conversationId;
12100
+ rec.summary = encryptedSummary;
12101
+ rec.summarizedUpTo = summarizedUpTo;
12102
+ rec.tokenCount = tokenCount;
12103
+ });
12104
+ }
12105
+ });
12106
+ return modelToStored(record2, summary);
12107
+ }
12108
+ async function deleteConversationSummaryOp(ctx, conversationId) {
12109
+ await ctx.database.write(async () => {
12110
+ const existing = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
12111
+ for (const record2 of existing) {
12112
+ await record2.destroyPermanently();
12113
+ }
12114
+ });
12115
+ }
12116
+
12117
+ // src/lib/db/conversationMemory/models.ts
12118
+ var import_watermelondb7 = require("@nozbe/watermelondb");
12119
+ var import_decorators2 = require("@nozbe/watermelondb/decorators");
12120
+ var ConversationMemory = class extends import_watermelondb7.Model {
12121
+ };
12122
+ ConversationMemory.table = "conversation_memory";
12123
+ ConversationMemory.associations = {};
12124
+ __decorateClass([
12125
+ (0, import_decorators2.text)("conversation_id")
12126
+ ], ConversationMemory.prototype, "conversationId", 2);
12127
+ __decorateClass([
12128
+ (0, import_decorators2.text)("memory_id")
12129
+ ], ConversationMemory.prototype, "memoryId", 2);
12130
+ __decorateClass([
12131
+ (0, import_decorators2.field)("score")
12132
+ ], ConversationMemory.prototype, "score", 2);
12133
+ __decorateClass([
12134
+ import_decorators2.readonly,
12135
+ (0, import_decorators2.date)("created_at")
12136
+ ], ConversationMemory.prototype, "createdAt", 2);
12137
+
11974
12138
  // src/lib/chatStore/chatImports.ts
11975
12139
  var importBatch = 100;
11976
12140
  var importChunks = 200;
@@ -11985,6 +12149,7 @@ function bytes2(value) {
11985
12149
  function conversationRecord(conversation, messages) {
11986
12150
  const createdAt = ms(conversation.createdAt);
11987
12151
  const data = plain({
12152
+ ...contextFields(conversation.context),
11988
12153
  title: conversation.title,
11989
12154
  projectId: conversation.projectId || void 0,
11990
12155
  pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
@@ -12554,17 +12719,17 @@ async function createRemoteMemoryPersistence(options) {
12554
12719
  expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
12555
12720
  if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
12556
12721
  throw new Error("expectedVersion must be a nonnegative integer");
12557
- const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
12722
+ const conflict2 = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
12558
12723
  let existing;
12559
12724
  if (expectedVersion !== 0 && !snapshot) {
12560
12725
  try {
12561
12726
  existing = memoryRecord(await request(path, {}, signal));
12562
12727
  } catch (error) {
12563
- if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
12728
+ if (error instanceof RemoteMemoryError && error.status === 404) throw conflict2();
12564
12729
  throw error;
12565
12730
  }
12566
12731
  }
12567
- if (existing && existing.version !== expectedVersion) throw conflict();
12732
+ if (existing && existing.version !== expectedVersion) throw conflict2();
12568
12733
  const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
12569
12734
  const reusableContent = snapshot?.encryptedContent ?? existing?.memory.content;
12570
12735
  const content = reusableContent && (snapshot?.content ?? decoded?.memory.content) === memory.content ? reusableContent : await encryptField2(memory.content);
@@ -12789,17 +12954,6 @@ async function createRemoteMemoryPersistence(options) {
12789
12954
  };
12790
12955
  }
12791
12956
 
12792
- // src/lib/chatStore/types.ts
12793
- var ChatStoreError = class extends Error {
12794
- constructor(message, status, code, retryAfterMs) {
12795
- super(message);
12796
- this.status = status;
12797
- this.code = code;
12798
- this.retryAfterMs = retryAfterMs;
12799
- this.name = "ChatStoreError";
12800
- }
12801
- };
12802
-
12803
12957
  // src/lib/chatStore/remote.ts
12804
12958
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links", "setting"]);
12805
12959
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
@@ -13524,10 +13678,10 @@ async function deletedSinceUpload(store, journal, local, signal) {
13524
13678
  const present = /* @__PURE__ */ new Set([...local.records.map((r) => key(r.record)), ...local.skipped.keys()]);
13525
13679
  const gone = [...journal.keys].filter((k) => !present.has(k));
13526
13680
  if (gone.length === 0) return [];
13527
- const live = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
13528
- const tombstoning = new Set(live.map((s) => key(s.record)));
13681
+ const live2 = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
13682
+ const tombstoning = new Set(live2.map((s) => key(s.record)));
13529
13683
  await journal.drop(gone.filter((k) => !tombstoning.has(k)));
13530
- return live.map(({ record: record2, version }) => {
13684
+ return live2.map(({ record: record2, version }) => {
13531
13685
  const empty = emptied[record2.kind];
13532
13686
  return {
13533
13687
  record: {
@@ -14187,12 +14341,13 @@ var resumableFields = [
14187
14341
  "error",
14188
14342
  "thoughtProcess",
14189
14343
  "thinking",
14190
- "toolCallEvents"
14344
+ "toolCallEvents",
14345
+ "anuma"
14191
14346
  ];
14192
14347
  function resumedFields(options) {
14193
14348
  return plain(
14194
14349
  Object.fromEntries(
14195
- resumableFields.filter((f) => options[f] !== void 0).map((f) => [f, options[f]])
14350
+ resumableFields.filter((f) => options[f] !== void 0).map((f) => [f, f === "anuma" ? anumaTurnData(options.anuma) : options[f]])
14196
14351
  )
14197
14352
  );
14198
14353
  }
@@ -14846,7 +15001,7 @@ function createVaultChatBackend(options) {
14846
15001
  },
14847
15002
  async getConversations(query) {
14848
15003
  await available2();
14849
- return all("conversation").map(toConversation).filter(
15004
+ return all("conversation").filter((record2) => record2.id !== ANUMA_CONVERSATION_ID).map(toConversation).filter(
14850
15005
  (c) => query?.projectId === void 0 || (query.projectId === null ? !c.projectId : c.projectId === query.projectId)
14851
15006
  ).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
14852
15007
  },
@@ -14882,7 +15037,14 @@ function createVaultChatBackend(options) {
14882
15037
  async updateConversationPinned(conversationId, pinned) {
14883
15038
  return updateConversation(conversationId, { pinnedAt: pinned ? now() : null });
14884
15039
  },
15040
+ async updateConversationContext(conversationId, context) {
15041
+ const set = contextFields(context);
15042
+ if (Object.keys(set).length > 0) return updateConversation(conversationId, set);
15043
+ const record2 = await conversation(conversationId);
15044
+ return !!record2 && !record2.isDeleted;
15045
+ },
14885
15046
  async deleteConversation(conversationId) {
15047
+ if (conversationId === ANUMA_CONVERSATION_ID) return false;
14886
15048
  const record2 = await conversation(conversationId);
14887
15049
  if (!record2 || record2.isDeleted) return false;
14888
15050
  for (const [k, patch] of pending)
@@ -17886,7 +18048,7 @@ async function countActiveVaultMemoriesOp(ctx) {
17886
18048
  return ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx)).fetchCount();
17887
18049
  }
17888
18050
  async function getVaultMemoryCountsOp(ctx) {
17889
- const [live, archived, quarantined] = await Promise.all([
18051
+ const [live2, archived, quarantined] = await Promise.all([
17890
18052
  countActiveVaultMemoriesOp(ctx),
17891
18053
  ctx.vaultMemoryCollection.query(
17892
18054
  ...baseVaultConditions(ctx, { includeArchived: true }),
@@ -17897,7 +18059,7 @@ async function getVaultMemoryCountsOp(ctx) {
17897
18059
  import_watermelondb21.Q.where("trust_tier", "quarantined")
17898
18060
  ).fetchCount()
17899
18061
  ]);
17900
- return { live, archived, quarantined };
18062
+ return { live: live2, archived, quarantined };
17901
18063
  }
17902
18064
  async function getActiveVaultMemoryIdsOp(ctx, ids) {
17903
18065
  if (ids.length === 0) return /* @__PURE__ */ new Set();
@@ -19184,12 +19346,12 @@ var WalletPoller = class {
19184
19346
  * @param maxAttempts - Maximum polling attempts before giving up (default: 60)
19185
19347
  * @returns Stop function to cancel polling
19186
19348
  */
19187
- startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS) {
19349
+ startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts2 = DEFAULT_MAX_ATTEMPTS) {
19188
19350
  this.stop();
19189
19351
  this.attempts = 0;
19190
19352
  const poll = async () => {
19191
19353
  this.attempts++;
19192
- if (this.attempts > maxAttempts) {
19354
+ if (this.attempts > maxAttempts2) {
19193
19355
  this.stop();
19194
19356
  return;
19195
19357
  }
@@ -26599,13 +26761,13 @@ function createRemoteMemoryStore(options) {
26599
26761
  });
26600
26762
  return run;
26601
26763
  };
26602
- const live = async (id2) => {
26764
+ const live2 = async (id2) => {
26603
26765
  const record2 = await persistence.get(id2);
26604
26766
  return record2 && !record2.memory.is_deleted ? record2 : null;
26605
26767
  };
26606
26768
  const mutateLocked = async (id2, change, edit, writeOptions) => {
26607
26769
  writeOptions?.signal?.throwIfAborted();
26608
- const record2 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live(id2);
26770
+ const record2 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live2(id2);
26609
26771
  if (!record2) return null;
26610
26772
  if (record2.memory.is_deleted) return null;
26611
26773
  if (writeOptions?.canWrite && !await writeOptions.canWrite())
@@ -27403,7 +27565,7 @@ function createRemoteMemoryStore(options) {
27403
27565
  }, clear);
27404
27566
  return snapshot.then((topics) => structuredClone(topics));
27405
27567
  },
27406
- get: async (id2) => asStored(await live(id2)),
27568
+ get: async (id2) => asStored(await live2(id2)),
27407
27569
  listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
27408
27570
  (record2) => stored(record2.memory)
27409
27571
  ),
@@ -27488,7 +27650,7 @@ function createRemoteMemoryStore(options) {
27488
27650
  return serialized(
27489
27651
  first,
27490
27652
  () => serialized(second, async () => {
27491
- const [old, next] = await Promise.all([live(id2), live(supersededById)]);
27653
+ const [old, next] = await Promise.all([live2(id2), live2(supersededById)]);
27492
27654
  if (!old || !next || old.memory.superseded_by || next.memory.superseded_by) return false;
27493
27655
  if (old.memory.kind !== void 0 && old.memory.kind !== null) return false;
27494
27656
  const saved = await persistence.putMany([
@@ -27509,7 +27671,7 @@ function createRemoteMemoryStore(options) {
27509
27671
  (memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
27510
27672
  ),
27511
27673
  restore: (id2) => serialized(id2, async () => {
27512
- const record2 = await live(id2);
27674
+ const record2 = await live2(id2);
27513
27675
  if (!record2) return false;
27514
27676
  if (record2.memory.archived_at === void 0 || record2.memory.archived_at === null)
27515
27677
  return true;
@@ -34682,6 +34844,7 @@ function useChatStorage(options) {
34682
34844
  }
34683
34845
  // Annotate the CommonJS export names for ESM import in node:
34684
34846
  0 && (module.exports = {
34847
+ ANUMA_CONVERSATION_ID,
34685
34848
  CHUNKS_DISCARDED_ORIGIN,
34686
34849
  ChatConversation,
34687
34850
  ChatMessage,
@@ -34741,6 +34904,8 @@ function useChatStorage(options) {
34741
34904
  WALLET_PAYMENT_TOOL_NAME,
34742
34905
  WalletPoller,
34743
34906
  addConversationMemoriesOp,
34907
+ anumaLastReadSortKey,
34908
+ anumaTurnContent,
34744
34909
  archiveVaultMemoryOp,
34745
34910
  assembleMemoryContext,
34746
34911
  attachFileContextToLastUserMessage,
@@ -34774,6 +34939,7 @@ function useChatStorage(options) {
34774
34939
  consoleLogger,
34775
34940
  conversationMemoryToStored,
34776
34941
  cosineInt8,
34942
+ countUnreadAnumaTurns,
34777
34943
  createAutoExtractor,
34778
34944
  createChunkVectorCache,
34779
34945
  createCryptoPricePreProcessor,
@@ -34822,6 +34988,7 @@ function useChatStorage(options) {
34822
34988
  embedMessage,
34823
34989
  encodeChunkVector,
34824
34990
  encryptToolCallEventsOp,
34991
+ ensureAnumaConversation,
34825
34992
  ensureDefaultFoldersOp,
34826
34993
  exchangeNotionCode,
34827
34994
  extractAndLinkEntitiesForMemoriesOp,
@@ -34862,6 +35029,7 @@ function useChatStorage(options) {
34862
35029
  isRerankerAvailable,
34863
35030
  loadSettings,
34864
35031
  localChatBackend,
35032
+ markAnumaRead,
34865
35033
  maskScopedEmbeddingCache,
34866
35034
  maxVaultAttachmentBytes,
34867
35035
  memoryCipher,
@@ -34877,6 +35045,7 @@ function useChatStorage(options) {
34877
35045
  quantizeEmbedding,
34878
35046
  queueManager,
34879
35047
  rankProfileCandidates,
35048
+ readAnumaTurn,
34880
35049
  recall,
34881
35050
  reencryptMemoryField,
34882
35051
  reflect,