@anuma/sdk 10.0.2 → 10.0.4

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.
@@ -2079,7 +2079,7 @@ ${appendix}` : appendix;
2079
2079
  }
2080
2080
 
2081
2081
  // src/lib/db/chat/operations.ts
2082
- var import_watermelondb3 = require("@nozbe/watermelondb");
2082
+ var import_watermelondb4 = require("@nozbe/watermelondb");
2083
2083
  var import_uuid2 = require("uuid");
2084
2084
 
2085
2085
  // src/react/useEncryption.ts
@@ -3302,8 +3302,162 @@ async function assembleDecryptedMessage(message, address) {
3302
3302
  return result;
3303
3303
  }
3304
3304
 
3305
- // src/lib/db/chat/toolCallEventIndex.ts
3305
+ // src/lib/db/chat/models.ts
3306
3306
  var import_watermelondb2 = require("@nozbe/watermelondb");
3307
+ var import_decorators = require("@nozbe/watermelondb/decorators");
3308
+ var Message = class extends import_watermelondb2.Model {
3309
+ };
3310
+ Message.table = "history";
3311
+ Message.associations = {
3312
+ conversations: { type: "belongs_to", key: "conversation_id" },
3313
+ media: { type: "has_many", foreignKey: "message_id" }
3314
+ };
3315
+ __decorateClass([
3316
+ (0, import_decorators.field)("message_id")
3317
+ ], Message.prototype, "messageId", 2);
3318
+ __decorateClass([
3319
+ (0, import_decorators.text)("conversation_id")
3320
+ ], Message.prototype, "conversationId", 2);
3321
+ __decorateClass([
3322
+ (0, import_decorators.text)("role")
3323
+ ], Message.prototype, "role", 2);
3324
+ __decorateClass([
3325
+ (0, import_decorators.text)("content")
3326
+ ], Message.prototype, "content", 2);
3327
+ __decorateClass([
3328
+ (0, import_decorators.text)("model")
3329
+ ], Message.prototype, "model", 2);
3330
+ __decorateClass([
3331
+ (0, import_decorators.text)("image_model")
3332
+ ], Message.prototype, "imageModel", 2);
3333
+ __decorateClass([
3334
+ (0, import_decorators.json)("files", (raw) => raw)
3335
+ ], Message.prototype, "files", 2);
3336
+ __decorateClass([
3337
+ (0, import_decorators.json)("file_ids", (raw) => raw)
3338
+ ], Message.prototype, "fileIds", 2);
3339
+ __decorateClass([
3340
+ (0, import_decorators.date)("created_at")
3341
+ ], Message.prototype, "createdAt", 2);
3342
+ __decorateClass([
3343
+ (0, import_decorators.date)("updated_at")
3344
+ ], Message.prototype, "updatedAt", 2);
3345
+ __decorateClass([
3346
+ (0, import_decorators.json)("vector", (raw) => raw)
3347
+ ], Message.prototype, "vector", 2);
3348
+ __decorateClass([
3349
+ (0, import_decorators.text)("embedding_model")
3350
+ ], Message.prototype, "embeddingModel", 2);
3351
+ __decorateClass([
3352
+ (0, import_decorators.json)("chunks", (raw) => raw)
3353
+ ], Message.prototype, "chunks", 2);
3354
+ __decorateClass([
3355
+ (0, import_decorators.json)("usage", (raw) => raw)
3356
+ ], Message.prototype, "usage", 2);
3357
+ __decorateClass([
3358
+ (0, import_decorators.json)("sources", (raw) => raw)
3359
+ ], Message.prototype, "sources", 2);
3360
+ __decorateClass([
3361
+ (0, import_decorators.field)("response_duration")
3362
+ ], Message.prototype, "responseDuration", 2);
3363
+ __decorateClass([
3364
+ (0, import_decorators.field)("was_stopped")
3365
+ ], Message.prototype, "wasStopped", 2);
3366
+ __decorateClass([
3367
+ (0, import_decorators.text)("error")
3368
+ ], Message.prototype, "error", 2);
3369
+ __decorateClass([
3370
+ (0, import_decorators.json)("thought_process", (raw) => raw)
3371
+ ], Message.prototype, "thoughtProcess", 2);
3372
+ __decorateClass([
3373
+ (0, import_decorators.text)("thinking")
3374
+ ], Message.prototype, "thinking", 2);
3375
+ __decorateClass([
3376
+ (0, import_decorators.text)("parent_message_id")
3377
+ ], Message.prototype, "parentMessageId", 2);
3378
+ __decorateClass([
3379
+ (0, import_decorators.text)("feedback")
3380
+ ], Message.prototype, "feedback", 2);
3381
+ __decorateClass([
3382
+ (0, import_decorators.json)("tool_call_events", (raw) => raw)
3383
+ ], Message.prototype, "toolCallEvents", 2);
3384
+ __decorateClass([
3385
+ (0, import_decorators.text)("origin")
3386
+ ], Message.prototype, "origin", 2);
3387
+ var Conversation = class extends import_watermelondb2.Model {
3388
+ };
3389
+ Conversation.table = "conversations";
3390
+ Conversation.associations = {
3391
+ history: { type: "has_many", foreignKey: "conversation_id" },
3392
+ projects: { type: "belongs_to", key: "project_id" }
3393
+ };
3394
+ __decorateClass([
3395
+ (0, import_decorators.text)("conversation_id")
3396
+ ], Conversation.prototype, "conversationId", 2);
3397
+ __decorateClass([
3398
+ (0, import_decorators.text)("title")
3399
+ ], Conversation.prototype, "title", 2);
3400
+ __decorateClass([
3401
+ (0, import_decorators.text)("project_id")
3402
+ ], Conversation.prototype, "projectId", 2);
3403
+ __decorateClass([
3404
+ (0, import_decorators.date)("created_at")
3405
+ ], Conversation.prototype, "createdAt", 2);
3406
+ __decorateClass([
3407
+ (0, import_decorators.date)("updated_at")
3408
+ ], Conversation.prototype, "updatedAt", 2);
3409
+ __decorateClass([
3410
+ (0, import_decorators.field)("is_deleted")
3411
+ ], Conversation.prototype, "isDeleted", 2);
3412
+ __decorateClass([
3413
+ (0, import_decorators.date)("pinned_at")
3414
+ ], Conversation.prototype, "pinnedAt", 2);
3415
+ var ConversationSummary = class extends import_watermelondb2.Model {
3416
+ };
3417
+ ConversationSummary.table = "conversation_summaries";
3418
+ ConversationSummary.associations = {
3419
+ conversations: { type: "belongs_to", key: "conversation_id" }
3420
+ };
3421
+ __decorateClass([
3422
+ (0, import_decorators.text)("conversation_id")
3423
+ ], ConversationSummary.prototype, "conversationId", 2);
3424
+ __decorateClass([
3425
+ (0, import_decorators.text)("summary")
3426
+ ], ConversationSummary.prototype, "summary", 2);
3427
+ __decorateClass([
3428
+ (0, import_decorators.text)("summarized_up_to")
3429
+ ], ConversationSummary.prototype, "summarizedUpTo", 2);
3430
+ __decorateClass([
3431
+ (0, import_decorators.field)("token_count")
3432
+ ], ConversationSummary.prototype, "tokenCount", 2);
3433
+ __decorateClass([
3434
+ (0, import_decorators.date)("created_at")
3435
+ ], ConversationSummary.prototype, "createdAt", 2);
3436
+ __decorateClass([
3437
+ (0, import_decorators.date)("updated_at")
3438
+ ], ConversationSummary.prototype, "updatedAt", 2);
3439
+
3440
+ // src/lib/db/chat/summaryRevision.ts
3441
+ var conversationRevisions = /* @__PURE__ */ new WeakMap();
3442
+ function getConversationRevision(database, conversationId) {
3443
+ return conversationRevisions.get(database)?.get(conversationId) ?? 0;
3444
+ }
3445
+ function advanceConversationRevision(database, conversationId) {
3446
+ let revisions = conversationRevisions.get(database);
3447
+ if (!revisions) {
3448
+ revisions = /* @__PURE__ */ new Map();
3449
+ conversationRevisions.set(database, revisions);
3450
+ }
3451
+ revisions.set(conversationId, getConversationRevision(database, conversationId) + 1);
3452
+ }
3453
+ function assertConversationRevision(database, conversationId, revision2) {
3454
+ if (getConversationRevision(database, conversationId) !== revision2) {
3455
+ throw new Error("The conversation changed during summarization. Retry the request.");
3456
+ }
3457
+ }
3458
+
3459
+ // src/lib/db/chat/toolCallEventIndex.ts
3460
+ var import_watermelondb3 = require("@nozbe/watermelondb");
3307
3461
  function parseEventIds(value) {
3308
3462
  const ids = /* @__PURE__ */ new Set();
3309
3463
  let events;
@@ -3323,7 +3477,7 @@ function parseEventIds(value) {
3323
3477
  async function fetchEventRows(collection, conversationId) {
3324
3478
  try {
3325
3479
  return await collection.query(
3326
- import_watermelondb2.Q.unsafeSqlQuery(
3480
+ import_watermelondb3.Q.unsafeSqlQuery(
3327
3481
  `select "id", "tool_call_events" from "history" where "conversation_id" = ? and "_status" != 'deleted' and "tool_call_events" is not null and "tool_call_events" not in ('', '[]')`,
3328
3482
  [conversationId]
3329
3483
  )
@@ -3333,10 +3487,10 @@ async function fetchEventRows(collection, conversationId) {
3333
3487
  throw error;
3334
3488
  }
3335
3489
  return await collection.query(
3336
- import_watermelondb2.Q.where("conversation_id", conversationId),
3337
- import_watermelondb2.Q.where("tool_call_events", import_watermelondb2.Q.notEq(null)),
3338
- import_watermelondb2.Q.where("tool_call_events", import_watermelondb2.Q.notIn(["", "[]"])),
3339
- import_watermelondb2.Q.unsafeLokiTransform(
3490
+ import_watermelondb3.Q.where("conversation_id", conversationId),
3491
+ import_watermelondb3.Q.where("tool_call_events", import_watermelondb3.Q.notEq(null)),
3492
+ import_watermelondb3.Q.where("tool_call_events", import_watermelondb3.Q.notIn(["", "[]"])),
3493
+ import_watermelondb3.Q.unsafeLokiTransform(
3340
3494
  (rows) => rows.map(({ id: id2, tool_call_events }) => ({ id: id2, tool_call_events }))
3341
3495
  )
3342
3496
  ).unsafeFetchRaw();
@@ -3806,7 +3960,7 @@ async function createConversationOp(ctx, opts, defaultTitle = "New Conversation"
3806
3960
  );
3807
3961
  }
3808
3962
  async function getConversationOp(ctx, id2) {
3809
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
3963
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
3810
3964
  return results.length > 0 ? await conversationToStored(
3811
3965
  results[0],
3812
3966
  ctx.walletAddress,
@@ -3815,7 +3969,7 @@ async function getConversationOp(ctx, id2) {
3815
3969
  ) : null;
3816
3970
  }
3817
3971
  async function getConversationsOp(ctx) {
3818
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("is_deleted", false), import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)).unsafeFetchRaw();
3972
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("is_deleted", false), import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)).unsafeFetchRaw();
3819
3973
  return Promise.all(
3820
3974
  results.map(
3821
3975
  (raw) => conversationRawToStored(raw, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
@@ -3836,33 +3990,33 @@ function conversationRawToLazyStored(raw) {
3836
3990
  };
3837
3991
  }
3838
3992
  async function getConversationsLazyOp(ctx) {
3839
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("is_deleted", false), import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)).unsafeFetchRaw();
3993
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("is_deleted", false), import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)).unsafeFetchRaw();
3840
3994
  return results.map(conversationRawToLazyStored);
3841
3995
  }
3842
3996
  async function getConversationsPageOp(ctx, options) {
3843
3997
  const limit = Math.floor(options?.limit ?? 200);
3844
3998
  if (!Number.isFinite(limit) || limit < 1) return [];
3845
3999
  const exclude = new Set(options?.boundaryExcludeUniqueIds ?? []);
3846
- const clauses = [import_watermelondb3.Q.where("is_deleted", false)];
4000
+ const clauses = [import_watermelondb4.Q.where("is_deleted", false)];
3847
4001
  if (options?.before !== void 0) {
3848
4002
  clauses.push(
3849
- exclude.size > 0 ? import_watermelondb3.Q.where("created_at", import_watermelondb3.Q.lte(options.before)) : import_watermelondb3.Q.where("created_at", import_watermelondb3.Q.lt(options.before))
4003
+ exclude.size > 0 ? import_watermelondb4.Q.where("created_at", import_watermelondb4.Q.lte(options.before)) : import_watermelondb4.Q.where("created_at", import_watermelondb4.Q.lt(options.before))
3850
4004
  );
3851
4005
  }
3852
- const fetched = await ctx.conversationsCollection.query(...clauses, import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc), import_watermelondb3.Q.take(limit + exclude.size)).unsafeFetchRaw();
4006
+ const fetched = await ctx.conversationsCollection.query(...clauses, import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc), import_watermelondb4.Q.take(limit + exclude.size)).unsafeFetchRaw();
3853
4007
  const results = exclude.size > 0 ? fetched.filter((raw) => !exclude.has(raw.id)) : fetched;
3854
4008
  return results.slice(0, limit).map(conversationRawToLazyStored);
3855
4009
  }
3856
4010
  async function getConversationsByProjectLazyOp(ctx, projectId) {
3857
4011
  const results = await ctx.conversationsCollection.query(
3858
- import_watermelondb3.Q.where("project_id", projectId === null ? "" : projectId),
3859
- import_watermelondb3.Q.where("is_deleted", false),
3860
- import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)
4012
+ import_watermelondb4.Q.where("project_id", projectId === null ? "" : projectId),
4013
+ import_watermelondb4.Q.where("is_deleted", false),
4014
+ import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)
3861
4015
  ).unsafeFetchRaw();
3862
4016
  return results.map(conversationRawToLazyStored);
3863
4017
  }
3864
4018
  async function updateConversationTitleOp(ctx, id2, title) {
3865
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
4019
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
3866
4020
  if (results.length > 0) {
3867
4021
  const encryptedOpts = ctx.walletAddress && ctx.signMessage ? await encryptConversationFields(
3868
4022
  { title },
@@ -3881,13 +4035,13 @@ async function updateConversationTitleOp(ctx, id2, title) {
3881
4035
  return false;
3882
4036
  }
3883
4037
  async function deleteConversationOp(ctx, id2) {
3884
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
4038
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
3885
4039
  if (results.length > 0) {
3886
4040
  await ctx.database.write(async () => {
3887
4041
  await results[0].update((conv) => {
3888
4042
  conv._setRaw("is_deleted", true);
3889
4043
  });
3890
- const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb3.Q.where("conversation_id", id2)).fetch() : [];
4044
+ const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb4.Q.where("conversation_id", id2)).fetch() : [];
3891
4045
  for (const job of jobs) await job.destroyPermanently();
3892
4046
  });
3893
4047
  return true;
@@ -3895,7 +4049,7 @@ async function deleteConversationOp(ctx, id2) {
3895
4049
  return false;
3896
4050
  }
3897
4051
  async function updateConversationPinnedOp(ctx, id2, pinned) {
3898
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
4052
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
3899
4053
  if (results.length > 0) {
3900
4054
  await ctx.database.write(async () => {
3901
4055
  await results[0].update((conv) => {
@@ -3907,7 +4061,7 @@ async function updateConversationPinnedOp(ctx, id2, pinned) {
3907
4061
  return false;
3908
4062
  }
3909
4063
  async function getMessagesOp(ctx, convId, opts) {
3910
- const fetched = await ctx.messagesCollection.query(import_watermelondb3.Q.where("conversation_id", convId), import_watermelondb3.Q.sortBy("message_id", import_watermelondb3.Q.asc)).unsafeFetchRaw();
4064
+ const fetched = await ctx.messagesCollection.query(import_watermelondb4.Q.where("conversation_id", convId), import_watermelondb4.Q.sortBy("message_id", import_watermelondb4.Q.asc)).unsafeFetchRaw();
3911
4065
  const results = opts?.rawFilter ? fetched.filter(opts.rawFilter) : fetched;
3912
4066
  return Promise.all(
3913
4067
  results.map(
@@ -3916,19 +4070,19 @@ async function getMessagesOp(ctx, convId, opts) {
3916
4070
  );
3917
4071
  }
3918
4072
  async function getMessageCountOp(ctx, convId) {
3919
- return await ctx.messagesCollection.query(import_watermelondb3.Q.where("conversation_id", convId)).fetchCount();
4073
+ return await ctx.messagesCollection.query(import_watermelondb4.Q.where("conversation_id", convId)).fetchCount();
3920
4074
  }
3921
4075
  async function getMessagesPageOp(ctx, convId, opts) {
3922
4076
  const limit = Math.floor(opts.limit);
3923
4077
  if (!Number.isFinite(limit) || limit < 1) return [];
3924
4078
  const exclude = new Set(opts.boundaryExcludeUniqueIds ?? []);
3925
- const clauses = [import_watermelondb3.Q.where("conversation_id", convId)];
4079
+ const clauses = [import_watermelondb4.Q.where("conversation_id", convId)];
3926
4080
  if (opts.beforeMessageId !== void 0) {
3927
4081
  clauses.push(
3928
- exclude.size > 0 ? import_watermelondb3.Q.where("message_id", import_watermelondb3.Q.lte(opts.beforeMessageId)) : import_watermelondb3.Q.where("message_id", import_watermelondb3.Q.lt(opts.beforeMessageId))
4082
+ exclude.size > 0 ? import_watermelondb4.Q.where("message_id", import_watermelondb4.Q.lte(opts.beforeMessageId)) : import_watermelondb4.Q.where("message_id", import_watermelondb4.Q.lt(opts.beforeMessageId))
3929
4083
  );
3930
4084
  }
3931
- const fetched = await ctx.messagesCollection.query(...clauses, import_watermelondb3.Q.sortBy("message_id", import_watermelondb3.Q.desc), import_watermelondb3.Q.take(limit + exclude.size)).unsafeFetchRaw();
4085
+ const fetched = await ctx.messagesCollection.query(...clauses, import_watermelondb4.Q.sortBy("message_id", import_watermelondb4.Q.desc), import_watermelondb4.Q.take(limit + exclude.size)).unsafeFetchRaw();
3932
4086
  const results = (exclude.size > 0 ? fetched.filter((raw) => !exclude.has(raw.id)) : fetched).slice(0, limit);
3933
4087
  results.reverse();
3934
4088
  return Promise.all(
@@ -3940,7 +4094,7 @@ async function getMessagesPageOp(ctx, convId, opts) {
3940
4094
  );
3941
4095
  }
3942
4096
  async function getMessageSkeletonsOp(ctx, convId) {
3943
- const results = await ctx.messagesCollection.query(import_watermelondb3.Q.where("conversation_id", convId), import_watermelondb3.Q.sortBy("message_id", import_watermelondb3.Q.asc)).unsafeFetchRaw();
4097
+ const results = await ctx.messagesCollection.query(import_watermelondb4.Q.where("conversation_id", convId), import_watermelondb4.Q.sortBy("message_id", import_watermelondb4.Q.asc)).unsafeFetchRaw();
3944
4098
  const roleById = /* @__PURE__ */ new Map();
3945
4099
  for (const raw of results) {
3946
4100
  roleById.set(raw.id, raw.role);
@@ -3987,10 +4141,22 @@ async function getMessageSkeletonsOp(ctx, convId) {
3987
4141
  async function getToolCallEventIdsOp(ctx, convId) {
3988
4142
  return getToolCallEventIds(ctx.messagesCollection, convId);
3989
4143
  }
4144
+ async function invalidateConversationSummary(ctx, conversationId, changedMessageId) {
4145
+ if (!ctx.database.schema?.tables[ConversationSummary.table]) return;
4146
+ const summaries = await ctx.database.get(ConversationSummary.table).query(import_watermelondb4.Q.where("conversation_id", conversationId)).fetch();
4147
+ for (const summary of summaries) {
4148
+ if (changedMessageId !== void 0) {
4149
+ const [boundary] = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", summary.summarizedUpTo), import_watermelondb4.Q.where("conversation_id", conversationId)).fetch();
4150
+ if (boundary && changedMessageId > boundary.messageId) continue;
4151
+ }
4152
+ await summary.destroyPermanently();
4153
+ }
4154
+ }
3990
4155
  async function clearMessagesOp(ctx, convId) {
3991
4156
  await ctx.database.write(async () => {
3992
- const messages = await ctx.messagesCollection.query(import_watermelondb3.Q.where("conversation_id", convId)).fetch();
3993
- const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb3.Q.where("conversation_id", convId)).fetch() : [];
4157
+ await invalidateConversationSummary(ctx, convId);
4158
+ const messages = await ctx.messagesCollection.query(import_watermelondb4.Q.where("conversation_id", convId)).fetch();
4159
+ const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb4.Q.where("conversation_id", convId)).fetch() : [];
3994
4160
  for (const job of jobs) {
3995
4161
  await job.update((row) => {
3996
4162
  row._setRaw("message_ids", "[]");
@@ -4000,11 +4166,12 @@ async function clearMessagesOp(ctx, convId) {
4000
4166
  }
4001
4167
  for (const message of messages) {
4002
4168
  await message.update((msg) => {
4003
- msg._setRaw("file_ids", null);
4169
+ if (ctx.messagesCollection.schema.columns.file_ids) msg._setRaw("file_ids", null);
4004
4170
  msg._setRaw("files", null);
4005
4171
  });
4006
4172
  await message.destroyPermanently();
4007
4173
  }
4174
+ advanceConversationRevision(ctx.database, convId);
4008
4175
  });
4009
4176
  }
4010
4177
  async function deleteMessageOp(ctx, uniqueId) {
@@ -4015,7 +4182,8 @@ async function deleteMessageOp(ctx, uniqueId) {
4015
4182
  return null;
4016
4183
  }
4017
4184
  await ctx.database.write(async () => {
4018
- const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb3.Q.where("conversation_id", message.conversationId)).fetch() : [];
4185
+ await invalidateConversationSummary(ctx, message.conversationId, message.messageId);
4186
+ const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb4.Q.where("conversation_id", message.conversationId)).fetch() : [];
4019
4187
  for (const job of jobs) {
4020
4188
  const ids = JSON.parse(String(job._getRaw("message_ids")));
4021
4189
  await job.update((row) => {
@@ -4024,10 +4192,11 @@ async function deleteMessageOp(ctx, uniqueId) {
4024
4192
  });
4025
4193
  }
4026
4194
  await message.update((msg) => {
4027
- msg._setRaw("file_ids", null);
4195
+ if (ctx.messagesCollection.schema.columns.file_ids) msg._setRaw("file_ids", null);
4028
4196
  msg._setRaw("files", null);
4029
4197
  });
4030
4198
  await message.destroyPermanently();
4199
+ advanceConversationRevision(ctx.database, message.conversationId);
4031
4200
  });
4032
4201
  return uniqueId;
4033
4202
  }
@@ -4088,9 +4257,9 @@ async function createMessageOp(ctx, opts) {
4088
4257
  }
4089
4258
  }
4090
4259
  const newest = await ctx.messagesCollection.query(
4091
- import_watermelondb3.Q.where("conversation_id", opts.conversationId),
4092
- import_watermelondb3.Q.sortBy("message_id", import_watermelondb3.Q.desc),
4093
- import_watermelondb3.Q.take(1)
4260
+ import_watermelondb4.Q.where("conversation_id", opts.conversationId),
4261
+ import_watermelondb4.Q.sortBy("message_id", import_watermelondb4.Q.desc),
4262
+ import_watermelondb4.Q.take(1)
4094
4263
  ).fetch();
4095
4264
  const messageId = (newest[0]?.messageId ?? 0) + 1;
4096
4265
  const encryptedOpts = await encryptMessageOptsIfNeeded(ctx, opts);
@@ -4104,7 +4273,7 @@ async function createMessageOp(ctx, opts) {
4104
4273
  return messageToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
4105
4274
  }
4106
4275
  async function upsertMessageOp(ctx, opts) {
4107
- const results = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", opts.uniqueId)).fetch();
4276
+ const results = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", opts.uniqueId)).fetch();
4108
4277
  const existing = results.length > 0 ? results[0] : null;
4109
4278
  if (!existing) {
4110
4279
  return createMessageOp(ctx, opts);
@@ -4212,13 +4381,13 @@ async function decryptMessageEmbeddingFields(raw, walletAddress) {
4212
4381
  async function sealLegacyMessageEmbeddingsOp(ctx) {
4213
4382
  if (!ctx.walletAddress) return 0;
4214
4383
  const candidateIds = await ctx.messagesCollection.query(
4215
- import_watermelondb3.Q.where("content", import_watermelondb3.Q.like("enc:%")),
4216
- import_watermelondb3.Q.or(
4384
+ import_watermelondb4.Q.where("content", import_watermelondb4.Q.like("enc:%")),
4385
+ import_watermelondb4.Q.or(
4217
4386
  ...["vector", "chunks"].map(
4218
- (column) => import_watermelondb3.Q.and(
4219
- import_watermelondb3.Q.where(column, import_watermelondb3.Q.notEq(null)),
4220
- import_watermelondb3.Q.where(column, import_watermelondb3.Q.notEq("")),
4221
- import_watermelondb3.Q.where(column, import_watermelondb3.Q.notLike("enc:%"))
4387
+ (column) => import_watermelondb4.Q.and(
4388
+ import_watermelondb4.Q.where(column, import_watermelondb4.Q.notEq(null)),
4389
+ import_watermelondb4.Q.where(column, import_watermelondb4.Q.notEq("")),
4390
+ import_watermelondb4.Q.where(column, import_watermelondb4.Q.notLike("enc:%"))
4222
4391
  )
4223
4392
  )
4224
4393
  )
@@ -4228,7 +4397,7 @@ async function sealLegacyMessageEmbeddingsOp(ctx) {
4228
4397
  for (let start = 0; start < candidateIds.length; start += 50) {
4229
4398
  const pageIds = candidateIds.slice(start, start + 50);
4230
4399
  await ctx.database.write(async () => {
4231
- const pageMessages = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(pageIds))).fetch();
4400
+ const pageMessages = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(pageIds))).fetch();
4232
4401
  for (const message of pageMessages) {
4233
4402
  if (!isEncrypted(message.content)) continue;
4234
4403
  const content = await decryptFieldDetailed(message.content, ctx.walletAddress);
@@ -4309,15 +4478,15 @@ function chunksWithoutText(raw) {
4309
4478
  });
4310
4479
  }
4311
4480
  async function stripLegacyChunkTextOp(ctx) {
4312
- const candidateIds = await ctx.messagesCollection.query(import_watermelondb3.Q.where("chunks", import_watermelondb3.Q.like(`%${import_watermelondb3.Q.sanitizeLikeString('"text":')}%`))).fetchIds();
4481
+ const candidateIds = await ctx.messagesCollection.query(import_watermelondb4.Q.where("chunks", import_watermelondb4.Q.like(`%${import_watermelondb4.Q.sanitizeLikeString('"text":')}%`))).fetchIds();
4313
4482
  let stripped = 0;
4314
4483
  for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
4315
4484
  const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
4316
- const rows = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(pageIds))).unsafeFetchRaw();
4485
+ const rows = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(pageIds))).unsafeFetchRaw();
4317
4486
  const changedIds = rows.filter((row) => chunksWithoutText(row.chunks) !== null).map((row) => String(row.id));
4318
4487
  if (changedIds.length === 0) continue;
4319
4488
  await ctx.database.write(async () => {
4320
- const messages = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(changedIds))).fetch();
4489
+ const messages = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(changedIds))).fetch();
4321
4490
  const updates = messages.flatMap((message) => {
4322
4491
  const raw = message._raw;
4323
4492
  const chunks3 = chunksWithoutText(raw.chunks);
@@ -4364,13 +4533,13 @@ async function encryptToolCallEventsOp(ctx) {
4364
4533
  return 0;
4365
4534
  }
4366
4535
  const candidateIds = await ctx.messagesCollection.query(
4367
- import_watermelondb3.Q.where("tool_call_events", import_watermelondb3.Q.notEq(null)),
4368
- import_watermelondb3.Q.where("tool_call_events", import_watermelondb3.Q.notIn(["", "[]"]))
4536
+ import_watermelondb4.Q.where("tool_call_events", import_watermelondb4.Q.notEq(null)),
4537
+ import_watermelondb4.Q.where("tool_call_events", import_watermelondb4.Q.notIn(["", "[]"]))
4369
4538
  ).fetchIds();
4370
4539
  let encrypted = 0;
4371
4540
  for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
4372
4541
  const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
4373
- const rows = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(pageIds))).unsafeFetchRaw();
4542
+ const rows = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(pageIds))).unsafeFetchRaw();
4374
4543
  const repairs = /* @__PURE__ */ new Map();
4375
4544
  for (const row of rows) {
4376
4545
  const column = await encryptedToolCallEventsColumn(
@@ -4383,12 +4552,12 @@ async function encryptToolCallEventsOp(ctx) {
4383
4552
  }
4384
4553
  if (repairs.size === 0) continue;
4385
4554
  await ctx.database.write(async () => {
4386
- const messages = (await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf([...repairs.keys()]))).fetch()).filter(
4555
+ const messages = (await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf([...repairs.keys()]))).fetch()).filter(
4387
4556
  (message) => message._raw.tool_call_events === repairs.get(message.id)?.raw
4388
4557
  );
4389
4558
  if (messages.length === 0) return;
4390
4559
  const conversationIds = [...new Set(messages.map((message) => message.conversationId))];
4391
- const conversations = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", import_watermelondb3.Q.oneOf(conversationIds))).fetch();
4560
+ const conversations = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", import_watermelondb4.Q.oneOf(conversationIds))).fetch();
4392
4561
  await ctx.database.batch(
4393
4562
  ...messages.map(
4394
4563
  (message) => message.prepareUpdate((msg) => {
@@ -4415,7 +4584,7 @@ async function savedKeyOpensExistingData(ctx, address, signMessage, embeddedWall
4415
4584
  return refreshEncryptionKeyIfMatches(address, v2Probe, signMessage, embeddedWalletSigner);
4416
4585
  }
4417
4586
  async function findEncryptedContent(ctx, pattern) {
4418
- const [row] = await ctx.messagesCollection.query(import_watermelondb3.Q.where("content", import_watermelondb3.Q.like(pattern)), import_watermelondb3.Q.take(1)).unsafeFetchRaw();
4587
+ const [row] = await ctx.messagesCollection.query(import_watermelondb4.Q.where("content", import_watermelondb4.Q.like(pattern)), import_watermelondb4.Q.take(1)).unsafeFetchRaw();
4419
4588
  return row ? String(row.content) : null;
4420
4589
  }
4421
4590
  async function updateMessageErrorOp(ctx, uniqueId, error) {
@@ -4446,6 +4615,14 @@ async function _updateMessageOp(ctx, uniqueId, opts) {
4446
4615
  ctx.embeddedWalletSigner
4447
4616
  ) : opts;
4448
4617
  await ctx.database.write(async () => {
4618
+ let contentChanged = false;
4619
+ if (opts.content !== void 0) {
4620
+ const originalContent = ctx.walletAddress ? await decryptField(message.content, ctx.walletAddress) : message.content;
4621
+ contentChanged = opts.content !== originalContent;
4622
+ if (contentChanged) {
4623
+ await invalidateConversationSummary(ctx, message.conversationId, message.messageId);
4624
+ }
4625
+ }
4449
4626
  await message.update((msg) => {
4450
4627
  if (encryptedOpts.content !== void 0)
4451
4628
  msg._setRaw("content", encryptedOpts.content);
@@ -4490,6 +4667,7 @@ async function _updateMessageOp(ctx, uniqueId, opts) {
4490
4667
  msg._setRaw("tool_call_events", tceValue);
4491
4668
  }
4492
4669
  });
4670
+ if (contentChanged) advanceConversationRevision(ctx.database, message.conversationId);
4493
4671
  });
4494
4672
  return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
4495
4673
  }
@@ -4528,7 +4706,7 @@ function toChunkCandidateKey(raw) {
4528
4706
  }
4529
4707
  async function fetchRowsByIds(ctx, ids) {
4530
4708
  if (ids.length === 0) return [];
4531
- return await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(ids))).unsafeFetchRaw();
4709
+ return await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(ids))).unsafeFetchRaw();
4532
4710
  }
4533
4711
  async function projectedChunkRowSource(ctx, filter) {
4534
4712
  const clauses = [
@@ -4546,7 +4724,7 @@ async function projectedChunkRowSource(ctx, filter) {
4546
4724
  args.push(filter.excludeConversationId);
4547
4725
  }
4548
4726
  const keyRows = await ctx.messagesCollection.query(
4549
- import_watermelondb3.Q.unsafeSqlQuery(
4727
+ import_watermelondb4.Q.unsafeSqlQuery(
4550
4728
  `select "id", "conversation_id", "updated_at", "embedding_model" from "history" where ${clauses.join(" and ")}`,
4551
4729
  args
4552
4730
  )
@@ -4556,7 +4734,7 @@ async function projectedChunkRowSource(ctx, filter) {
4556
4734
  loadVectorRows: async (ids) => {
4557
4735
  if (ids.length === 0) return [];
4558
4736
  return await ctx.messagesCollection.query(
4559
- import_watermelondb3.Q.unsafeSqlQuery(
4737
+ import_watermelondb4.Q.unsafeSqlQuery(
4560
4738
  `select "id", "updated_at", "chunks", "vector" from "history" where "_status" is not 'deleted' and "id" in (${ids.map(() => "?").join(",")})`,
4561
4739
  ids
4562
4740
  )
@@ -4566,11 +4744,11 @@ async function projectedChunkRowSource(ctx, filter) {
4566
4744
  };
4567
4745
  }
4568
4746
  async function fullScanChunkRowSource(ctx, filter) {
4569
- const activeConversations = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("is_deleted", false)).fetch();
4747
+ const activeConversations = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("is_deleted", false)).fetch();
4570
4748
  const activeConversationIds = new Set(
4571
4749
  activeConversations.map((c) => String(c._getRaw("conversation_id")))
4572
4750
  );
4573
- const queryConditions = filter.conversationId !== void 0 ? [import_watermelondb3.Q.where("conversation_id", filter.conversationId)] : [];
4751
+ const queryConditions = filter.conversationId !== void 0 ? [import_watermelondb4.Q.where("conversation_id", filter.conversationId)] : [];
4574
4752
  const rows = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
4575
4753
  const rowsById = /* @__PURE__ */ new Map();
4576
4754
  for (const row of rows) {
@@ -6427,22 +6605,22 @@ function toReceipt(action, argumentsJson, output) {
6427
6605
  const result = parseObject(output);
6428
6606
  return {
6429
6607
  kind: action.kind,
6430
- venueName: text(args.venue_name) ?? "",
6431
- day: text(args.day) ?? "",
6432
- time: text(args.time) ?? "",
6608
+ venueName: text2(args.venue_name) ?? "",
6609
+ day: text2(args.day) ?? "",
6610
+ time: text2(args.time) ?? "",
6433
6611
  partySize: count(args.party_size),
6434
- reservationId: text(result.reservation_id) ?? text(args.reservation_id),
6435
- resyUrl: text(result.reservations_url),
6436
- feeSummary: text(result.fee_summary),
6612
+ reservationId: text2(result.reservation_id) ?? text2(args.reservation_id),
6613
+ resyUrl: text2(result.reservations_url),
6614
+ feeSummary: text2(result.fee_summary),
6437
6615
  ...outcome(action, output, result)
6438
6616
  };
6439
6617
  }
6440
6618
  function outcome(action, output, result) {
6441
6619
  if (action.alreadyDone.test(output)) return { status: "already_done" };
6442
- const reason = text(result.error);
6620
+ const reason = text2(result.error);
6443
6621
  if (action.kind === "booking") {
6444
6622
  if (BOOKING_OUTCOME_UNKNOWN.test(output)) return { status: "unknown" };
6445
- const held = result.success === true || text(result.reservation_id) !== void 0;
6623
+ const held = result.success === true || text2(result.reservation_id) !== void 0;
6446
6624
  return held ? { status: "made" } : { status: "not_made", reason };
6447
6625
  }
6448
6626
  if (result.error_code === CANCEL_OUTCOME_UNKNOWN) return { status: "unknown", reason };
@@ -6457,7 +6635,7 @@ function parseObject(json5) {
6457
6635
  return {};
6458
6636
  }
6459
6637
  }
6460
- function text(value) {
6638
+ function text2(value) {
6461
6639
  if (typeof value === "number") return String(value);
6462
6640
  return typeof value === "string" && value ? value : void 0;
6463
6641
  }
@@ -11942,7 +12120,7 @@ function hasControl(value) {
11942
12120
  function integer(value, minimum = 0) {
11943
12121
  return Number.isSafeInteger(value) && value >= minimum;
11944
12122
  }
11945
- function json(value, ancestors = /* @__PURE__ */ new Set()) {
12123
+ function json2(value, ancestors = /* @__PURE__ */ new Set()) {
11946
12124
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
11947
12125
  if (typeof value === "number") return Number.isFinite(value);
11948
12126
  if (typeof value !== "object" || ancestors.has(value)) return false;
@@ -11950,12 +12128,12 @@ function json(value, ancestors = /* @__PURE__ */ new Set()) {
11950
12128
  if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
11951
12129
  return false;
11952
12130
  ancestors.add(value);
11953
- const valid = Object.values(value).every((v) => json(v, ancestors));
12131
+ const valid = Object.values(value).every((v) => json2(v, ancestors));
11954
12132
  ancestors.delete(value);
11955
12133
  return valid;
11956
12134
  }
11957
12135
  function validRecord(value) {
11958
- if (!object(value) || typeof value.kind !== "string" || !kinds.has(value.kind) || !id(value.id) || !integer(value.sortKey) || !integer(value.createdAt, 1) || !integer(value.updatedAt, 1) || typeof value.isDeleted !== "boolean" || !object(value.data) || !json(value.data) || Object.keys(value).some(
12136
+ if (!object(value) || typeof value.kind !== "string" || !kinds.has(value.kind) || !id(value.id) || !integer(value.sortKey) || !integer(value.createdAt, 1) || !integer(value.updatedAt, 1) || typeof value.isDeleted !== "boolean" || !object(value.data) || !json2(value.data) || Object.keys(value).some(
11959
12137
  (key) => ![...metadata, "data"].includes(key)
11960
12138
  ))
11961
12139
  return false;
@@ -11984,14 +12162,14 @@ function vectorFields(write) {
11984
12162
  ...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
11985
12163
  };
11986
12164
  }
11987
- function text2(value) {
12165
+ function text3(value) {
11988
12166
  return typeof value === "string";
11989
12167
  }
11990
12168
  function timestamp(value) {
11991
12169
  return typeof value === "string" && Number.isFinite(Date.parse(value));
11992
12170
  }
11993
12171
  function presigned(value) {
11994
- if (!object(value) || !text2(value.url) || !/^https:\/\//.test(value.url) || !text2(value.method) || !object(value.headers) || !Object.values(value.headers).every(text2) || !timestamp(value.expires_at))
12172
+ if (!object(value) || !text3(value.url) || !/^https:\/\//.test(value.url) || !text3(value.method) || !object(value.headers) || !Object.values(value.headers).every(text3) || !timestamp(value.expires_at))
11995
12173
  invalid();
11996
12174
  return {
11997
12175
  url: value.url,
@@ -12001,7 +12179,7 @@ function presigned(value) {
12001
12179
  };
12002
12180
  }
12003
12181
  function attachment(value) {
12004
- if (!object(value) || !text2(value.attachment_id) || !attachmentIdPattern.test(value.attachment_id) || !integer(value.size_bytes, 1) || value.state !== "pending" && value.state !== "committed" || value.owner_kind !== void 0 && value.owner_kind !== "message" && value.owner_kind !== "summary" || value.owner_id !== void 0 && !id(value.owner_id) || !timestamp(value.created_at) || value.committed_at !== void 0 && !timestamp(value.committed_at))
12182
+ if (!object(value) || !text3(value.attachment_id) || !attachmentIdPattern.test(value.attachment_id) || !integer(value.size_bytes, 1) || value.state !== "pending" && value.state !== "committed" || value.owner_kind !== void 0 && value.owner_kind !== "message" && value.owner_kind !== "summary" || value.owner_id !== void 0 && !id(value.owner_id) || !timestamp(value.created_at) || value.committed_at !== void 0 && !timestamp(value.committed_at))
12005
12183
  invalid();
12006
12184
  return {
12007
12185
  id: value.attachment_id,
@@ -12014,7 +12192,7 @@ function attachment(value) {
12014
12192
  };
12015
12193
  }
12016
12194
  function ref(value) {
12017
- if (!object(value) || !text2(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
12195
+ if (!object(value) || !text3(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
12018
12196
  return { kind: value.kind, id: value.id };
12019
12197
  }
12020
12198
  function sameMetadata(a, b) {
@@ -12237,7 +12415,7 @@ async function createRemoteChatStore(options) {
12237
12415
  },
12238
12416
  async account(signal) {
12239
12417
  const value = await request("/account", {}, signal);
12240
- if (!object(value) || value.account_id !== accountId || !text2(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count))
12418
+ if (!object(value) || value.account_id !== accountId || !text3(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count))
12241
12419
  invalid();
12242
12420
  if (value.key_id && value.key_id !== keyId)
12243
12421
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -12311,12 +12489,12 @@ async function createRemoteChatStore(options) {
12311
12489
  },
12312
12490
  async changes(cursor, options2) {
12313
12491
  const limit = options2?.limit ?? 100;
12314
- if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text2(cursor) || cursor.length > 2048))
12492
+ if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text3(cursor) || cursor.length > 2048))
12315
12493
  invalid();
12316
12494
  const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
12317
12495
  if (cursor) params.set("cursor", cursor);
12318
12496
  const value = await request(`/changes?${params}`, {}, options2?.signal);
12319
- if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !text2(value.next_cursor) || value.changes_cursor !== void 0 && !text2(value.changes_cursor))
12497
+ if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !text3(value.next_cursor) || value.changes_cursor !== void 0 && !text3(value.changes_cursor))
12320
12498
  invalid();
12321
12499
  const items = [];
12322
12500
  for (const item of value.items) items.push(await decode(item));
@@ -12507,141 +12685,6 @@ async function decryptConversationTitle(encryptedTitle, address) {
12507
12685
  }
12508
12686
  }
12509
12687
 
12510
- // src/lib/db/chat/models.ts
12511
- var import_watermelondb4 = require("@nozbe/watermelondb");
12512
- var import_decorators = require("@nozbe/watermelondb/decorators");
12513
- var Message = class extends import_watermelondb4.Model {
12514
- };
12515
- Message.table = "history";
12516
- Message.associations = {
12517
- conversations: { type: "belongs_to", key: "conversation_id" },
12518
- media: { type: "has_many", foreignKey: "message_id" }
12519
- };
12520
- __decorateClass([
12521
- (0, import_decorators.field)("message_id")
12522
- ], Message.prototype, "messageId", 2);
12523
- __decorateClass([
12524
- (0, import_decorators.text)("conversation_id")
12525
- ], Message.prototype, "conversationId", 2);
12526
- __decorateClass([
12527
- (0, import_decorators.text)("role")
12528
- ], Message.prototype, "role", 2);
12529
- __decorateClass([
12530
- (0, import_decorators.text)("content")
12531
- ], Message.prototype, "content", 2);
12532
- __decorateClass([
12533
- (0, import_decorators.text)("model")
12534
- ], Message.prototype, "model", 2);
12535
- __decorateClass([
12536
- (0, import_decorators.text)("image_model")
12537
- ], Message.prototype, "imageModel", 2);
12538
- __decorateClass([
12539
- (0, import_decorators.json)("files", (raw) => raw)
12540
- ], Message.prototype, "files", 2);
12541
- __decorateClass([
12542
- (0, import_decorators.json)("file_ids", (raw) => raw)
12543
- ], Message.prototype, "fileIds", 2);
12544
- __decorateClass([
12545
- (0, import_decorators.date)("created_at")
12546
- ], Message.prototype, "createdAt", 2);
12547
- __decorateClass([
12548
- (0, import_decorators.date)("updated_at")
12549
- ], Message.prototype, "updatedAt", 2);
12550
- __decorateClass([
12551
- (0, import_decorators.json)("vector", (raw) => raw)
12552
- ], Message.prototype, "vector", 2);
12553
- __decorateClass([
12554
- (0, import_decorators.text)("embedding_model")
12555
- ], Message.prototype, "embeddingModel", 2);
12556
- __decorateClass([
12557
- (0, import_decorators.json)("chunks", (raw) => raw)
12558
- ], Message.prototype, "chunks", 2);
12559
- __decorateClass([
12560
- (0, import_decorators.json)("usage", (raw) => raw)
12561
- ], Message.prototype, "usage", 2);
12562
- __decorateClass([
12563
- (0, import_decorators.json)("sources", (raw) => raw)
12564
- ], Message.prototype, "sources", 2);
12565
- __decorateClass([
12566
- (0, import_decorators.field)("response_duration")
12567
- ], Message.prototype, "responseDuration", 2);
12568
- __decorateClass([
12569
- (0, import_decorators.field)("was_stopped")
12570
- ], Message.prototype, "wasStopped", 2);
12571
- __decorateClass([
12572
- (0, import_decorators.text)("error")
12573
- ], Message.prototype, "error", 2);
12574
- __decorateClass([
12575
- (0, import_decorators.json)("thought_process", (raw) => raw)
12576
- ], Message.prototype, "thoughtProcess", 2);
12577
- __decorateClass([
12578
- (0, import_decorators.text)("thinking")
12579
- ], Message.prototype, "thinking", 2);
12580
- __decorateClass([
12581
- (0, import_decorators.text)("parent_message_id")
12582
- ], Message.prototype, "parentMessageId", 2);
12583
- __decorateClass([
12584
- (0, import_decorators.text)("feedback")
12585
- ], Message.prototype, "feedback", 2);
12586
- __decorateClass([
12587
- (0, import_decorators.json)("tool_call_events", (raw) => raw)
12588
- ], Message.prototype, "toolCallEvents", 2);
12589
- __decorateClass([
12590
- (0, import_decorators.text)("origin")
12591
- ], Message.prototype, "origin", 2);
12592
- var Conversation = class extends import_watermelondb4.Model {
12593
- };
12594
- Conversation.table = "conversations";
12595
- Conversation.associations = {
12596
- history: { type: "has_many", foreignKey: "conversation_id" },
12597
- projects: { type: "belongs_to", key: "project_id" }
12598
- };
12599
- __decorateClass([
12600
- (0, import_decorators.text)("conversation_id")
12601
- ], Conversation.prototype, "conversationId", 2);
12602
- __decorateClass([
12603
- (0, import_decorators.text)("title")
12604
- ], Conversation.prototype, "title", 2);
12605
- __decorateClass([
12606
- (0, import_decorators.text)("project_id")
12607
- ], Conversation.prototype, "projectId", 2);
12608
- __decorateClass([
12609
- (0, import_decorators.date)("created_at")
12610
- ], Conversation.prototype, "createdAt", 2);
12611
- __decorateClass([
12612
- (0, import_decorators.date)("updated_at")
12613
- ], Conversation.prototype, "updatedAt", 2);
12614
- __decorateClass([
12615
- (0, import_decorators.field)("is_deleted")
12616
- ], Conversation.prototype, "isDeleted", 2);
12617
- __decorateClass([
12618
- (0, import_decorators.date)("pinned_at")
12619
- ], Conversation.prototype, "pinnedAt", 2);
12620
- var ConversationSummary = class extends import_watermelondb4.Model {
12621
- };
12622
- ConversationSummary.table = "conversation_summaries";
12623
- ConversationSummary.associations = {
12624
- conversations: { type: "belongs_to", key: "conversation_id" }
12625
- };
12626
- __decorateClass([
12627
- (0, import_decorators.text)("conversation_id")
12628
- ], ConversationSummary.prototype, "conversationId", 2);
12629
- __decorateClass([
12630
- (0, import_decorators.text)("summary")
12631
- ], ConversationSummary.prototype, "summary", 2);
12632
- __decorateClass([
12633
- (0, import_decorators.text)("summarized_up_to")
12634
- ], ConversationSummary.prototype, "summarizedUpTo", 2);
12635
- __decorateClass([
12636
- (0, import_decorators.field)("token_count")
12637
- ], ConversationSummary.prototype, "tokenCount", 2);
12638
- __decorateClass([
12639
- (0, import_decorators.date)("created_at")
12640
- ], ConversationSummary.prototype, "createdAt", 2);
12641
- __decorateClass([
12642
- (0, import_decorators.date)("updated_at")
12643
- ], ConversationSummary.prototype, "updatedAt", 2);
12644
-
12645
12688
  // src/lib/db/chat/schema.ts
12646
12689
  var import_watermelondb5 = require("@nozbe/watermelondb");
12647
12690
  var import_migrations = require("@nozbe/watermelondb/Schema/migrations");
@@ -25123,10 +25166,7 @@ async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark,
25123
25166
  for (const facet of facets) {
25124
25167
  if (!previous.sections.some((s) => s.key === facet.key)) stale.add(facet.key);
25125
25168
  }
25126
- const citedIds = new Set(previous.sections.flatMap((s) => s.sourceMemoryIds));
25127
- let toAttribute = changed.filter(
25128
- (m) => !m.isDeleted && !m.supersededBy && !citedIds.has(m.uniqueId)
25129
- );
25169
+ let toAttribute = changed.filter((m) => !m.isDeleted && !m.supersededBy);
25130
25170
  if (reviewedMemoryIds !== void 0) {
25131
25171
  const allowed = new Set(reviewedMemoryIds);
25132
25172
  toAttribute = toAttribute.filter((m) => allowed.has(m.uniqueId));
@@ -29207,6 +29247,13 @@ var lastCompactionTime = /* @__PURE__ */ new Map();
29207
29247
  var COMPACTION_COOLDOWN_MS = 6e4;
29208
29248
  var MAX_SUMMARY_TOKEN_RATIO = 0.8;
29209
29249
  async function maybeSummarizeHistory(options) {
29250
+ const { database, conversationId } = options;
29251
+ const revision2 = getConversationRevision(database, conversationId);
29252
+ const result = await summarizeHistoryAtRevision(options, revision2);
29253
+ assertConversationRevision(database, conversationId, revision2);
29254
+ return result;
29255
+ }
29256
+ async function summarizeHistoryAtRevision(options, revision2) {
29210
29257
  const { database, conversationId, messages, summarizeHistory, summaryMinWindowMessages, token } = options;
29211
29258
  if (!summarizeHistory) {
29212
29259
  return { messagesToConvert: messages, summarySystemMessage: null };
@@ -29247,7 +29294,7 @@ async function maybeSummarizeHistory(options) {
29247
29294
  clearTimeout(staleGuardTimerId);
29248
29295
  }
29249
29296
  }
29250
- const promise = doSummarizeHistory(options);
29297
+ const promise = doSummarizeHistory(options, revision2);
29251
29298
  summarizationLocks.set(conversationId, promise);
29252
29299
  try {
29253
29300
  return await promise;
@@ -29261,7 +29308,7 @@ Summary to condense:
29261
29308
  {summary}
29262
29309
 
29263
29310
  Condensed summary:`;
