@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.
@@ -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,46 +13325,93 @@ 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;
13433
13362
  return number(data.lastActivityAt) ?? createdAt;
13434
13363
  }
13364
+ var CONTEXT_FIELD_PREFIX = "context.";
13365
+ function contextField(key3) {
13366
+ return `${CONTEXT_FIELD_PREFIX}${key3}`;
13367
+ }
13368
+ function contextFields(context) {
13369
+ return plain(
13370
+ Object.fromEntries(Object.entries(context ?? {}).map(([k, value]) => [contextField(k), value]))
13371
+ );
13372
+ }
13373
+ function conversationContext(data) {
13374
+ const entries = Object.entries(data).filter(([field10]) => field10.startsWith(CONTEXT_FIELD_PREFIX)).map(([field10, value]) => [field10.slice(CONTEXT_FIELD_PREFIX.length), value]);
13375
+ return entries.length > 0 ? plain(Object.fromEntries(entries)) : void 0;
13376
+ }
13435
13377
  function toConversation(record2) {
13436
13378
  const pinnedAt = number(record2.data.pinnedAt);
13437
- const projectId = text4(record2.data.projectId);
13379
+ const projectId = text3(record2.data.projectId);
13380
+ const context = conversationContext(record2.data);
13438
13381
  return {
13439
13382
  uniqueId: record2.id,
13440
13383
  conversationId: record2.id,
13441
- title: text4(record2.data.title) ?? "",
13384
+ title: text3(record2.data.title) ?? "",
13442
13385
  ...projectId ? { projectId } : {},
13443
13386
  createdAt: new Date(record2.createdAt),
13444
13387
  updatedAt: new Date(record2.updatedAt),
13445
13388
  isDeleted: record2.isDeleted,
13446
- pinnedAt: pinnedAt ? new Date(pinnedAt) : null
13389
+ pinnedAt: pinnedAt ? new Date(pinnedAt) : null,
13390
+ ...context ? { context } : {}
13447
13391
  };
13448
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
+ }
13449
13399
  function messageData(options) {
13450
- return plain(
13451
- Object.fromEntries(
13400
+ const anuma = anumaTurnData(options.anuma);
13401
+ return plain({
13402
+ ...Object.fromEntries(
13452
13403
  Object.entries(options).filter(
13453
- ([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
13404
+ ([key3, value]) => key3 !== "anuma" && !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
13454
13405
  )
13455
- )
13456
- );
13406
+ ),
13407
+ ...anuma ? { anuma } : {}
13408
+ });
13457
13409
  }
13458
13410
  function toMessage(record2) {
13459
- const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
13411
+ const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } = record2.data;
13412
+ const anuma = readAnumaTurn(rawAnuma);
13460
13413
  return {
13414
+ ...anuma ? { anuma } : {},
13461
13415
  ...fields,
13462
13416
  uniqueId: record2.id,
13463
13417
  messageId: record2.sortKey,
@@ -13471,20 +13425,20 @@ function chunkOffsets(record2) {
13471
13425
  return Array.isArray(offsets) ? offsets : void 0;
13472
13426
  }
13473
13427
  function toSkeletons(records) {
13474
- 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)]));
13475
13429
  return records.map((r) => {
13476
- const parentMessageId = text4(r.data.parentMessageId);
13477
- const model = text4(r.data.model);
13430
+ const parentMessageId = text3(r.data.parentMessageId);
13431
+ const model = text3(r.data.model);
13478
13432
  const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
13479
13433
  return {
13480
13434
  uniqueId: r.id,
13481
13435
  messageId: r.sortKey,
13482
13436
  conversationId: r.conversationId,
13483
- role: text4(r.data.role) ?? "",
13437
+ role: text3(r.data.role) ?? "",
13484
13438
  createdAt: new Date(r.createdAt),
13485
13439
  ...parentMessageId ? { parentMessageId } : {},
13486
13440
  ...model ? { model } : {},
13487
- ...artifact ? { content: text4(r.data.content) ?? "" } : {}
13441
+ ...artifact ? { content: text3(r.data.content) ?? "" } : {}
13488
13442
  };
13489
13443
  });
13490
13444
  }
