@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.
@@ -266,17 +266,17 @@ async function callPortalJsonCompletion(req) {
266
266
  if (autoUpgraded) endpoint = endpointForTransport(endpoint, transport);
267
267
  assertTransportMatchesEndpoint(transport, endpoint);
268
268
  }
269
- const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
269
+ const maxAttempts2 = Math.max(1, req.maxAttempts ?? 3);
270
270
  const startedAt = Date.now();
271
271
  const deadlineAt = req.totalTimeoutMs === void 0 ? void 0 : startedAt + req.totalTimeoutMs;
272
272
  const overBudget = () => deadlineAt !== void 0 && Date.now() >= deadlineAt;
273
273
  let lastFailure;
274
274
  let reinforce = false;
275
275
  const giveUp = () => {
276
- req.onFailure?.(lastFailure ?? { reason: "network", attempts: maxAttempts });
276
+ req.onFailure?.(lastFailure ?? { reason: "network", attempts: maxAttempts2 });
277
277
  return null;
278
278
  };
279
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
279
+ for (let attempt = 1; attempt <= maxAttempts2; attempt++) {
280
280
  if (attempt > 1 && overBudget()) {
281
281
  log.warn(`[${req.tag}] over time budget before attempt ${attempt}, giving up`);
282
282
  lastFailure = { reason: "time-budget-exhausted", attempts: attempt - 1 };
@@ -308,20 +308,20 @@ async function callPortalJsonCompletion(req) {
308
308
  log.warn(`[${req.tag}] ${outcome2.reason}`);
309
309
  return giveUp();
310
310
  }
311
- if (attempt >= maxAttempts) {
312
- log.warn(`[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts}, giving up`);
311
+ if (attempt >= maxAttempts2) {
312
+ log.warn(`[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts2}, giving up`);
313
313
  break;
314
314
  }
315
315
  const backoff = (req.backoffMs ?? defaultBackoffMs)(attempt);
316
316
  const delay = Math.max(backoff, outcome2.retryAfterMs ?? 0);
317
317
  if (overBudget() || req.totalTimeoutMs !== void 0 && Date.now() - startedAt + delay >= req.totalTimeoutMs) {
318
318
  log.warn(
319
- `[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts}, over time budget, giving up`
319
+ `[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts2}, over time budget, giving up`
320
320
  );
321
321
  lastFailure = { reason: "time-budget-exhausted", attempts: attempt };
322
322
  break;
323
323
  }
324
- log.warn(`[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts}, retrying`);
324
+ log.warn(`[${req.tag}] ${outcome2.reason} \u2014 attempt ${attempt}/${maxAttempts2}, retrying`);
325
325
  if (delay > 0) await sleep(delay);
326
326
  }
327
327
  return giveUp();
@@ -1419,6 +1419,7 @@ CARRY FORWARD UNCHANGED DETAILS (every "update" and "supersede"): a memory can h
1419
1419
  // src/react/index.ts
1420
1420
  var index_exports = {};
1421
1421
  __export(index_exports, {
1422
+ ANUMA_CONVERSATION_ID: () => ANUMA_CONVERSATION_ID,
1422
1423
  Anuma: () => Anuma,
1423
1424
  AnumaJsxError: () => AnumaJsxError,
1424
1425
  AnumaShadowIsolationProvider: () => AnumaShadowIsolationProvider,
@@ -1523,6 +1524,8 @@ __export(index_exports, {
1523
1524
  WordProcessor: () => WordProcessor,
1524
1525
  ZipProcessor: () => ZipProcessor,
1525
1526
  addConversationMemoriesOp: () => addConversationMemoriesOp,
1527
+ anumaLastReadSortKey: () => anumaLastReadSortKey,
1528
+ anumaTurnContent: () => anumaTurnContent,
1526
1529
  appFileToStored: () => appFileToStored,
1527
1530
  archiveVaultMemoryOp: () => archiveVaultMemoryOp,
1528
1531
  assembleMemoryContext: () => assembleMemoryContext,
@@ -1562,6 +1565,7 @@ __export(index_exports, {
1562
1565
  consoleLogger: () => consoleLogger,
1563
1566
  conversationMemoryToStored: () => conversationMemoryToStored,
1564
1567
  cosineInt8: () => cosineInt8,
1568
+ countUnreadAnumaTurns: () => countUnreadAnumaTurns,
1565
1569
  createAutoExtractor: () => createAutoExtractor,
1566
1570
  createChunkVectorCache: () => createChunkVectorCache,
1567
1571
  createCryptoPricePreProcessor: () => createCryptoPricePreProcessor,
@@ -1631,6 +1635,7 @@ __export(index_exports, {
1631
1635
  encryptDataBytes: () => encryptDataBytes,
1632
1636
  encryptDataWithKey: () => encryptDataWithKey,
1633
1637
  encryptToolCallEventsOp: () => encryptToolCallEventsOp,
1638
+ ensureAnumaConversation: () => ensureAnumaConversation,
1634
1639
  ensureDefaultFoldersOp: () => ensureDefaultFoldersOp,
1635
1640
  expandToolSetsAdditive: () => expandToolSetsAdditive,
1636
1641
  exportElementToPdf: () => exportElementToPdf,
@@ -1741,6 +1746,7 @@ __export(index_exports, {
1741
1746
  listActiveStreams: () => listActiveStreams,
1742
1747
  loadSettings: () => loadSettings,
1743
1748
  localChatBackend: () => localChatBackend,
1749
+ markAnumaRead: () => markAnumaRead,
1744
1750
  maskScopedEmbeddingCache: () => maskScopedEmbeddingCache,
1745
1751
  maxVaultAttachmentBytes: () => maxVaultAttachmentBytes,
1746
1752
  mediaToStored: () => mediaToStored,
@@ -1766,6 +1772,7 @@ __export(index_exports, {
1766
1772
  quantizeEmbedding: () => quantizeEmbedding,
1767
1773
  queueManager: () => queueManager,
1768
1774
  rankProfileCandidates: () => rankProfileCandidates,
1775
+ readAnumaTurn: () => readAnumaTurn,
1769
1776
  readEncryptedFile: () => readEncryptedFile,
1770
1777
  recall: () => recall,
1771
1778
  reencryptMemoryField: () => reencryptMemoryField,
@@ -8025,17 +8032,17 @@ async function createRemoteMemoryPersistence(options) {
8025
8032
  expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
8026
8033
  if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
8027
8034
  throw new Error("expectedVersion must be a nonnegative integer");
8028
- const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
8035
+ const conflict2 = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
8029
8036
  let existing;
8030
8037
  if (expectedVersion !== 0 && !snapshot) {
8031
8038
  try {
8032
8039
  existing = memoryRecord(await request(path, {}, signal));
8033
8040
  } catch (error) {
8034
- if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
8041
+ if (error instanceof RemoteMemoryError && error.status === 404) throw conflict2();
8035
8042
  throw error;
8036
8043
  }
8037
8044
  }
8038
- if (existing && existing.version !== expectedVersion) throw conflict();
8045
+ if (existing && existing.version !== expectedVersion) throw conflict2();
8039
8046
  const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
8040
8047
  const reusableContent = snapshot?.encryptedContent ?? existing?.memory.content;
8041
8048
  const content = reusableContent && (snapshot?.content ?? decoded?.memory.content) === memory.content ? reusableContent : await encryptField2(memory.content);
@@ -13208,119 +13215,19 @@ function createWebSearchPreProcessor(options = {}) {
13208
13215
  };
13209
13216
  }
13210
13217
 
13211
- // src/lib/db/chat/summaryOperations.ts
13212
- var import_watermelondb5 = require("@nozbe/watermelondb");
13213
- init_logger();
13214
- function createSummaryContext(database, encryption = {}) {
13215
- return {
13216
- ...encryption,
13217
- database,
13218
- summariesCollection: database.get("conversation_summaries")
13219
- };
13220
- }
13221
- function modelToStored(record2, summary) {
13222
- return {
13223
- uniqueId: record2.id,
13224
- conversationId: record2.conversationId,
13225
- summary,
13226
- summarizedUpTo: record2.summarizedUpTo,
13227
- tokenCount: record2.tokenCount,
13228
- createdAt: record2.createdAt,
13229
- updatedAt: record2.updatedAt
13230
- };
13231
- }
13232
- async function getConversationSummaryOp(ctx, conversationId) {
13233
- const results = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
13234
- if (results.length === 0) return null;
13235
- const record2 = results[0];
13236
- const stored2 = modelToStored(record2, record2.summary);
13237
- if (ctx.walletAddress && isEncrypted(stored2.summary)) {
13238
- if (ctx.signMessage) {
13239
- try {
13240
- await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
13241
- } catch (error) {
13242
- getLogger().warn("Failed to request the encryption key for the summary:", error);
13243
- }
13244
- }
13245
- stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
13246
- } else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
13247
- try {
13248
- const encryptedSummary = await encryptField(
13249
- stored2.summary,
13250
- ctx.walletAddress,
13251
- ctx.signMessage,
13252
- ctx.embeddedWalletSigner
13253
- );
13254
- await ctx.database.write(async () => {
13255
- const current = await ctx.summariesCollection.query(import_watermelondb5.Q.where("id", record2.id)).fetch();
13256
- if (current[0]?.summary === stored2.summary) {
13257
- await current[0].update((rec) => {
13258
- rec.summary = encryptedSummary;
13259
- });
13260
- }
13261
- });
13262
- } catch (error) {
13263
- getLogger().warn("Failed to encrypt the legacy summary:", error);
13264
- }
13218
+ // src/lib/chatStore/types.ts
13219
+ var ChatStoreError = class extends Error {
13220
+ constructor(message, status, code, retryAfterMs) {
13221
+ super(message);
13222
+ this.status = status;
13223
+ this.code = code;
13224
+ this.retryAfterMs = retryAfterMs;
13225
+ this.name = "ChatStoreError";
13265
13226
  }
13266
- return stored2;
13267
- }
13268
- async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
13269
- const revision2 = getConversationRevision(ctx.database, conversationId);
13270
- let record2;
13271
- const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
13272
- await ctx.database.write(async () => {
13273
- assertConversationRevision(ctx.database, conversationId, revision2);
13274
- const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
13275
- if (existing.length > 0) {
13276
- record2 = await existing[0].update((rec) => {
13277
- rec.summary = encryptedSummary;
13278
- rec.summarizedUpTo = summarizedUpTo;
13279
- rec.tokenCount = tokenCount;
13280
- });
13281
- } else {
13282
- record2 = await ctx.summariesCollection.create((rec) => {
13283
- rec.conversationId = conversationId;
13284
- rec.summary = encryptedSummary;
13285
- rec.summarizedUpTo = summarizedUpTo;
13286
- rec.tokenCount = tokenCount;
13287
- });
13288
- }
13289
- });
13290
- return modelToStored(record2, summary);
13291
- }
13292
- async function deleteConversationSummaryOp(ctx, conversationId) {
13293
- await ctx.database.write(async () => {
13294
- const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
13295
- for (const record2 of existing) {
13296
- await record2.destroyPermanently();
13297
- }
13298
- });
13299
- }
13300
-
13301
- // src/lib/db/conversationMemory/models.ts
13302
- var import_watermelondb6 = require("@nozbe/watermelondb");
13303
- var import_decorators2 = require("@nozbe/watermelondb/decorators");
13304
- var ConversationMemory = class extends import_watermelondb6.Model {
13305
13227
  };
13306
- ConversationMemory.table = "conversation_memory";
13307
- ConversationMemory.associations = {};
13308
- __decorateClass([
13309
- (0, import_decorators2.text)("conversation_id")
13310
- ], ConversationMemory.prototype, "conversationId", 2);
13311
- __decorateClass([
13312
- (0, import_decorators2.text)("memory_id")
13313
- ], ConversationMemory.prototype, "memoryId", 2);
13314
- __decorateClass([
13315
- (0, import_decorators2.field)("score")
13316
- ], ConversationMemory.prototype, "score", 2);
13317
- __decorateClass([
13318
- import_decorators2.readonly,
13319
- (0, import_decorators2.date)("created_at")
13320
- ], ConversationMemory.prototype, "createdAt", 2);
13321
13228
 
13322
13229
  // src/lib/db/conversationMemory/operations.ts
13323
- var import_watermelondb7 = require("@nozbe/watermelondb");
13230
+ var import_watermelondb5 = require("@nozbe/watermelondb");
13324
13231
  var MAX_PER_CONVERSATION = 200;
13325
13232
  function conversationMemoryToStored(row) {
13326
13233
  return {
@@ -13335,7 +13242,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
13335
13242
  if (!conversationId || items.length === 0) return;
13336
13243
  const now = Date.now();
13337
13244
  await ctx.database.write(async () => {
13338
- const existing = await ctx.conversationMemoryCollection.query(import_watermelondb7.Q.where("conversation_id", conversationId), import_watermelondb7.Q.sortBy("created_at", import_watermelondb7.Q.asc)).fetch();
13245
+ const existing = await ctx.conversationMemoryCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.sortBy("created_at", import_watermelondb5.Q.asc)).fetch();
13339
13246
  const seen = new Set(existing.map((r) => r.memoryId));
13340
13247
  const batchSeen = /* @__PURE__ */ new Set();
13341
13248
  const deduped = [];
@@ -13372,7 +13279,7 @@ async function recordConversationMemoriesOp(ctx, conversationId, items, now = Da
13372
13279
  if (!conversationId || turn.size === 0) return;
13373
13280
  const kept = new Map([...turn].slice(-MAX_PER_CONVERSATION));
13374
13281
  await ctx.database.write(async () => {
13375
- const existing = await ctx.conversationMemoryCollection.query(import_watermelondb7.Q.where("conversation_id", conversationId), import_watermelondb7.Q.sortBy("created_at", import_watermelondb7.Q.asc)).fetch();
13282
+ const existing = await ctx.conversationMemoryCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.sortBy("created_at", import_watermelondb5.Q.asc)).fetch();
13376
13283
  const earlier = existing.filter((r) => !turn.has(r.memoryId));
13377
13284
  const linked = new Set(existing.map((r) => r.memoryId));
13378
13285
  await ctx.database.batch(
@@ -13397,13 +13304,13 @@ async function recordConversationMemoriesOp(ctx, conversationId, items, now = Da
13397
13304
  }
13398
13305
  async function getConversationMemoriesOp(ctx, conversationId) {
13399
13306
  if (!conversationId) return [];
13400
- const rows = await ctx.conversationMemoryCollection.query(import_watermelondb7.Q.where("conversation_id", conversationId), import_watermelondb7.Q.sortBy("created_at", import_watermelondb7.Q.asc)).fetch();
13307
+ const rows = await ctx.conversationMemoryCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.sortBy("created_at", import_watermelondb5.Q.asc)).fetch();
13401
13308
  return rows.map(conversationMemoryToStored);
13402
13309
  }
13403
13310
  async function clearConversationMemoriesOp(ctx, conversationId) {
13404
13311
  if (!conversationId) return;
13405
13312
  await ctx.database.write(async () => {
13406
- const rows = await ctx.conversationMemoryCollection.query(import_watermelondb7.Q.where("conversation_id", conversationId)).fetch();
13313
+ const rows = await ctx.conversationMemoryCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
13407
13314
  if (rows.length === 0) return;
13408
13315
  await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
13409
13316
  });
@@ -13418,15 +13325,37 @@ var maxChunks = 16;
13418
13325
  var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
13419
13326
  var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
13420
13327
  var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
13328
+ var maxBubbles = 3;
13329
+ var maxTurnIdBytes = 128;
13330
+ var maxBubbleBytes = 16384;
13331
+ var anumaOrigins = /* @__PURE__ */ new Set(["intro", "reply"]);
13421
13332
  function plain(value) {
13422
13333
  return JSON.parse(JSON.stringify(value ?? {}));
13423
13334
  }
13424
- function text4(value) {
13335
+ function text3(value) {
13425
13336
  return typeof value === "string" ? value : void 0;
13426
13337
  }
13427
13338
  function number(value) {
13428
13339
  return typeof value === "number" ? value : void 0;
13429
13340
  }
13341
+ function readAnumaTurn(value) {
13342
+ if (!isObject(value)) return void 0;
13343
+ const { turnId, bubbles, origin } = value;
13344
+ if (typeof turnId !== "string" || turnId.length === 0 || new TextEncoder().encode(turnId).length > maxTurnIdBytes)
13345
+ return void 0;
13346
+ 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))
13347
+ return void 0;
13348
+ if (origin !== void 0 && (typeof origin !== "string" || !anumaOrigins.has(origin)))
13349
+ return void 0;
13350
+ return {
13351
+ turnId,
13352
+ ...bubbles !== void 0 ? { bubbles: [...bubbles] } : {},
13353
+ ...origin !== void 0 ? { origin } : {}
13354
+ };
13355
+ }
13356
+ function isObject(value) {
13357
+ return value !== null && typeof value === "object" && !Array.isArray(value);
13358
+ }
13430
13359
  function conversationSortKey(data, createdAt) {
13431
13360
  const pinnedAt = number(data.pinnedAt);
13432
13361
  if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
@@ -13447,12 +13376,12 @@ function conversationContext(data) {
13447
13376
  }
13448
13377
  function toConversation(record2) {
13449
13378
  const pinnedAt = number(record2.data.pinnedAt);
13450
- const projectId = text4(record2.data.projectId);
13379
+ const projectId = text3(record2.data.projectId);
13451
13380
  const context = conversationContext(record2.data);
13452
13381
  return {
13453
13382
  uniqueId: record2.id,
13454
13383
  conversationId: record2.id,
13455
- title: text4(record2.data.title) ?? "",
13384
+ title: text3(record2.data.title) ?? "",
13456
13385
  ...projectId ? { projectId } : {},
13457
13386
  createdAt: new Date(record2.createdAt),
13458
13387
  updatedAt: new Date(record2.updatedAt),
@@ -13461,18 +13390,28 @@ function toConversation(record2) {
13461
13390
  ...context ? { context } : {}
13462
13391
  };
13463
13392
  }
13393
+ function anumaTurnData(value) {
13394
+ if (value === void 0) return void 0;
13395
+ const turn = readAnumaTurn(value);
13396
+ if (!turn) throw new ChatStoreError("Invalid Anuma turn", 0, "invalid_record");
13397
+ return turn;
13398
+ }
13464
13399
  function messageData(options) {
13465
- return plain(
13466
- Object.fromEntries(
13400
+ const anuma = anumaTurnData(options.anuma);
13401
+ return plain({
13402
+ ...Object.fromEntries(
13467
13403
  Object.entries(options).filter(
13468
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
13404
+ ([key3, value]) => key3 !== "anuma" && !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
13469
13405
  )
13470
- )
13471
- );
13406
+ ),
13407
+ ...anuma ? { anuma } : {}
13408
+ });
13472
13409
  }
13473
13410
  function toMessage(record2) {
13474
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
13411
+ const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } = record2.data;
13412
+ const anuma = readAnumaTurn(rawAnuma);
13475
13413
  return {
13414
+ ...anuma ? { anuma } : {},
13476
13415
  ...fields,
13477
13416
  uniqueId: record2.id,
13478
13417
  messageId: record2.sortKey,
@@ -13486,20 +13425,20 @@ function chunkOffsets(record2) {
13486
13425
  return Array.isArray(offsets) ? offsets : void 0;
13487
13426
  }
13488
13427
  function toSkeletons(records) {
13489
- const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
13428
+ const roleById = new Map(records.map((r) => [r.id, text3(r.data.role)]));
13490
13429
  return records.map((r) => {
13491
- const parentMessageId = text4(r.data.parentMessageId);
13492
- const model = text4(r.data.model);
13430
+ const parentMessageId = text3(r.data.parentMessageId);
13431
+ const model = text3(r.data.model);
13493
13432
  const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
13494
13433
  return {
13495
13434
  uniqueId: r.id,
13496
13435
  messageId: r.sortKey,
13497
13436
  conversationId: r.conversationId,
13498
- role: text4(r.data.role) ?? "",
13437
+ role: text3(r.data.role) ?? "",
13499
13438
  createdAt: new Date(r.createdAt),
13500
13439
  ...parentMessageId ? { parentMessageId } : {},
13501
13440
  ...model ? { model } : {},
13502
- ...artifact ? { content: text4(r.data.content) ?? "" } : {}
13441
+ ...artifact ? { content: text3(r.data.content) ?? "" } : {}
13503
13442
  };
13504
13443
  });
13505
13444
  }
@@ -13507,8 +13446,8 @@ function toSummary(record2) {
13507
13446
  return {
13508
13447
  uniqueId: record2.id,
13509
13448
  conversationId: record2.id,
13510
- summary: text4(record2.data.summary) ?? "",
13511
- summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
13449
+ summary: text3(record2.data.summary) ?? "",
13450
+ summarizedUpTo: text3(record2.data.summarizedUpTo) ?? "",
13512
13451
  tokenCount: number(record2.data.tokenCount) ?? 0,
13513
13452
  createdAt: new Date(record2.createdAt),
13514
13453
  updatedAt: new Date(record2.updatedAt)
@@ -13559,7 +13498,7 @@ function fitRecord(record2) {
13559
13498
  delete data[field10];
13560
13499
  truncated.push(field10);
13561
13500
  }
13562
- const content = text4(data.content) ?? "";
13501
+ const content = text3(data.content) ?? "";
13563
13502
  const over = bytes({ ...record2, data }) - recordBudgetBytes;
13564
13503
  if (over > 0) {
13565
13504
  const encoded = new TextEncoder().encode(content);
@@ -13603,6 +13542,216 @@ function fitChunks(chunks3) {
13603
13542
  return out;
13604
13543
  }
13605
13544
 
13545
+ // src/lib/chatStore/anuma.ts
13546
+ var ANUMA_CONVERSATION_ID = "anuma-1on1";
13547
+ var maxAttempts = 3;
13548
+ function anumaTurnContent(bubbles) {
13549
+ return bubbles.join("\n\n");
13550
+ }
13551
+ function anumaLastReadSortKey(conversation) {
13552
+ const record2 = conversation && "record" in conversation ? conversation.record : conversation;
13553
+ const state = record2?.data.anuma;
13554
+ if (!isObject(state)) return 0;
13555
+ const sortKey = state.lastReadSortKey;
13556
+ return Number.isSafeInteger(sortKey) && sortKey > 0 ? sortKey : 0;
13557
+ }
13558
+ function conflict(error) {
13559
+ return error instanceof ChatStoreError && error.code === "version_conflict";
13560
+ }
13561
+ function live(snapshot) {
13562
+ if (snapshot?.record.isDeleted)
13563
+ throw new ChatStoreError("Anuma conversation was deleted", 409, "conversation_deleted");
13564
+ return snapshot;
13565
+ }
13566
+ async function ensureAnumaConversation(store, options = {}) {
13567
+ const existing = live(await store.get("conversation", ANUMA_CONVERSATION_ID, options.signal));
13568
+ if (existing) return existing;
13569
+ const at = (options.now ?? Date.now)();
13570
+ const data = plain({ title: "Anuma", lastActivityAt: at, anuma: { lastReadSortKey: 0 } });
13571
+ try {
13572
+ const [created] = await store.putMany(
13573
+ [
13574
+ {
13575
+ expectedVersion: 0,
13576
+ record: {
13577
+ kind: "conversation",
13578
+ id: ANUMA_CONVERSATION_ID,
13579
+ conversationId: "",
13580
+ sortKey: conversationSortKey(data, at),
13581
+ createdAt: at,
13582
+ updatedAt: at,
13583
+ isDeleted: false,
13584
+ data
13585
+ }
13586
+ }
13587
+ ],
13588
+ options.signal
13589
+ );
13590
+ return created;
13591
+ } catch (error) {
13592
+ if (!conflict(error)) throw error;
13593
+ const winner = live(await store.get("conversation", ANUMA_CONVERSATION_ID, options.signal));
13594
+ if (!winner) throw error;
13595
+ return winner;
13596
+ }
13597
+ }
13598
+ async function markAnumaRead(store, sortKey, options = {}) {
13599
+ if (!Number.isSafeInteger(sortKey) || sortKey < 0)
13600
+ throw new ChatStoreError("Invalid Anuma read marker", 0, "invalid_record");
13601
+ const now = options.now ?? Date.now;
13602
+ for (let attempt = 1; ; attempt++) {
13603
+ const current = await ensureAnumaConversation(store, options);
13604
+ const read = anumaLastReadSortKey(current);
13605
+ if (sortKey <= read) return current;
13606
+ const record2 = current.record;
13607
+ const state = isObject(record2.data.anuma) ? record2.data.anuma : {};
13608
+ const data = plain({ ...record2.data, anuma: { ...state, lastReadSortKey: sortKey } });
13609
+ try {
13610
+ const [written] = await store.putMany(
13611
+ [
13612
+ {
13613
+ expectedVersion: current.version,
13614
+ record: {
13615
+ ...record2,
13616
+ data,
13617
+ sortKey: conversationSortKey(data, record2.createdAt),
13618
+ updatedAt: Math.max(record2.updatedAt, now())
13619
+ }
13620
+ }
13621
+ ],
13622
+ options.signal
13623
+ );
13624
+ return written;
13625
+ } catch (error) {
13626
+ if (!conflict(error) || attempt >= maxAttempts) throw error;
13627
+ }
13628
+ }
13629
+ }
13630
+ function countUnreadAnumaTurns(messages, lastReadSortKey) {
13631
+ const answered = Math.max(
13632
+ 0,
13633
+ ...messages.filter((m) => m.role === "user").map((m) => m.messageId)
13634
+ );
13635
+ const floor = Math.max(lastReadSortKey, answered);
13636
+ const turns = /* @__PURE__ */ new Set();
13637
+ for (const m of messages) {
13638
+ if (m.role !== "assistant" || m.messageId <= floor) continue;
13639
+ turns.add(m.anuma?.turnId ? `turn:${m.anuma.turnId}` : `message:${m.uniqueId}`);
13640
+ }
13641
+ return turns.size;
13642
+ }
13643
+
13644
+ // src/lib/db/chat/summaryOperations.ts
13645
+ var import_watermelondb6 = require("@nozbe/watermelondb");
13646
+ init_logger();
13647
+ function createSummaryContext(database, encryption = {}) {
13648
+ return {
13649
+ ...encryption,
13650
+ database,
13651
+ summariesCollection: database.get("conversation_summaries")
13652
+ };
13653
+ }
13654
+ function modelToStored(record2, summary) {
13655
+ return {
13656
+ uniqueId: record2.id,
13657
+ conversationId: record2.conversationId,
13658
+ summary,
13659
+ summarizedUpTo: record2.summarizedUpTo,
13660
+ tokenCount: record2.tokenCount,
13661
+ createdAt: record2.createdAt,
13662
+ updatedAt: record2.updatedAt
13663
+ };
13664
+ }
13665
+ async function getConversationSummaryOp(ctx, conversationId) {
13666
+ const results = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
13667
+ if (results.length === 0) return null;
13668
+ const record2 = results[0];
13669
+ const stored2 = modelToStored(record2, record2.summary);
13670
+ if (ctx.walletAddress && isEncrypted(stored2.summary)) {
13671
+ if (ctx.signMessage) {
13672
+ try {
13673
+ await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
13674
+ } catch (error) {
13675
+ getLogger().warn("Failed to request the encryption key for the summary:", error);
13676
+ }
13677
+ }
13678
+ stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
13679
+ } else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
13680
+ try {
13681
+ const encryptedSummary = await encryptField(
13682
+ stored2.summary,
13683
+ ctx.walletAddress,
13684
+ ctx.signMessage,
13685
+ ctx.embeddedWalletSigner
13686
+ );
13687
+ await ctx.database.write(async () => {
13688
+ const current = await ctx.summariesCollection.query(import_watermelondb6.Q.where("id", record2.id)).fetch();
13689
+ if (current[0]?.summary === stored2.summary) {
13690
+ await current[0].update((rec) => {
13691
+ rec.summary = encryptedSummary;
13692
+ });
13693
+ }
13694
+ });
13695
+ } catch (error) {
13696
+ getLogger().warn("Failed to encrypt the legacy summary:", error);
13697
+ }
13698
+ }
13699
+ return stored2;
13700
+ }
13701
+ async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
13702
+ const revision2 = getConversationRevision(ctx.database, conversationId);
13703
+ let record2;
13704
+ const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
13705
+ await ctx.database.write(async () => {
13706
+ assertConversationRevision(ctx.database, conversationId, revision2);
13707
+ const existing = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
13708
+ if (existing.length > 0) {
13709
+ record2 = await existing[0].update((rec) => {
13710
+ rec.summary = encryptedSummary;
13711
+ rec.summarizedUpTo = summarizedUpTo;
13712
+ rec.tokenCount = tokenCount;
13713
+ });
13714
+ } else {
13715
+ record2 = await ctx.summariesCollection.create((rec) => {
13716
+ rec.conversationId = conversationId;
13717
+ rec.summary = encryptedSummary;
13718
+ rec.summarizedUpTo = summarizedUpTo;
13719
+ rec.tokenCount = tokenCount;
13720
+ });
13721
+ }
13722
+ });
13723
+ return modelToStored(record2, summary);
13724
+ }
13725
+ async function deleteConversationSummaryOp(ctx, conversationId) {
13726
+ await ctx.database.write(async () => {
13727
+ const existing = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
13728
+ for (const record2 of existing) {
13729
+ await record2.destroyPermanently();
13730
+ }
13731
+ });
13732
+ }
13733
+
13734
+ // src/lib/db/conversationMemory/models.ts
13735
+ var import_watermelondb7 = require("@nozbe/watermelondb");
13736
+ var import_decorators2 = require("@nozbe/watermelondb/decorators");
13737
+ var ConversationMemory = class extends import_watermelondb7.Model {
13738
+ };
13739
+ ConversationMemory.table = "conversation_memory";
13740
+ ConversationMemory.associations = {};
13741
+ __decorateClass([
13742
+ (0, import_decorators2.text)("conversation_id")
13743
+ ], ConversationMemory.prototype, "conversationId", 2);
13744
+ __decorateClass([
13745
+ (0, import_decorators2.text)("memory_id")
13746
+ ], ConversationMemory.prototype, "memoryId", 2);
13747
+ __decorateClass([
13748
+ (0, import_decorators2.field)("score")
13749
+ ], ConversationMemory.prototype, "score", 2);
13750
+ __decorateClass([
13751
+ import_decorators2.readonly,
13752
+ (0, import_decorators2.date)("created_at")
13753
+ ], ConversationMemory.prototype, "createdAt", 2);
13754
+
13606
13755
  // src/lib/chatStore/chatImports.ts
13607
13756
  var importBatch = 100;
13608
13757
  var importChunks = 200;
@@ -13694,17 +13843,6 @@ function batches(records) {
13694
13843
  return out;
13695
13844
  }
13696
13845
 
13697
- // src/lib/chatStore/types.ts
13698
- var ChatStoreError = class extends Error {
13699
- constructor(message, status, code, retryAfterMs) {
13700
- super(message);
13701
- this.status = status;
13702
- this.code = code;
13703
- this.retryAfterMs = retryAfterMs;
13704
- this.name = "ChatStoreError";
13705
- }
13706
- };
13707
-
13708
13846
  // src/lib/chatStore/remote.ts
13709
13847
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links", "setting"]);
13710
13848
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
@@ -14429,10 +14567,10 @@ async function deletedSinceUpload(store, journal, local, signal) {
14429
14567
  const present = /* @__PURE__ */ new Set([...local.records.map((r) => key(r.record)), ...local.skipped.keys()]);
14430
14568
  const gone = [...journal.keys].filter((k) => !present.has(k));
14431
14569
  if (gone.length === 0) return [];
14432
- const live = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
14433
- const tombstoning = new Set(live.map((s) => key(s.record)));
14570
+ const live2 = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
14571
+ const tombstoning = new Set(live2.map((s) => key(s.record)));
14434
14572
  await journal.drop(gone.filter((k) => !tombstoning.has(k)));
14435
- return live.map(({ record: record2, version }) => {
14573
+ return live2.map(({ record: record2, version }) => {
14436
14574
  const empty = emptied[record2.kind];
14437
14575
  return {
14438
14576
  record: {
@@ -15092,12 +15230,13 @@ var resumableFields = [
15092
15230
  "error",
15093
15231
  "thoughtProcess",
15094
15232
  "thinking",
15095
- "toolCallEvents"
15233
+ "toolCallEvents",
15234
+ "anuma"
15096
15235
  ];
15097
15236
  function resumedFields(options) {
15098
15237
  return plain(
15099
15238
  Object.fromEntries(
15100
- resumableFields.filter((f) => options[f] !== void 0).map((f) => [f, options[f]])
15239
+ resumableFields.filter((f) => options[f] !== void 0).map((f) => [f, f === "anuma" ? anumaTurnData(options.anuma) : options[f]])
15101
15240
  )
15102
15241
  );
15103
15242
  }
@@ -15751,7 +15890,7 @@ function createVaultChatBackend(options) {
15751
15890
  },
15752
15891
  async getConversations(query) {
15753
15892
  await available2();
15754
- return all("conversation").map(toConversation).filter(
15893
+ return all("conversation").filter((record2) => record2.id !== ANUMA_CONVERSATION_ID).map(toConversation).filter(
15755
15894
  (c) => query?.projectId === void 0 || (query.projectId === null ? !c.projectId : c.projectId === query.projectId)
15756
15895
  ).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
15757
15896
  },
@@ -15794,6 +15933,7 @@ function createVaultChatBackend(options) {
15794
15933
  return !!record2 && !record2.isDeleted;
15795
15934
  },
15796
15935
  async deleteConversation(conversationId) {
15936
+ if (conversationId === ANUMA_CONVERSATION_ID) return false;
15797
15937
  const record2 = await conversation(conversationId);
15798
15938
  if (!record2 || record2.isDeleted) return false;
15799
15939
  for (const [k, patch] of pending)
@@ -19864,7 +20004,7 @@ async function countActiveVaultMemoriesOp(ctx) {
19864
20004
  return ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx)).fetchCount();
19865
20005
  }
19866
20006
  async function getVaultMemoryCountsOp(ctx) {
19867
- const [live, archived, quarantined] = await Promise.all([
20007
+ const [live2, archived, quarantined] = await Promise.all([
19868
20008
  countActiveVaultMemoriesOp(ctx),
19869
20009
  ctx.vaultMemoryCollection.query(
19870
20010
  ...baseVaultConditions(ctx, { includeArchived: true }),
@@ -19875,7 +20015,7 @@ async function getVaultMemoryCountsOp(ctx) {
19875
20015
  import_watermelondb24.Q.where("trust_tier", "quarantined")
19876
20016
  ).fetchCount()
19877
20017
  ]);
19878
- return { live, archived, quarantined };
20018
+ return { live: live2, archived, quarantined };
19879
20019
  }
19880
20020
  async function getActiveVaultMemoryIdsOp(ctx, ids) {
19881
20021
  if (ids.length === 0) return /* @__PURE__ */ new Set();
@@ -21249,12 +21389,12 @@ var WalletPoller = class {
21249
21389
  * @param maxAttempts - Maximum polling attempts before giving up (default: 60)
21250
21390
  * @returns Stop function to cancel polling
21251
21391
  */
21252
- startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS) {
21392
+ startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts2 = DEFAULT_MAX_ATTEMPTS) {
21253
21393
  this.stop();
21254
21394
  this.attempts = 0;
21255
21395
  const poll = async () => {
21256
21396
  this.attempts++;
21257
- if (this.attempts > maxAttempts) {
21397
+ if (this.attempts > maxAttempts2) {
21258
21398
  this.stop();
21259
21399
  return;
21260
21400
  }
@@ -29073,13 +29213,13 @@ function createRemoteMemoryStore(options) {
29073
29213
  });
29074
29214
  return run;
29075
29215
  };
29076
- const live = async (id2) => {
29216
+ const live2 = async (id2) => {
29077
29217
  const record2 = await persistence.get(id2);
29078
29218
  return record2 && !record2.memory.is_deleted ? record2 : null;
29079
29219
  };
29080
29220
  const mutateLocked = async (id2, change, edit, writeOptions) => {
29081
29221
  writeOptions?.signal?.throwIfAborted();
29082
- const record2 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live(id2);
29222
+ const record2 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live2(id2);
29083
29223
  if (!record2) return null;
29084
29224
  if (record2.memory.is_deleted) return null;
29085
29225
  if (writeOptions?.canWrite && !await writeOptions.canWrite())
@@ -29877,7 +30017,7 @@ function createRemoteMemoryStore(options) {
29877
30017
  }, clear);
29878
30018
  return snapshot.then((topics) => structuredClone(topics));
29879
30019
  },
29880
- get: async (id2) => asStored(await live(id2)),
30020
+ get: async (id2) => asStored(await live2(id2)),
29881
30021
  listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
29882
30022
  (record2) => stored(record2.memory)
29883
30023
  ),
@@ -29962,7 +30102,7 @@ function createRemoteMemoryStore(options) {
29962
30102
  return serialized(
29963
30103
  first,
29964
30104
  () => serialized(second, async () => {
29965
- const [old, next] = await Promise.all([live(id2), live(supersededById)]);
30105
+ const [old, next] = await Promise.all([live2(id2), live2(supersededById)]);
29966
30106
  if (!old || !next || old.memory.superseded_by || next.memory.superseded_by) return false;
29967
30107
  if (old.memory.kind !== void 0 && old.memory.kind !== null) return false;
29968
30108
  const saved = await persistence.putMany([
@@ -29983,7 +30123,7 @@ function createRemoteMemoryStore(options) {
29983
30123
  (memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
29984
30124
  ),
29985
30125
  restore: (id2) => serialized(id2, async () => {
29986
- const record2 = await live(id2);
30126
+ const record2 = await live2(id2);
29987
30127
  if (!record2) return false;
29988
30128
  if (record2.memory.archived_at === void 0 || record2.memory.archived_at === null)
29989
30129
  return true;
@@ -41604,11 +41744,11 @@ function usePhoneCalls(options = {}) {
41604
41744
  pollRunIdRef.current = runId;
41605
41745
  setIsPolling(true);
41606
41746
  const intervalMs = pollOptions.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
41607
- const maxAttempts = pollOptions.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS;
41747
+ const maxAttempts2 = pollOptions.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS;
41608
41748
  const stopWhenCompleted = pollOptions.stopWhenCompleted ?? true;
41609
41749
  let latestCall = null;
41610
41750
  try {
41611
- for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
41751
+ for (let attempt = 0; attempt < maxAttempts2; attempt += 1) {
41612
41752
  if (pollRunIdRef.current !== runId) {
41613
41753
  break;
41614
41754
  }
@@ -41638,7 +41778,7 @@ function usePhoneCalls(options = {}) {
41638
41778
  break;
41639
41779
  }
41640
41780
  }
41641
- if (attempt < maxAttempts - 1) {
41781
+ if (attempt < maxAttempts2 - 1) {
41642
41782
  await wait2(intervalMs);
41643
41783
  }
41644
41784
  }
@@ -43153,6 +43293,7 @@ function useWalletBinding(options = {}) {
43153
43293
  }
43154
43294
  // Annotate the CommonJS export names for ESM import in node:
43155
43295
  0 && (module.exports = {
43296
+ ANUMA_CONVERSATION_ID,
43156
43297
  Anuma,
43157
43298
  AnumaJsxError,
43158
43299
  AnumaShadowIsolationProvider,
@@ -43257,6 +43398,8 @@ function useWalletBinding(options = {}) {
43257
43398
  WordProcessor,
43258
43399
  ZipProcessor,
43259
43400
  addConversationMemoriesOp,
43401
+ anumaLastReadSortKey,
43402
+ anumaTurnContent,
43260
43403
  appFileToStored,
43261
43404
  archiveVaultMemoryOp,
43262
43405
  assembleMemoryContext,
@@ -43296,6 +43439,7 @@ function useWalletBinding(options = {}) {
43296
43439
  consoleLogger,
43297
43440
  conversationMemoryToStored,
43298
43441
  cosineInt8,
43442
+ countUnreadAnumaTurns,
43299
43443
  createAutoExtractor,
43300
43444
  createChunkVectorCache,
43301
43445
  createCryptoPricePreProcessor,
@@ -43365,6 +43509,7 @@ function useWalletBinding(options = {}) {
43365
43509
  encryptDataBytes,
43366
43510
  encryptDataWithKey,
43367
43511
  encryptToolCallEventsOp,
43512
+ ensureAnumaConversation,
43368
43513
  ensureDefaultFoldersOp,
43369
43514
  expandToolSetsAdditive,
43370
43515
  exportElementToPdf,
@@ -43475,6 +43620,7 @@ function useWalletBinding(options = {}) {
43475
43620
  listActiveStreams,
43476
43621
  loadSettings,
43477
43622
  localChatBackend,
43623
+ markAnumaRead,
43478
43624
  maskScopedEmbeddingCache,
43479
43625
  maxVaultAttachmentBytes,
43480
43626
  mediaToStored,
@@ -43500,6 +43646,7 @@ function useWalletBinding(options = {}) {
43500
43646
  quantizeEmbedding,
43501
43647
  queueManager,
43502
43648
  rankProfileCandidates,
43649
+ readAnumaTurn,
43503
43650
  readEncryptedFile,
43504
43651
  recall,
43505
43652
  reencryptMemoryField,