29264
- async function doSummarizeHistory(options) {
29311
+ async function doSummarizeHistory(options, revision2) {
29265
29312
  const {
29266
29313
  database,
29267
29314
  conversationId,
@@ -29276,7 +29323,20 @@ async function doSummarizeHistory(options) {
29276
29323
  } = options;
29277
29324
  try {
29278
29325
  const summaryCtx = createSummaryContext(database);
29326
+ const persistSummary = (summary, summarizedUpTo, tokenCount) => database.write(async (writer) => {
29327
+ assertConversationRevision(database, conversationId, revision2);
29328
+ await writer.callWriter(
29329
+ () => upsertConversationSummaryOp(
29330
+ summaryCtx,
29331
+ conversationId,
29332
+ summary,
29333
+ summarizedUpTo,
29334
+ tokenCount
29335
+ )
29336
+ );
29337
+ });
29279
29338
  let cachedSummary = await getConversationSummaryOp(summaryCtx, conversationId);
29339
+ assertConversationRevision(database, conversationId, revision2);
29280
29340
  const lastCompacted = lastCompactionTime.get(conversationId) ?? 0;
29281
29341
  const compactionCooledDown = Date.now() - lastCompacted > COMPACTION_COOLDOWN_MS;
29282
29342
  if (cachedSummary && cachedSummary.tokenCount > summaryTokenThreshold * MAX_SUMMARY_TOKEN_RATIO && compactionCooledDown) {
@@ -29292,13 +29352,7 @@ async function doSummarizeHistory(options) {
29292
29352
  );
29293
29353
  const compactedSummary = redactor ? redactor.deAnonymize(rawCompacted) : rawCompacted;
29294
29354
  const compactedTokens = estimateTokens(compactedSummary);
29295
- await upsertConversationSummaryOp(
29296
- summaryCtx,
29297
- conversationId,
29298
- compactedSummary,
29299
- cachedSummary.summarizedUpTo,
29300
- compactedTokens
29301
- );
29355
+ await persistSummary(compactedSummary, cachedSummary.summarizedUpTo, compactedTokens);
29302
29356
  cachedSummary = {
29303
29357
  ...cachedSummary,
29304
29358
  summary: compactedSummary,
@@ -29306,6 +29360,7 @@ async function doSummarizeHistory(options) {
29306
29360
  };
29307
29361
  lastCompactionTime.set(conversationId, Date.now());
29308
29362
  } catch {
29363
+ assertConversationRevision(database, conversationId, revision2);
29309
29364
  lastCompactionTime.set(conversationId, Date.now());
29310
29365
  getLogger().warn(
29311
29366
  "[summarize] Summary compaction failed, proceeding with oversized summary"
@@ -29337,10 +29392,9 @@ async function doSummarizeHistory(options) {
29337
29392
  redactor,
29338
29393
  onPiiRedacted
29339
29394
  });
29395
+ assertConversationRevision(database, conversationId, revision2);
29340
29396
  if (summarizeResult.didSummarize && summarizeResult.summary && summarizeResult.summarizedUpTo) {
29341
- await upsertConversationSummaryOp(
29342
- summaryCtx,
29343
- conversationId,
29397
+ await persistSummary(
29344
29398
  summarizeResult.summary,
29345
29399
  summarizeResult.summarizedUpTo,
29346
29400
  summarizeResult.summaryTokenCount
@@ -29359,6 +29413,7 @@ async function doSummarizeHistory(options) {
29359
29413
  summarySystemMessage: summarizeResult.summary ? summaryToSystemMessage(summarizeResult.summary) : null
29360
29414
  };
29361
29415
  } catch (err) {
29416
+ assertConversationRevision(database, conversationId, revision2);
29362
29417
  getLogger().warn("[summarize] Summarization failed, falling back to verbatim:", err);
29363
29418
  return { messagesToConvert: messages, summarySystemMessage: null };
29364
29419
  }