@@ -13492,8 +13446,8 @@ function toSummary(record2) {
13492
13446
  return {
13493
13447
  uniqueId: record2.id,
13494
13448
  conversationId: record2.id,
13495
- summary: text4(record2.data.summary) ?? "",
13496
- summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
13449
+ summary: text3(record2.data.summary) ?? "",
13450
+ summarizedUpTo: text3(record2.data.summarizedUpTo) ?? "",
13497
13451
  tokenCount: number(record2.data.tokenCount) ?? 0,
13498
13452
  createdAt: new Date(record2.createdAt),
13499
13453
  updatedAt: new Date(record2.updatedAt)
@@ -13544,7 +13498,7 @@ function fitRecord(record2) {
13544
13498
  delete data[field10];
13545
13499
  truncated.push(field10);
13546
13500
  }
13547
- const content = text4(data.content) ?? "";
13501
+ const content = text3(data.content) ?? "";
13548
13502
  const over = bytes({ ...record2, data }) - recordBudgetBytes;
13549
13503
  if (over > 0) {
13550
13504
  const encoded = new TextEncoder().encode(content);
@@ -13588,6 +13542,216 @@ function fitChunks(chunks3) {
13588
13542
  return out;
13589
13543
  }
13590
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
+
13591
13755
  // src/lib/chatStore/chatImports.ts
13592
13756
  var importBatch = 100;
13593
13757
  var importChunks = 200;
@@ -13602,6 +13766,7 @@ function bytes2(value) {
13602
13766
  function conversationRecord(conversation, messages) {
13603
13767
  const createdAt = ms(conversation.createdAt);
13604
13768
  const data = plain({
13769
+ ...contextFields(conversation.context),
13605
13770
  title: conversation.title,
13606
13771
  projectId: conversation.projectId || void 0,
13607
13772
  pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
@@ -13678,17 +13843,6 @@ function batches(records) {
13678
13843
  return out;
13679
13844
  }
13680
13845
 
13681
- // src/lib/chatStore/types.ts
13682
- var ChatStoreError = class extends Error {
13683
- constructor(message, status, code, retryAfterMs) {
13684
- super(message);
13685
- this.status = status;
13686
- this.code = code;
13687
- this.retryAfterMs = retryAfterMs;
13688
- this.name = "ChatStoreError";
13689
- }
13690
- };
13691
-
13692
13846
  // src/lib/chatStore/remote.ts
13693
13847
  var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links", "setting"]);
13694
13848
  var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
@@ -14413,10 +14567,10 @@ async function deletedSinceUpload(store, journal, local, signal) {
14413
14567
  const present = /* @__PURE__ */ new Set([...local.records.map((r) => key(r.record)), ...local.skipped.keys()]);
14414
14568
  const gone = [...journal.keys].filter((k) => !present.has(k));
14415
14569
  if (gone.length === 0) return [];
14416
- const live = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
14417
- 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)));
14418
14572
  await journal.drop(gone.filter((k) => !tombstoning.has(k)));
14419
- return live.map(({ record: record2, version }) => {
14573
+ return live2.map(({ record: record2, version }) => {
14420
14574
  const empty = emptied[record2.kind];
14421
14575
  return {
14422
14576
  record: {
@@ -15076,12 +15230,13 @@ var resumableFields = [
15076
15230
  "error",
15077
15231
  "thoughtProcess",
15078
15232
  "thinking",
15079
- "toolCallEvents"
15233
+ "toolCallEvents",
15234
+ "anuma"
15080
15235
  ];
15081
15236
  function resumedFields(options) {
15082
15237
  return plain(
15083
15238
  Object.fromEntries(
15084
- 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]])
15085
15240
  )
15086
15241
  );
15087
15242
  }
@@ -15735,7 +15890,7 @@ function createVaultChatBackend(options) {
15735
15890
  },
15736
15891
  async getConversations(query) {
15737
15892
  await available2();
15738
- return all("conversation").map(toConversation).filter(
15893
+ return all("conversation").filter((record2) => record2.id !== ANUMA_CONVERSATION_ID).map(toConversation).filter(
15739
15894
  (c) => query?.projectId === void 0 || (query.projectId === null ? !c.projectId : c.projectId === query.projectId)
15740
15895
  ).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
15741
15896
  },
@@ -15771,7 +15926,14 @@ function createVaultChatBackend(options) {
15771
15926
  async updateConversationPinned(conversationId, pinned) {
15772
15927
  return updateConversation(conversationId, { pinnedAt: pinned ? now() : null });
15773
15928
  },
15929
+ async updateConversationContext(conversationId, context) {
15930
+ const set = contextFields(context);
15931
+ if (Object.keys(set).length > 0) return updateConversation(conversationId, set);
15932
+ const record2 = await conversation(conversationId);
15933
+ return !!record2 && !record2.isDeleted;
15934
+ },
15774
15935
  async deleteConversation(conversationId) {
15936
+ if (conversationId === ANUMA_CONVERSATION_ID) return false;
15775
15937
  const record2 = await conversation(conversationId);
15776
15938
  if (!record2 || record2.isDeleted) return false;
15777
15939
  for (const [k, patch] of pending)
@@ -19842,7 +20004,7 @@ async function countActiveVaultMemoriesOp(ctx) {
19842
20004
  return ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx)).fetchCount();
19843
20005
  }
19844
20006
  async function getVaultMemoryCountsOp(ctx) {
19845
- const [live, archived, quarantined] = await Promise.all([
20007
+ const [live2, archived, quarantined] = await Promise.all([
19846
20008
  countActiveVaultMemoriesOp(ctx),
19847
20009
  ctx.vaultMemoryCollection.query(
19848
20010
  ...baseVaultConditions(ctx, { includeArchived: true }),
@@ -19853,7 +20015,7 @@ async function getVaultMemoryCountsOp(ctx) {
19853
20015
  import_watermelondb24.Q.where("trust_tier", "quarantined")
19854
20016
  ).fetchCount()
19855
20017
  ]);
19856
- return { live, archived, quarantined };
20018
+ return { live: live2, archived, quarantined };
19857
20019
  }
19858
20020
  async function getActiveVaultMemoryIdsOp(ctx, ids) {
19859
20021
  if (ids.length === 0) return /* @__PURE__ */ new Set();
@@ -21227,12 +21389,12 @@ var WalletPoller = class {
21227
21389
  * @param maxAttempts - Maximum polling attempts before giving up (default: 60)
21228
21390
  * @returns Stop function to cancel polling
21229
21391
  */
21230
- startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS) {
21392
+ startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts2 = DEFAULT_MAX_ATTEMPTS) {
21231
21393
  this.stop();
21232
21394
  this.attempts = 0;
21233
21395
  const poll = async () => {
21234
21396
  this.attempts++;
21235
- if (this.attempts > maxAttempts) {
21397
+ if (this.attempts > maxAttempts2) {
21236
21398
  this.stop();
21237
21399
  return;
21238
21400
  }
@@ -29051,13 +29213,13 @@ function createRemoteMemoryStore(options) {
29051
29213
  });
29052
29214
  return run;
29053
29215
  };
29054
- const live = async (id2) => {
29216
+ const live2 = async (id2) => {
29055
29217
  const record2 = await persistence.get(id2);
29056
29218
  return record2 && !record2.memory.is_deleted ? record2 : null;
29057
29219
  };
29058
29220
  const mutateLocked = async (id2, change, edit, writeOptions) => {
29059
29221
  writeOptions?.signal?.throwIfAborted();
29060
- 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);
29061
29223
  if (!record2) return null;
29062
29224
  if (record2.memory.is_deleted) return null;
29063
29225
  if (writeOptions?.canWrite && !await writeOptions.canWrite())
@@ -29855,7 +30017,7 @@ function createRemoteMemoryStore(options) {
29855
30017
  }, clear);
29856
30018
  return snapshot.then((topics) => structuredClone(topics));
29857
30019
  },
29858
- get: async (id2) => asStored(await live(id2)),
30020
+ get: async (id2) => asStored(await live2(id2)),
29859
30021
  listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
29860
30022
  (record2) => stored(record2.memory)
29861
30023
  ),
@@ -29940,7 +30102,7 @@ function createRemoteMemoryStore(options) {
29940
30102
  return serialized(
29941
30103
  first,
29942
30104
  () => serialized(second, async () => {
29943
- const [old, next] = await Promise.all([live(id2), live(supersededById)]);
30105
+ const [old, next] = await Promise.all([live2(id2), live2(supersededById)]);
29944
30106
  if (!old || !next || old.memory.superseded_by || next.memory.superseded_by) return false;
29945
30107
  if (old.memory.kind !== void 0 && old.memory.kind !== null) return false;
29946
30108
  const saved = await persistence.putMany([
@@ -29961,7 +30123,7 @@ function createRemoteMemoryStore(options) {
29961
30123
  (memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
29962
30124
  ),
29963
30125
  restore: (id2) => serialized(id2, async () => {
29964
- const record2 = await live(id2);
30126
+ const record2 = await live2(id2);
29965
30127
  if (!record2) return false;
29966
30128
  if (record2.memory.archived_at === void 0 || record2.memory.archived_at === null)
29967
30129
  return true;
@@ -41582,11 +41744,11 @@ function usePhoneCalls(options = {}) {
41582
41744
  pollRunIdRef.current = runId;
41583
41745
  setIsPolling(true);
41584
41746
  const intervalMs = pollOptions.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
41585
- const maxAttempts = pollOptions.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS;
41747
+ const maxAttempts2 = pollOptions.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS;
41586
41748
  const stopWhenCompleted = pollOptions.stopWhenCompleted ?? true;
41587
41749
  let latestCall = null;
41588
41750
  try {
41589
- for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
41751
+ for (let attempt = 0; attempt < maxAttempts2; attempt += 1) {
41590
41752
  if (pollRunIdRef.current !== runId) {
41591
41753
  break;
41592
41754
  }
@@ -41616,7 +41778,7 @@ function usePhoneCalls(options = {}) {
41616
41778
  break;
41617
41779
  }
41618
41780
  }
41619
- if (attempt < maxAttempts - 1) {
41781
+ if (attempt < maxAttempts2 - 1) {
41620
41782
  await wait2(intervalMs);
41621
41783
  }
41622
41784
  }
@@ -43131,6 +43293,7 @@ function useWalletBinding(options = {}) {
43131
43293
  }
43132
43294
  // Annotate the CommonJS export names for ESM import in node:
43133
43295
  0 && (module.exports = {
43296
+ ANUMA_CONVERSATION_ID,
43134
43297
  Anuma,
43135
43298
  AnumaJsxError,
43136
43299
  AnumaShadowIsolationProvider,
@@ -43235,6 +43398,8 @@ function useWalletBinding(options = {}) {
43235
43398
  WordProcessor,
43236
43399
  ZipProcessor,
43237
43400
  addConversationMemoriesOp,
43401
+ anumaLastReadSortKey,
43402
+ anumaTurnContent,
43238
43403
  appFileToStored,
43239
43404
  archiveVaultMemoryOp,
43240
43405
  assembleMemoryContext,
@@ -43274,6 +43439,7 @@ function useWalletBinding(options = {}) {
43274
43439
  consoleLogger,
43275
43440
  conversationMemoryToStored,
43276
43441
  cosineInt8,
43442
+ countUnreadAnumaTurns,
43277
43443
  createAutoExtractor,
43278
43444
  createChunkVectorCache,
43279
43445
  createCryptoPricePreProcessor,
@@ -43343,6 +43509,7 @@ function useWalletBinding(options = {}) {
43343
43509
  encryptDataBytes,
43344
43510
  encryptDataWithKey,
43345
43511
  encryptToolCallEventsOp,
43512
+ ensureAnumaConversation,
43346
43513
  ensureDefaultFoldersOp,
43347
43514
  expandToolSetsAdditive,
43348
43515
  exportElementToPdf,
@@ -43453,6 +43620,7 @@ function useWalletBinding(options = {}) {
43453
43620
  listActiveStreams,
43454
43621
  loadSettings,
43455
43622
  localChatBackend,
43623
+ markAnumaRead,
43456
43624
  maskScopedEmbeddingCache,
43457
43625
  maxVaultAttachmentBytes,
43458
43626
  mediaToStored,
@@ -43478,6 +43646,7 @@ function useWalletBinding(options = {}) {
43478
43646
  quantizeEmbedding,
43479
43647
  queueManager,
43480
43648
  rankProfileCandidates,
43649
+ readAnumaTurn,
43481
43650
  readEncryptedFile,
43482
43651
  recall,
43483
43652
  reencryptMemoryField,