@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.
@@ -3554,7 +3554,7 @@ ${appendix}` : appendix;
3554
3554
  }
3555
3555
 
3556
3556
  // src/lib/db/chat/operations.ts
3557
- var import_watermelondb3 = require("@nozbe/watermelondb");
3557
+ var import_watermelondb4 = require("@nozbe/watermelondb");
3558
3558
  var import_uuid2 = require("uuid");
3559
3559
  init_logger();
3560
3560
 
@@ -4010,8 +4010,162 @@ async function assembleDecryptedMessage(message, address) {
4010
4010
  return result;
4011
4011
  }
4012
4012
 
4013
- // src/lib/db/chat/toolCallEventIndex.ts
4013
+ // src/lib/db/chat/models.ts
4014
4014
  var import_watermelondb2 = require("@nozbe/watermelondb");
4015
+ var import_decorators = require("@nozbe/watermelondb/decorators");
4016
+ var Message = class extends import_watermelondb2.Model {
4017
+ };
4018
+ Message.table = "history";
4019
+ Message.associations = {
4020
+ conversations: { type: "belongs_to", key: "conversation_id" },
4021
+ media: { type: "has_many", foreignKey: "message_id" }
4022
+ };
4023
+ __decorateClass([
4024
+ (0, import_decorators.field)("message_id")
4025
+ ], Message.prototype, "messageId", 2);
4026
+ __decorateClass([
4027
+ (0, import_decorators.text)("conversation_id")
4028
+ ], Message.prototype, "conversationId", 2);
4029
+ __decorateClass([
4030
+ (0, import_decorators.text)("role")
4031
+ ], Message.prototype, "role", 2);
4032
+ __decorateClass([
4033
+ (0, import_decorators.text)("content")
4034
+ ], Message.prototype, "content", 2);
4035
+ __decorateClass([
4036
+ (0, import_decorators.text)("model")
4037
+ ], Message.prototype, "model", 2);
4038
+ __decorateClass([
4039
+ (0, import_decorators.text)("image_model")
4040
+ ], Message.prototype, "imageModel", 2);
4041
+ __decorateClass([
4042
+ (0, import_decorators.json)("files", (raw) => raw)
4043
+ ], Message.prototype, "files", 2);
4044
+ __decorateClass([
4045
+ (0, import_decorators.json)("file_ids", (raw) => raw)
4046
+ ], Message.prototype, "fileIds", 2);
4047
+ __decorateClass([
4048
+ (0, import_decorators.date)("created_at")
4049
+ ], Message.prototype, "createdAt", 2);
4050
+ __decorateClass([
4051
+ (0, import_decorators.date)("updated_at")
4052
+ ], Message.prototype, "updatedAt", 2);
4053
+ __decorateClass([
4054
+ (0, import_decorators.json)("vector", (raw) => raw)
4055
+ ], Message.prototype, "vector", 2);
4056
+ __decorateClass([
4057
+ (0, import_decorators.text)("embedding_model")
4058
+ ], Message.prototype, "embeddingModel", 2);
4059
+ __decorateClass([
4060
+ (0, import_decorators.json)("chunks", (raw) => raw)
4061
+ ], Message.prototype, "chunks", 2);
4062
+ __decorateClass([
4063
+ (0, import_decorators.json)("usage", (raw) => raw)
4064
+ ], Message.prototype, "usage", 2);
4065
+ __decorateClass([
4066
+ (0, import_decorators.json)("sources", (raw) => raw)
4067
+ ], Message.prototype, "sources", 2);
4068
+ __decorateClass([
4069
+ (0, import_decorators.field)("response_duration")
4070
+ ], Message.prototype, "responseDuration", 2);
4071
+ __decorateClass([
4072
+ (0, import_decorators.field)("was_stopped")
4073
+ ], Message.prototype, "wasStopped", 2);
4074
+ __decorateClass([
4075
+ (0, import_decorators.text)("error")
4076
+ ], Message.prototype, "error", 2);
4077
+ __decorateClass([
4078
+ (0, import_decorators.json)("thought_process", (raw) => raw)
4079
+ ], Message.prototype, "thoughtProcess", 2);
4080
+ __decorateClass([
4081
+ (0, import_decorators.text)("thinking")
4082
+ ], Message.prototype, "thinking", 2);
4083
+ __decorateClass([
4084
+ (0, import_decorators.text)("parent_message_id")
4085
+ ], Message.prototype, "parentMessageId", 2);
4086
+ __decorateClass([
4087
+ (0, import_decorators.text)("feedback")
4088
+ ], Message.prototype, "feedback", 2);
4089
+ __decorateClass([
4090
+ (0, import_decorators.json)("tool_call_events", (raw) => raw)
4091
+ ], Message.prototype, "toolCallEvents", 2);
4092
+ __decorateClass([
4093
+ (0, import_decorators.text)("origin")
4094
+ ], Message.prototype, "origin", 2);
4095
+ var Conversation = class extends import_watermelondb2.Model {
4096
+ };
4097
+ Conversation.table = "conversations";
4098
+ Conversation.associations = {
4099
+ history: { type: "has_many", foreignKey: "conversation_id" },
4100
+ projects: { type: "belongs_to", key: "project_id" }
4101
+ };
4102
+ __decorateClass([
4103
+ (0, import_decorators.text)("conversation_id")
4104
+ ], Conversation.prototype, "conversationId", 2);
4105
+ __decorateClass([
4106
+ (0, import_decorators.text)("title")
4107
+ ], Conversation.prototype, "title", 2);
4108
+ __decorateClass([
4109
+ (0, import_decorators.text)("project_id")
4110
+ ], Conversation.prototype, "projectId", 2);
4111
+ __decorateClass([
4112
+ (0, import_decorators.date)("created_at")
4113
+ ], Conversation.prototype, "createdAt", 2);
4114
+ __decorateClass([
4115
+ (0, import_decorators.date)("updated_at")
4116
+ ], Conversation.prototype, "updatedAt", 2);
4117
+ __decorateClass([
4118
+ (0, import_decorators.field)("is_deleted")
4119
+ ], Conversation.prototype, "isDeleted", 2);
4120
+ __decorateClass([
4121
+ (0, import_decorators.date)("pinned_at")
4122
+ ], Conversation.prototype, "pinnedAt", 2);
4123
+ var ConversationSummary = class extends import_watermelondb2.Model {
4124
+ };
4125
+ ConversationSummary.table = "conversation_summaries";
4126
+ ConversationSummary.associations = {
4127
+ conversations: { type: "belongs_to", key: "conversation_id" }
4128
+ };
4129
+ __decorateClass([
4130
+ (0, import_decorators.text)("conversation_id")
4131
+ ], ConversationSummary.prototype, "conversationId", 2);
4132
+ __decorateClass([
4133
+ (0, import_decorators.text)("summary")
4134
+ ], ConversationSummary.prototype, "summary", 2);
4135
+ __decorateClass([
4136
+ (0, import_decorators.text)("summarized_up_to")
4137
+ ], ConversationSummary.prototype, "summarizedUpTo", 2);
4138
+ __decorateClass([
4139
+ (0, import_decorators.field)("token_count")
4140
+ ], ConversationSummary.prototype, "tokenCount", 2);
4141
+ __decorateClass([
4142
+ (0, import_decorators.date)("created_at")
4143
+ ], ConversationSummary.prototype, "createdAt", 2);
4144
+ __decorateClass([
4145
+ (0, import_decorators.date)("updated_at")
4146
+ ], ConversationSummary.prototype, "updatedAt", 2);
4147
+
4148
+ // src/lib/db/chat/summaryRevision.ts
4149
+ var conversationRevisions = /* @__PURE__ */ new WeakMap();
4150
+ function getConversationRevision(database, conversationId) {
4151
+ return conversationRevisions.get(database)?.get(conversationId) ?? 0;
4152
+ }
4153
+ function advanceConversationRevision(database, conversationId) {
4154
+ let revisions = conversationRevisions.get(database);
4155
+ if (!revisions) {
4156
+ revisions = /* @__PURE__ */ new Map();
4157
+ conversationRevisions.set(database, revisions);
4158
+ }
4159
+ revisions.set(conversationId, getConversationRevision(database, conversationId) + 1);
4160
+ }
4161
+ function assertConversationRevision(database, conversationId, revision2) {
4162
+ if (getConversationRevision(database, conversationId) !== revision2) {
4163
+ throw new Error("The conversation changed during summarization. Retry the request.");
4164
+ }
4165
+ }
4166
+
4167
+ // src/lib/db/chat/toolCallEventIndex.ts
4168
+ var import_watermelondb3 = require("@nozbe/watermelondb");
4015
4169
  function parseEventIds(value) {
4016
4170
  const ids = /* @__PURE__ */ new Set();
4017
4171
  let events;
@@ -4031,7 +4185,7 @@ function parseEventIds(value) {
4031
4185
  async function fetchEventRows(collection, conversationId) {
4032
4186
  try {
4033
4187
  return await collection.query(
4034
- import_watermelondb2.Q.unsafeSqlQuery(
4188
+ import_watermelondb3.Q.unsafeSqlQuery(
4035
4189
  `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 ('', '[]')`,
4036
4190
  [conversationId]
4037
4191
  )
@@ -4041,10 +4195,10 @@ async function fetchEventRows(collection, conversationId) {
4041
4195
  throw error;
4042
4196
  }
4043
4197
  return await collection.query(
4044
- import_watermelondb2.Q.where("conversation_id", conversationId),
4045
- import_watermelondb2.Q.where("tool_call_events", import_watermelondb2.Q.notEq(null)),
4046
- import_watermelondb2.Q.where("tool_call_events", import_watermelondb2.Q.notIn(["", "[]"])),
4047
- import_watermelondb2.Q.unsafeLokiTransform(
4198
+ import_watermelondb3.Q.where("conversation_id", conversationId),
4199
+ import_watermelondb3.Q.where("tool_call_events", import_watermelondb3.Q.notEq(null)),
4200
+ import_watermelondb3.Q.where("tool_call_events", import_watermelondb3.Q.notIn(["", "[]"])),
4201
+ import_watermelondb3.Q.unsafeLokiTransform(
4048
4202
  (rows) => rows.map(({ id: id2, tool_call_events }) => ({ id: id2, tool_call_events }))
4049
4203
  )
4050
4204
  ).unsafeFetchRaw();
@@ -4514,7 +4668,7 @@ async function createConversationOp(ctx, opts, defaultTitle = "New Conversation"
4514
4668
  );
4515
4669
  }
4516
4670
  async function getConversationOp(ctx, id2) {
4517
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
4671
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
4518
4672
  return results.length > 0 ? await conversationToStored(
4519
4673
  results[0],
4520
4674
  ctx.walletAddress,
@@ -4523,7 +4677,7 @@ async function getConversationOp(ctx, id2) {
4523
4677
  ) : null;
4524
4678
  }
4525
4679
  async function getConversationsOp(ctx) {
4526
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("is_deleted", false), import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)).unsafeFetchRaw();
4680
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("is_deleted", false), import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)).unsafeFetchRaw();
4527
4681
  return Promise.all(
4528
4682
  results.map(
4529
4683
  (raw) => conversationRawToStored(raw, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
@@ -4544,33 +4698,33 @@ function conversationRawToLazyStored(raw) {
4544
4698
  };
4545
4699
  }
4546
4700
  async function getConversationsLazyOp(ctx) {
4547
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("is_deleted", false), import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)).unsafeFetchRaw();
4701
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("is_deleted", false), import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)).unsafeFetchRaw();
4548
4702
  return results.map(conversationRawToLazyStored);
4549
4703
  }
4550
4704
  async function getConversationsPageOp(ctx, options) {
4551
4705
  const limit = Math.floor(options?.limit ?? 200);
4552
4706
  if (!Number.isFinite(limit) || limit < 1) return [];
4553
4707
  const exclude = new Set(options?.boundaryExcludeUniqueIds ?? []);
4554
- const clauses = [import_watermelondb3.Q.where("is_deleted", false)];
4708
+ const clauses = [import_watermelondb4.Q.where("is_deleted", false)];
4555
4709
  if (options?.before !== void 0) {
4556
4710
  clauses.push(
4557
- 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))
4711
+ 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))
4558
4712
  );
4559
4713
  }
4560
- 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();
4714
+ 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();
4561
4715
  const results = exclude.size > 0 ? fetched.filter((raw) => !exclude.has(raw.id)) : fetched;
4562
4716
  return results.slice(0, limit).map(conversationRawToLazyStored);
4563
4717
  }
4564
4718
  async function getConversationsByProjectLazyOp(ctx, projectId) {
4565
4719
  const results = await ctx.conversationsCollection.query(
4566
- import_watermelondb3.Q.where("project_id", projectId === null ? "" : projectId),
4567
- import_watermelondb3.Q.where("is_deleted", false),
4568
- import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)
4720
+ import_watermelondb4.Q.where("project_id", projectId === null ? "" : projectId),
4721
+ import_watermelondb4.Q.where("is_deleted", false),
4722
+ import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)
4569
4723
  ).unsafeFetchRaw();
4570
4724
  return results.map(conversationRawToLazyStored);
4571
4725
  }
4572
4726
  async function updateConversationTitleOp(ctx, id2, title) {
4573
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
4727
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
4574
4728
  if (results.length > 0) {
4575
4729
  const encryptedOpts = ctx.walletAddress && ctx.signMessage ? await encryptConversationFields(
4576
4730
  { title },
@@ -4589,13 +4743,13 @@ async function updateConversationTitleOp(ctx, id2, title) {
4589
4743
  return false;
4590
4744
  }
4591
4745
  async function deleteConversationOp(ctx, id2) {
4592
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
4746
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
4593
4747
  if (results.length > 0) {
4594
4748
  await ctx.database.write(async () => {
4595
4749
  await results[0].update((conv) => {
4596
4750
  conv._setRaw("is_deleted", true);
4597
4751
  });
4598
- const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb3.Q.where("conversation_id", id2)).fetch() : [];
4752
+ const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb4.Q.where("conversation_id", id2)).fetch() : [];
4599
4753
  for (const job of jobs) await job.destroyPermanently();
4600
4754
  });
4601
4755
  return true;
@@ -4603,7 +4757,7 @@ async function deleteConversationOp(ctx, id2) {
4603
4757
  return false;
4604
4758
  }
4605
4759
  async function updateConversationProjectOp(ctx, id2, projectId) {
4606
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
4760
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
4607
4761
  if (results.length > 0) {
4608
4762
  await ctx.database.write(async () => {
4609
4763
  await results[0].update((conv) => {
@@ -4615,7 +4769,7 @@ async function updateConversationProjectOp(ctx, id2, projectId) {
4615
4769
  return false;
4616
4770
  }
4617
4771
  async function updateConversationPinnedOp(ctx, id2, pinned) {
4618
- const results = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", id2), import_watermelondb3.Q.where("is_deleted", false)).fetch();
4772
+ const results = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", id2), import_watermelondb4.Q.where("is_deleted", false)).fetch();
4619
4773
  if (results.length > 0) {
4620
4774
  await ctx.database.write(async () => {
4621
4775
  await results[0].update((conv) => {
@@ -4628,9 +4782,9 @@ async function updateConversationPinnedOp(ctx, id2, pinned) {
4628
4782
  }
4629
4783
  async function getConversationsByProjectOp(ctx, projectId) {
4630
4784
  const results = await ctx.conversationsCollection.query(
4631
- import_watermelondb3.Q.where("project_id", projectId === null ? "" : projectId),
4632
- import_watermelondb3.Q.where("is_deleted", false),
4633
- import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)
4785
+ import_watermelondb4.Q.where("project_id", projectId === null ? "" : projectId),
4786
+ import_watermelondb4.Q.where("is_deleted", false),
4787
+ import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)
4634
4788
  ).unsafeFetchRaw();
4635
4789
  return Promise.all(
4636
4790
  results.map(
@@ -4639,7 +4793,7 @@ async function getConversationsByProjectOp(ctx, projectId) {
4639
4793
  );
4640
4794
  }
4641
4795
  async function getMessagesOp(ctx, convId, opts) {
4642
- const fetched = await ctx.messagesCollection.query(import_watermelondb3.Q.where("conversation_id", convId), import_watermelondb3.Q.sortBy("message_id", import_watermelondb3.Q.asc)).unsafeFetchRaw();
4796
+ const fetched = await ctx.messagesCollection.query(import_watermelondb4.Q.where("conversation_id", convId), import_watermelondb4.Q.sortBy("message_id", import_watermelondb4.Q.asc)).unsafeFetchRaw();
4643
4797
  const results = opts?.rawFilter ? fetched.filter(opts.rawFilter) : fetched;
4644
4798
  return Promise.all(
4645
4799
  results.map(
@@ -4648,19 +4802,19 @@ async function getMessagesOp(ctx, convId, opts) {
4648
4802
  );
4649
4803
  }
4650
4804
  async function getMessageCountOp(ctx, convId) {
4651
- return await ctx.messagesCollection.query(import_watermelondb3.Q.where("conversation_id", convId)).fetchCount();
4805
+ return await ctx.messagesCollection.query(import_watermelondb4.Q.where("conversation_id", convId)).fetchCount();
4652
4806
  }
4653
4807
  async function getMessagesPageOp(ctx, convId, opts) {
4654
4808
  const limit = Math.floor(opts.limit);
4655
4809
  if (!Number.isFinite(limit) || limit < 1) return [];
4656
4810
  const exclude = new Set(opts.boundaryExcludeUniqueIds ?? []);
4657
- const clauses = [import_watermelondb3.Q.where("conversation_id", convId)];
4811
+ const clauses = [import_watermelondb4.Q.where("conversation_id", convId)];
4658
4812
  if (opts.beforeMessageId !== void 0) {
4659
4813
  clauses.push(
4660
- 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))
4814
+ 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))
4661
4815
  );
4662
4816
  }
4663
- 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();
4817
+ 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();
4664
4818
  const results = (exclude.size > 0 ? fetched.filter((raw) => !exclude.has(raw.id)) : fetched).slice(0, limit);
4665
4819
  results.reverse();
4666
4820
  return Promise.all(
@@ -4672,7 +4826,7 @@ async function getMessagesPageOp(ctx, convId, opts) {
4672
4826
  );
4673
4827
  }
4674
4828
  async function getMessageSkeletonsOp(ctx, convId) {
4675
- const results = await ctx.messagesCollection.query(import_watermelondb3.Q.where("conversation_id", convId), import_watermelondb3.Q.sortBy("message_id", import_watermelondb3.Q.asc)).unsafeFetchRaw();
4829
+ const results = await ctx.messagesCollection.query(import_watermelondb4.Q.where("conversation_id", convId), import_watermelondb4.Q.sortBy("message_id", import_watermelondb4.Q.asc)).unsafeFetchRaw();
4676
4830
  const roleById = /* @__PURE__ */ new Map();
4677
4831
  for (const raw of results) {
4678
4832
  roleById.set(raw.id, raw.role);
@@ -4719,10 +4873,22 @@ async function getMessageSkeletonsOp(ctx, convId) {
4719
4873
  async function getToolCallEventIdsOp(ctx, convId) {
4720
4874
  return getToolCallEventIds(ctx.messagesCollection, convId);
4721
4875
  }
4876
+ async function invalidateConversationSummary(ctx, conversationId, changedMessageId) {
4877
+ if (!ctx.database.schema?.tables[ConversationSummary.table]) return;
4878
+ const summaries = await ctx.database.get(ConversationSummary.table).query(import_watermelondb4.Q.where("conversation_id", conversationId)).fetch();
4879
+ for (const summary of summaries) {
4880
+ if (changedMessageId !== void 0) {
4881
+ const [boundary] = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", summary.summarizedUpTo), import_watermelondb4.Q.where("conversation_id", conversationId)).fetch();
4882
+ if (boundary && changedMessageId > boundary.messageId) continue;
4883
+ }
4884
+ await summary.destroyPermanently();
4885
+ }
4886
+ }
4722
4887
  async function clearMessagesOp(ctx, convId) {
4723
4888
  await ctx.database.write(async () => {
4724
- const messages = await ctx.messagesCollection.query(import_watermelondb3.Q.where("conversation_id", convId)).fetch();
4725
- const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb3.Q.where("conversation_id", convId)).fetch() : [];
4889
+ await invalidateConversationSummary(ctx, convId);
4890
+ const messages = await ctx.messagesCollection.query(import_watermelondb4.Q.where("conversation_id", convId)).fetch();
4891
+ const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb4.Q.where("conversation_id", convId)).fetch() : [];
4726
4892
  for (const job of jobs) {
4727
4893
  await job.update((row) => {
4728
4894
  row._setRaw("message_ids", "[]");
@@ -4732,11 +4898,12 @@ async function clearMessagesOp(ctx, convId) {
4732
4898
  }
4733
4899
  for (const message of messages) {
4734
4900
  await message.update((msg) => {
4735
- msg._setRaw("file_ids", null);
4901
+ if (ctx.messagesCollection.schema.columns.file_ids) msg._setRaw("file_ids", null);
4736
4902
  msg._setRaw("files", null);
4737
4903
  });
4738
4904
  await message.destroyPermanently();
4739
4905
  }
4906
+ advanceConversationRevision(ctx.database, convId);
4740
4907
  });
4741
4908
  }
4742
4909
  async function deleteMessageOp(ctx, uniqueId) {
@@ -4747,7 +4914,8 @@ async function deleteMessageOp(ctx, uniqueId) {
4747
4914
  return null;
4748
4915
  }
4749
4916
  await ctx.database.write(async () => {
4750
- const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb3.Q.where("conversation_id", message.conversationId)).fetch() : [];
4917
+ await invalidateConversationSummary(ctx, message.conversationId, message.messageId);
4918
+ const jobs = ctx.database.schema?.tables[ExtractionJob.table] ? await ctx.database.get(ExtractionJob.table).query(import_watermelondb4.Q.where("conversation_id", message.conversationId)).fetch() : [];
4751
4919
  for (const job of jobs) {
4752
4920
  const ids = JSON.parse(String(job._getRaw("message_ids")));
4753
4921
  await job.update((row) => {
@@ -4756,10 +4924,11 @@ async function deleteMessageOp(ctx, uniqueId) {
4756
4924
  });
4757
4925
  }
4758
4926
  await message.update((msg) => {
4759
- msg._setRaw("file_ids", null);
4927
+ if (ctx.messagesCollection.schema.columns.file_ids) msg._setRaw("file_ids", null);
4760
4928
  msg._setRaw("files", null);
4761
4929
  });
4762
4930
  await message.destroyPermanently();
4931
+ advanceConversationRevision(ctx.database, message.conversationId);
4763
4932
  });
4764
4933
  return uniqueId;
4765
4934
  }
@@ -4820,9 +4989,9 @@ async function createMessageOp(ctx, opts) {
4820
4989
  }
4821
4990
  }
4822
4991
  const newest = await ctx.messagesCollection.query(
4823
- import_watermelondb3.Q.where("conversation_id", opts.conversationId),
4824
- import_watermelondb3.Q.sortBy("message_id", import_watermelondb3.Q.desc),
4825
- import_watermelondb3.Q.take(1)
4992
+ import_watermelondb4.Q.where("conversation_id", opts.conversationId),
4993
+ import_watermelondb4.Q.sortBy("message_id", import_watermelondb4.Q.desc),
4994
+ import_watermelondb4.Q.take(1)
4826
4995
  ).fetch();
4827
4996
  const messageId = (newest[0]?.messageId ?? 0) + 1;
4828
4997
  const encryptedOpts = await encryptMessageOptsIfNeeded(ctx, opts);
@@ -4918,13 +5087,13 @@ async function decryptMessageEmbeddingFields(raw, walletAddress) {
4918
5087
  async function sealLegacyMessageEmbeddingsOp(ctx) {
4919
5088
  if (!ctx.walletAddress) return 0;
4920
5089
  const candidateIds = await ctx.messagesCollection.query(
4921
- import_watermelondb3.Q.where("content", import_watermelondb3.Q.like("enc:%")),
4922
- import_watermelondb3.Q.or(
5090
+ import_watermelondb4.Q.where("content", import_watermelondb4.Q.like("enc:%")),
5091
+ import_watermelondb4.Q.or(
4923
5092
  ...["vector", "chunks"].map(
4924
- (column) => import_watermelondb3.Q.and(
4925
- import_watermelondb3.Q.where(column, import_watermelondb3.Q.notEq(null)),
4926
- import_watermelondb3.Q.where(column, import_watermelondb3.Q.notEq("")),
4927
- import_watermelondb3.Q.where(column, import_watermelondb3.Q.notLike("enc:%"))
5093
+ (column) => import_watermelondb4.Q.and(
5094
+ import_watermelondb4.Q.where(column, import_watermelondb4.Q.notEq(null)),
5095
+ import_watermelondb4.Q.where(column, import_watermelondb4.Q.notEq("")),
5096
+ import_watermelondb4.Q.where(column, import_watermelondb4.Q.notLike("enc:%"))
4928
5097
  )
4929
5098
  )
4930
5099
  )
@@ -4934,7 +5103,7 @@ async function sealLegacyMessageEmbeddingsOp(ctx) {
4934
5103
  for (let start = 0; start < candidateIds.length; start += 50) {
4935
5104
  const pageIds = candidateIds.slice(start, start + 50);
4936
5105
  await ctx.database.write(async () => {
4937
- const pageMessages = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(pageIds))).fetch();
5106
+ const pageMessages = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(pageIds))).fetch();
4938
5107
  for (const message of pageMessages) {
4939
5108
  if (!isEncrypted(message.content)) continue;
4940
5109
  const content = await decryptFieldDetailed(message.content, ctx.walletAddress);
@@ -5015,15 +5184,15 @@ function chunksWithoutText(raw) {
5015
5184
  });
5016
5185
  }
5017
5186
  async function stripLegacyChunkTextOp(ctx) {
5018
- const candidateIds = await ctx.messagesCollection.query(import_watermelondb3.Q.where("chunks", import_watermelondb3.Q.like(`%${import_watermelondb3.Q.sanitizeLikeString('"text":')}%`))).fetchIds();
5187
+ const candidateIds = await ctx.messagesCollection.query(import_watermelondb4.Q.where("chunks", import_watermelondb4.Q.like(`%${import_watermelondb4.Q.sanitizeLikeString('"text":')}%`))).fetchIds();
5019
5188
  let stripped = 0;
5020
5189
  for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
5021
5190
  const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
5022
- const rows = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(pageIds))).unsafeFetchRaw();
5191
+ const rows = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(pageIds))).unsafeFetchRaw();
5023
5192
  const changedIds = rows.filter((row) => chunksWithoutText(row.chunks) !== null).map((row) => String(row.id));
5024
5193
  if (changedIds.length === 0) continue;
5025
5194
  await ctx.database.write(async () => {
5026
- const messages = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(changedIds))).fetch();
5195
+ const messages = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(changedIds))).fetch();
5027
5196
  const updates = messages.flatMap((message) => {
5028
5197
  const raw = message._raw;
5029
5198
  const chunks3 = chunksWithoutText(raw.chunks);
@@ -5070,13 +5239,13 @@ async function encryptToolCallEventsOp(ctx) {
5070
5239
  return 0;
5071
5240
  }
5072
5241
  const candidateIds = await ctx.messagesCollection.query(
5073
- import_watermelondb3.Q.where("tool_call_events", import_watermelondb3.Q.notEq(null)),
5074
- import_watermelondb3.Q.where("tool_call_events", import_watermelondb3.Q.notIn(["", "[]"]))
5242
+ import_watermelondb4.Q.where("tool_call_events", import_watermelondb4.Q.notEq(null)),
5243
+ import_watermelondb4.Q.where("tool_call_events", import_watermelondb4.Q.notIn(["", "[]"]))
5075
5244
  ).fetchIds();
5076
5245
  let encrypted = 0;
5077
5246
  for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
5078
5247
  const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
5079
- const rows = await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(pageIds))).unsafeFetchRaw();
5248
+ const rows = await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(pageIds))).unsafeFetchRaw();
5080
5249
  const repairs = /* @__PURE__ */ new Map();
5081
5250
  for (const row of rows) {
5082
5251
  const column = await encryptedToolCallEventsColumn(
@@ -5089,12 +5258,12 @@ async function encryptToolCallEventsOp(ctx) {
5089
5258
  }
5090
5259
  if (repairs.size === 0) continue;
5091
5260
  await ctx.database.write(async () => {
5092
- const messages = (await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf([...repairs.keys()]))).fetch()).filter(
5261
+ const messages = (await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf([...repairs.keys()]))).fetch()).filter(
5093
5262
  (message) => message._raw.tool_call_events === repairs.get(message.id)?.raw
5094
5263
  );
5095
5264
  if (messages.length === 0) return;
5096
5265
  const conversationIds = [...new Set(messages.map((message) => message.conversationId))];
5097
- const conversations = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("conversation_id", import_watermelondb3.Q.oneOf(conversationIds))).fetch();
5266
+ const conversations = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("conversation_id", import_watermelondb4.Q.oneOf(conversationIds))).fetch();
5098
5267
  await ctx.database.batch(
5099
5268
  ...messages.map(
5100
5269
  (message) => message.prepareUpdate((msg) => {
@@ -5121,7 +5290,7 @@ async function savedKeyOpensExistingData(ctx, address, signMessage, embeddedWall
5121
5290
  return refreshEncryptionKeyIfMatches(address, v2Probe, signMessage, embeddedWalletSigner);
5122
5291
  }
5123
5292
  async function findEncryptedContent(ctx, pattern) {
5124
- const [row] = await ctx.messagesCollection.query(import_watermelondb3.Q.where("content", import_watermelondb3.Q.like(pattern)), import_watermelondb3.Q.take(1)).unsafeFetchRaw();
5293
+ const [row] = await ctx.messagesCollection.query(import_watermelondb4.Q.where("content", import_watermelondb4.Q.like(pattern)), import_watermelondb4.Q.take(1)).unsafeFetchRaw();
5125
5294
  return row ? String(row.content) : null;
5126
5295
  }
5127
5296
  async function updateMessageErrorOp(ctx, uniqueId, error) {
@@ -5169,6 +5338,14 @@ async function _updateMessageOp(ctx, uniqueId, opts) {
5169
5338
  ctx.embeddedWalletSigner
5170
5339
  ) : opts;
5171
5340
  await ctx.database.write(async () => {
5341
+ let contentChanged = false;
5342
+ if (opts.content !== void 0) {
5343
+ const originalContent = ctx.walletAddress ? await decryptField(message.content, ctx.walletAddress) : message.content;
5344
+ contentChanged = opts.content !== originalContent;
5345
+ if (contentChanged) {
5346
+ await invalidateConversationSummary(ctx, message.conversationId, message.messageId);
5347
+ }
5348
+ }
5172
5349
  await message.update((msg) => {
5173
5350
  if (encryptedOpts.content !== void 0)
5174
5351
  msg._setRaw("content", encryptedOpts.content);
@@ -5213,6 +5390,7 @@ async function _updateMessageOp(ctx, uniqueId, opts) {
5213
5390
  msg._setRaw("tool_call_events", tceValue);
5214
5391
  }
5215
5392
  });
5393
+ if (contentChanged) advanceConversationRevision(ctx.database, message.conversationId);
5216
5394
  });
5217
5395
  return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
5218
5396
  }
@@ -5240,11 +5418,11 @@ async function readRawJsonField(raw, column, walletAddress) {
5240
5418
  }
5241
5419
  async function searchMessagesOp(ctx, queryVector, options) {
5242
5420
  const { limit = 10, minSimilarity = 0.5, conversationId } = options || {};
5243
- const activeConversations = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("is_deleted", false)).fetch();
5421
+ const activeConversations = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("is_deleted", false)).fetch();
5244
5422
  const activeConversationIds = new Set(
5245
5423
  activeConversations.map((c) => String(c._getRaw("conversation_id")))
5246
5424
  );
5247
- const queryConditions = conversationId ? [import_watermelondb3.Q.where("conversation_id", conversationId)] : [];
5425
+ const queryConditions = conversationId ? [import_watermelondb4.Q.where("conversation_id", conversationId)] : [];
5248
5426
  const messages = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
5249
5427
  const candidates = [];
5250
5428
  for (const message of messages) {
@@ -5283,7 +5461,7 @@ function toChunkCandidateKey(raw) {
5283
5461
  }
5284
5462
  async function fetchRowsByIds(ctx, ids) {
5285
5463
  if (ids.length === 0) return [];
5286
- return await ctx.messagesCollection.query(import_watermelondb3.Q.where("id", import_watermelondb3.Q.oneOf(ids))).unsafeFetchRaw();
5464
+ return await ctx.messagesCollection.query(import_watermelondb4.Q.where("id", import_watermelondb4.Q.oneOf(ids))).unsafeFetchRaw();
5287
5465
  }
5288
5466
  async function projectedChunkRowSource(ctx, filter) {
5289
5467
  const clauses = [
@@ -5301,7 +5479,7 @@ async function projectedChunkRowSource(ctx, filter) {
5301
5479
  args.push(filter.excludeConversationId);
5302
5480
  }
5303
5481
  const keyRows = await ctx.messagesCollection.query(
5304
- import_watermelondb3.Q.unsafeSqlQuery(
5482
+ import_watermelondb4.Q.unsafeSqlQuery(
5305
5483
  `select "id", "conversation_id", "updated_at", "embedding_model" from "history" where ${clauses.join(" and ")}`,
5306
5484
  args
5307
5485
  )
@@ -5311,7 +5489,7 @@ async function projectedChunkRowSource(ctx, filter) {
5311
5489
  loadVectorRows: async (ids) => {
5312
5490
  if (ids.length === 0) return [];
5313
5491
  return await ctx.messagesCollection.query(
5314
- import_watermelondb3.Q.unsafeSqlQuery(
5492
+ import_watermelondb4.Q.unsafeSqlQuery(
5315
5493
  `select "id", "updated_at", "chunks", "vector" from "history" where "_status" is not 'deleted' and "id" in (${ids.map(() => "?").join(",")})`,
5316
5494
  ids
5317
5495
  )
@@ -5321,11 +5499,11 @@ async function projectedChunkRowSource(ctx, filter) {
5321
5499
  };
5322
5500
  }
5323
5501
  async function fullScanChunkRowSource(ctx, filter) {
5324
- const activeConversations = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("is_deleted", false)).fetch();
5502
+ const activeConversations = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("is_deleted", false)).fetch();
5325
5503
  const activeConversationIds = new Set(
5326
5504
  activeConversations.map((c) => String(c._getRaw("conversation_id")))
5327
5505
  );
5328
- const queryConditions = filter.conversationId !== void 0 ? [import_watermelondb3.Q.where("conversation_id", filter.conversationId)] : [];
5506
+ const queryConditions = filter.conversationId !== void 0 ? [import_watermelondb4.Q.where("conversation_id", filter.conversationId)] : [];
5329
5507
  const rows = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
5330
5508
  const rowsById = /* @__PURE__ */ new Map();
5331
5509
  for (const row of rows) {
@@ -5532,12 +5710,12 @@ async function searchChunksOp(ctx, queryVector, options) {
5532
5710
  }
5533
5711
  async function getAllFilesOp(ctx, options) {
5534
5712
  const { conversationId, limit } = options || {};
5535
- const activeConversations = await ctx.conversationsCollection.query(import_watermelondb3.Q.where("is_deleted", false)).fetch();
5713
+ const activeConversations = await ctx.conversationsCollection.query(import_watermelondb4.Q.where("is_deleted", false)).fetch();
5536
5714
  const activeConversationIds = new Set(
5537
5715
  activeConversations.map((c) => String(c._getRaw("conversation_id")))
5538
5716
  );
5539
- const queryConditions = conversationId ? [import_watermelondb3.Q.where("conversation_id", conversationId)] : [];
5540
- const messages = await ctx.messagesCollection.query(...queryConditions, import_watermelondb3.Q.sortBy("created_at", import_watermelondb3.Q.desc)).fetch();
5717
+ const queryConditions = conversationId ? [import_watermelondb4.Q.where("conversation_id", conversationId)] : [];
5718
+ const messages = await ctx.messagesCollection.query(...queryConditions, import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)).fetch();
5541
5719
  const filesWithContext = [];
5542
5720
  for (const message of messages) {
5543
5721
  const msgConvId = String(message._getRaw("conversation_id"));
@@ -7257,22 +7435,22 @@ function toReceipt(action, argumentsJson, output) {
7257
7435
  const result = parseObject(output);
7258
7436
  return {
7259
7437
  kind: action.kind,
7260
- venueName: text(args.venue_name) ?? "",
7261
- day: text(args.day) ?? "",
7262
- time: text(args.time) ?? "",
7438
+ venueName: text2(args.venue_name) ?? "",
7439
+ day: text2(args.day) ?? "",
7440
+ time: text2(args.time) ?? "",
7263
7441
  partySize: count(args.party_size),
7264
- reservationId: text(result.reservation_id) ?? text(args.reservation_id),
7265
- resyUrl: text(result.reservations_url),
7266
- feeSummary: text(result.fee_summary),
7442
+ reservationId: text2(result.reservation_id) ?? text2(args.reservation_id),
7443
+ resyUrl: text2(result.reservations_url),
7444
+ feeSummary: text2(result.fee_summary),
7267
7445
  ...outcome(action, output, result)
7268
7446
  };
7269
7447
  }
7270
7448
  function outcome(action, output, result) {
7271
7449
  if (action.alreadyDone.test(output)) return { status: "already_done" };
7272
- const reason = text(result.error);
7450
+ const reason = text2(result.error);
7273
7451
  if (action.kind === "booking") {
7274
7452
  if (BOOKING_OUTCOME_UNKNOWN.test(output)) return { status: "unknown" };
7275
- const held = result.success === true || text(result.reservation_id) !== void 0;
7453
+ const held = result.success === true || text2(result.reservation_id) !== void 0;
7276
7454
  return held ? { status: "made" } : { status: "not_made", reason };
7277
7455
  }
7278
7456
  if (result.error_code === CANCEL_OUTCOME_UNKNOWN) return { status: "unknown", reason };
@@ -7287,7 +7465,7 @@ function parseObject(json5) {
7287
7465
  return {};
7288
7466
  }
7289
7467
  }
7290
- function text(value) {
7468
+ function text2(value) {
7291
7469
  if (typeof value === "number") return String(value);
7292
7470
  return typeof value === "string" && value ? value : void 0;
7293
7471
  }
@@ -12755,7 +12933,7 @@ function hasControl(value) {
12755
12933
  function integer(value, minimum = 0) {
12756
12934
  return Number.isSafeInteger(value) && value >= minimum;
12757
12935
  }
12758
- function json(value, ancestors = /* @__PURE__ */ new Set()) {
12936
+ function json2(value, ancestors = /* @__PURE__ */ new Set()) {
12759
12937
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
12760
12938
  if (typeof value === "number") return Number.isFinite(value);
12761
12939
  if (typeof value !== "object" || ancestors.has(value)) return false;
@@ -12763,12 +12941,12 @@ function json(value, ancestors = /* @__PURE__ */ new Set()) {
12763
12941
  if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
12764
12942
  return false;
12765
12943
  ancestors.add(value);
12766
- const valid = Object.values(value).every((v) => json(v, ancestors));
12944
+ const valid = Object.values(value).every((v) => json2(v, ancestors));
12767
12945
  ancestors.delete(value);
12768
12946
  return valid;
12769
12947
  }
12770
12948
  function validRecord(value) {
12771
- 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(
12949
+ 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(
12772
12950
  (key) => ![...metadata, "data"].includes(key)
12773
12951
  ))
12774
12952
  return false;
@@ -12797,14 +12975,14 @@ function vectorFields(write) {
12797
12975
  ...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
12798
12976
  };
12799
12977
  }
12800
- function text2(value) {
12978
+ function text3(value) {
12801
12979
  return typeof value === "string";
12802
12980
  }
12803
12981
  function timestamp(value) {
12804
12982
  return typeof value === "string" && Number.isFinite(Date.parse(value));
12805
12983
  }
12806
12984
  function presigned(value) {
12807
- 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))
12985
+ 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))
12808
12986
  invalid();
12809
12987
  return {
12810
12988
  url: value.url,
@@ -12814,7 +12992,7 @@ function presigned(value) {
12814
12992
  };
12815
12993
  }
12816
12994
  function attachment(value) {
12817
- 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))
12995
+ 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))
12818
12996
  invalid();
12819
12997
  return {
12820
12998
  id: value.attachment_id,
@@ -12827,7 +13005,7 @@ function attachment(value) {
12827
13005
  };
12828
13006
  }
12829
13007
  function ref(value) {
12830
- if (!object(value) || !text2(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
13008
+ if (!object(value) || !text3(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
12831
13009
  return { kind: value.kind, id: value.id };
12832
13010
  }
12833
13011
  function sameMetadata(a, b) {
@@ -13050,7 +13228,7 @@ async function createRemoteChatStore(options) {
13050
13228
  },
13051
13229
  async account(signal) {
13052
13230
  const value = await request("/account", {}, signal);
13053
- 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))
13231
+ 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))
13054
13232
  invalid();
13055
13233
  if (value.key_id && value.key_id !== keyId)
13056
13234
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -13124,12 +13302,12 @@ async function createRemoteChatStore(options) {
13124
13302
  },
13125
13303
  async changes(cursor, options2) {
13126
13304
  const limit = options2?.limit ?? 100;
13127
- if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text2(cursor) || cursor.length > 2048))
13305
+ if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text3(cursor) || cursor.length > 2048))
13128
13306
  invalid();
13129
13307
  const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
13130
13308
  if (cursor) params.set("cursor", cursor);
13131
13309
  const value = await request(`/changes?${params}`, {}, options2?.signal);
13132
- 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))
13310
+ 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))
13133
13311
  invalid();
13134
13312
  const items = [];
13135
13313
  for (const item of value.items) items.push(await decode(item));
@@ -13257,31 +13435,31 @@ var emptyMessage = {
13257
13435
  };
13258
13436
 
13259
13437
  // src/lib/db/appFiles/models.ts
13260
- var import_watermelondb4 = require("@nozbe/watermelondb");
13261
- var import_decorators = require("@nozbe/watermelondb/decorators");
13262
- var AppFile = class extends import_watermelondb4.Model {
13438
+ var import_watermelondb5 = require("@nozbe/watermelondb");
13439
+ var import_decorators2 = require("@nozbe/watermelondb/decorators");
13440
+ var AppFile = class extends import_watermelondb5.Model {
13263
13441
  };
13264
13442
  AppFile.table = "app_files";
13265
13443
  AppFile.associations = {};
13266
13444
  __decorateClass([
13267
- (0, import_decorators.text)("conversation_id")
13445
+ (0, import_decorators2.text)("conversation_id")
13268
13446
  ], AppFile.prototype, "conversationId", 2);
13269
13447
  __decorateClass([
13270
- (0, import_decorators.text)("path")
13448
+ (0, import_decorators2.text)("path")
13271
13449
  ], AppFile.prototype, "path", 2);
13272
13450
  __decorateClass([
13273
- (0, import_decorators.text)("content")
13451
+ (0, import_decorators2.text)("content")
13274
13452
  ], AppFile.prototype, "content", 2);
13275
13453
  __decorateClass([
13276
- import_decorators.readonly,
13277
- (0, import_decorators.date)("created_at")
13454
+ import_decorators2.readonly,
13455
+ (0, import_decorators2.date)("created_at")
13278
13456
  ], AppFile.prototype, "createdAt", 2);
13279
13457
  __decorateClass([
13280
- (0, import_decorators.date)("updated_at")
13458
+ (0, import_decorators2.date)("updated_at")
13281
13459
  ], AppFile.prototype, "updatedAt", 2);
13282
13460
 
13283
13461
  // src/lib/db/appFiles/operations.ts
13284
- var import_watermelondb5 = require("@nozbe/watermelondb");
13462
+ var import_watermelondb6 = require("@nozbe/watermelondb");
13285
13463
 
13286
13464
  // src/utils/paths.ts
13287
13465
  function normalizePath(p) {
@@ -13307,7 +13485,7 @@ async function putAppFileOp(ctx, conversationId, path, content) {
13307
13485
  const normalized = normalizePath(path);
13308
13486
  const now = Date.now();
13309
13487
  const result = await ctx.database.write(async () => {
13310
- const existing = await ctx.appFilesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.where("path", normalized)).fetch();
13488
+ const existing = await ctx.appFilesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId), import_watermelondb6.Q.where("path", normalized)).fetch();
13311
13489
  if (existing.length > 0) {
13312
13490
  await existing[0].update((f) => {
13313
13491
  f._setRaw("content", content);
@@ -13327,11 +13505,11 @@ async function putAppFileOp(ctx, conversationId, path, content) {
13327
13505
  }
13328
13506
  async function getAppFileOp(ctx, conversationId, path) {
13329
13507
  const normalized = normalizePath(path);
13330
- const results = await ctx.appFilesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.where("path", normalized)).fetch();
13508
+ const results = await ctx.appFilesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId), import_watermelondb6.Q.where("path", normalized)).fetch();
13331
13509
  return results.length > 0 ? appFileToStored(results[0]) : null;
13332
13510
  }
13333
13511
  async function getAppFilesOp(ctx, conversationId) {
13334
- const results = await ctx.appFilesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
13512
+ const results = await ctx.appFilesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
13335
13513
  return results.map(appFileToStored);
13336
13514
  }
13337
13515
  async function getAppFileMapOp(ctx, conversationId) {
@@ -13342,7 +13520,7 @@ async function getAppFileMapOp(ctx, conversationId) {
13342
13520
  }
13343
13521
  async function deleteAppFileOp(ctx, conversationId, path) {
13344
13522
  const normalized = normalizePath(path);
13345
- const results = await ctx.appFilesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId), import_watermelondb5.Q.where("path", normalized)).fetch();
13523
+ const results = await ctx.appFilesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId), import_watermelondb6.Q.where("path", normalized)).fetch();
13346
13524
  if (results.length === 0) return false;
13347
13525
  await ctx.database.write(async () => {
13348
13526
  await results[0].destroyPermanently();
@@ -13350,7 +13528,7 @@ async function deleteAppFileOp(ctx, conversationId, path) {
13350
13528
  return true;
13351
13529
  }
13352
13530
  async function deleteAllAppFilesOp(ctx, conversationId) {
13353
- const results = await ctx.appFilesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
13531
+ const results = await ctx.appFilesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
13354
13532
  if (results.length === 0) return;
13355
13533
  await ctx.database.write(async () => {
13356
13534
  const batch = results.map((file) => file.prepareDestroyPermanently());
@@ -13422,141 +13600,6 @@ async function decryptConversationTitle(encryptedTitle, address) {
13422
13600
  }
13423
13601
  }
13424
13602
 
13425
- // src/lib/db/chat/models.ts
13426
- var import_watermelondb6 = require("@nozbe/watermelondb");
13427
- var import_decorators2 = require("@nozbe/watermelondb/decorators");
13428
- var Message = class extends import_watermelondb6.Model {
13429
- };
13430
- Message.table = "history";
13431
- Message.associations = {
13432
- conversations: { type: "belongs_to", key: "conversation_id" },
13433
- media: { type: "has_many", foreignKey: "message_id" }
13434
- };
13435
- __decorateClass([
13436
- (0, import_decorators2.field)("message_id")
13437
- ], Message.prototype, "messageId", 2);
13438
- __decorateClass([
13439
- (0, import_decorators2.text)("conversation_id")
13440
- ], Message.prototype, "conversationId", 2);
13441
- __decorateClass([
13442
- (0, import_decorators2.text)("role")
13443
- ], Message.prototype, "role", 2);
13444
- __decorateClass([
13445
- (0, import_decorators2.text)("content")
13446
- ], Message.prototype, "content", 2);
13447
- __decorateClass([
13448
- (0, import_decorators2.text)("model")
13449
- ], Message.prototype, "model", 2);
13450
- __decorateClass([
13451
- (0, import_decorators2.text)("image_model")
13452
- ], Message.prototype, "imageModel", 2);
13453
- __decorateClass([
13454
- (0, import_decorators2.json)("files", (raw) => raw)
13455
- ], Message.prototype, "files", 2);
13456
- __decorateClass([
13457
- (0, import_decorators2.json)("file_ids", (raw) => raw)
13458
- ], Message.prototype, "fileIds", 2);
13459
- __decorateClass([
13460
- (0, import_decorators2.date)("created_at")
13461
- ], Message.prototype, "createdAt", 2);
13462
- __decorateClass([
13463
- (0, import_decorators2.date)("updated_at")
13464
- ], Message.prototype, "updatedAt", 2);
13465
- __decorateClass([
13466
- (0, import_decorators2.json)("vector", (raw) => raw)
13467
- ], Message.prototype, "vector", 2);
13468
- __decorateClass([
13469
- (0, import_decorators2.text)("embedding_model")
13470
- ], Message.prototype, "embeddingModel", 2);
13471
- __decorateClass([
13472
- (0, import_decorators2.json)("chunks", (raw) => raw)
13473
- ], Message.prototype, "chunks", 2);
13474
- __decorateClass([
13475
- (0, import_decorators2.json)("usage", (raw) => raw)
13476
- ], Message.prototype, "usage", 2);
13477
- __decorateClass([
13478
- (0, import_decorators2.json)("sources", (raw) => raw)
13479
- ], Message.prototype, "sources", 2);
13480
- __decorateClass([
13481
- (0, import_decorators2.field)("response_duration")
13482
- ], Message.prototype, "responseDuration", 2);
13483
- __decorateClass([
13484
- (0, import_decorators2.field)("was_stopped")
13485
- ], Message.prototype, "wasStopped", 2);
13486
- __decorateClass([
13487
- (0, import_decorators2.text)("error")
13488
- ], Message.prototype, "error", 2);
13489
- __decorateClass([
13490
- (0, import_decorators2.json)("thought_process", (raw) => raw)
13491
- ], Message.prototype, "thoughtProcess", 2);
13492
- __decorateClass([
13493
- (0, import_decorators2.text)("thinking")
13494
- ], Message.prototype, "thinking", 2);
13495
- __decorateClass([
13496
- (0, import_decorators2.text)("parent_message_id")
13497
- ], Message.prototype, "parentMessageId", 2);
13498
- __decorateClass([
13499
- (0, import_decorators2.text)("feedback")
13500
- ], Message.prototype, "feedback", 2);
13501
- __decorateClass([
13502
- (0, import_decorators2.json)("tool_call_events", (raw) => raw)
13503
- ], Message.prototype, "toolCallEvents", 2);
13504
- __decorateClass([
13505
- (0, import_decorators2.text)("origin")
13506
- ], Message.prototype, "origin", 2);
13507
- var Conversation = class extends import_watermelondb6.Model {
13508
- };
13509
- Conversation.table = "conversations";
13510
- Conversation.associations = {
13511
- history: { type: "has_many", foreignKey: "conversation_id" },
13512
- projects: { type: "belongs_to", key: "project_id" }
13513
- };
13514
- __decorateClass([
13515
- (0, import_decorators2.text)("conversation_id")
13516
- ], Conversation.prototype, "conversationId", 2);
13517
- __decorateClass([
13518
- (0, import_decorators2.text)("title")
13519
- ], Conversation.prototype, "title", 2);
13520
- __decorateClass([
13521
- (0, import_decorators2.text)("project_id")
13522
- ], Conversation.prototype, "projectId", 2);
13523
- __decorateClass([
13524
- (0, import_decorators2.date)("created_at")
13525
- ], Conversation.prototype, "createdAt", 2);
13526
- __decorateClass([
13527
- (0, import_decorators2.date)("updated_at")
13528
- ], Conversation.prototype, "updatedAt", 2);
13529
- __decorateClass([
13530
- (0, import_decorators2.field)("is_deleted")
13531
- ], Conversation.prototype, "isDeleted", 2);
13532
- __decorateClass([
13533
- (0, import_decorators2.date)("pinned_at")
13534
- ], Conversation.prototype, "pinnedAt", 2);
13535
- var ConversationSummary = class extends import_watermelondb6.Model {
13536
- };
13537
- ConversationSummary.table = "conversation_summaries";
13538
- ConversationSummary.associations = {
13539
- conversations: { type: "belongs_to", key: "conversation_id" }
13540
- };
13541
- __decorateClass([
13542
- (0, import_decorators2.text)("conversation_id")
13543
- ], ConversationSummary.prototype, "conversationId", 2);
13544
- __decorateClass([
13545
- (0, import_decorators2.text)("summary")
13546
- ], ConversationSummary.prototype, "summary", 2);
13547
- __decorateClass([
13548
- (0, import_decorators2.text)("summarized_up_to")
13549
- ], ConversationSummary.prototype, "summarizedUpTo", 2);
13550
- __decorateClass([
13551
- (0, import_decorators2.field)("token_count")
13552
- ], ConversationSummary.prototype, "tokenCount", 2);
13553
- __decorateClass([
13554
- (0, import_decorators2.date)("created_at")
13555
- ], ConversationSummary.prototype, "createdAt", 2);
13556
- __decorateClass([
13557
- (0, import_decorators2.date)("updated_at")
13558
- ], ConversationSummary.prototype, "updatedAt", 2);
13559
-
13560
13603
  // src/lib/db/chat/schema.ts
13561
13604
  var import_watermelondb7 = require("@nozbe/watermelondb");
13562
13605
  var import_migrations = require("@nozbe/watermelondb/Schema/migrations");
@@ -27443,10 +27486,7 @@ async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark,
27443
27486
  for (const facet of facets) {
27444
27487
  if (!previous.sections.some((s) => s.key === facet.key)) stale.add(facet.key);
27445
27488
  }
27446
- const citedIds = new Set(previous.sections.flatMap((s) => s.sourceMemoryIds));
27447
- let toAttribute = changed.filter(
27448
- (m) => !m.isDeleted && !m.supersededBy && !citedIds.has(m.uniqueId)
27449
- );
27489
+ let toAttribute = changed.filter((m) => !m.isDeleted && !m.supersededBy);
27450
27490
  if (reviewedMemoryIds !== void 0) {
27451
27491
  const allowed = new Set(reviewedMemoryIds);
27452
27492
  toAttribute = toAttribute.filter((m) => allowed.has(m.uniqueId));
@@ -34262,6 +34302,13 @@ var lastCompactionTime = /* @__PURE__ */ new Map();
34262
34302
  var COMPACTION_COOLDOWN_MS = 6e4;
34263
34303
  var MAX_SUMMARY_TOKEN_RATIO = 0.8;
34264
34304
  async function maybeSummarizeHistory(options) {
34305
+ const { database, conversationId } = options;
34306
+ const revision2 = getConversationRevision(database, conversationId);
34307
+ const result = await summarizeHistoryAtRevision(options, revision2);
34308
+ assertConversationRevision(database, conversationId, revision2);
34309
+ return result;
34310
+ }
34311
+ async function summarizeHistoryAtRevision(options, revision2) {
34265
34312
  const { database, conversationId, messages, summarizeHistory, summaryMinWindowMessages, token } = options;
34266
34313
  if (!summarizeHistory) {
34267
34314
  return { messagesToConvert: messages, summarySystemMessage: null };
@@ -34302,7 +34349,7 @@ async function maybeSummarizeHistory(options) {
34302
34349
  clearTimeout(staleGuardTimerId);
34303
34350
  }
34304
34351
  }
34305
- const promise = doSummarizeHistory(options);
34352
+ const promise = doSummarizeHistory(options, revision2);
34306
34353
  summarizationLocks.set(conversationId, promise);
34307
34354
  try {
34308
34355
  return await promise;
@@ -34316,7 +34363,7 @@ Summary to condense:
34316
34363
  {summary}
34317
34364
 
34318
34365
  Condensed summary:`;
34319
- async function doSummarizeHistory(options) {
34366
+ async function doSummarizeHistory(options, revision2) {
34320
34367
  const {
34321
34368
  database,
34322
34369
  conversationId,
@@ -34331,7 +34378,20 @@ async function doSummarizeHistory(options) {
34331
34378
  } = options;
34332
34379
  try {
34333
34380
  const summaryCtx = createSummaryContext(database);
34381
+ const persistSummary = (summary, summarizedUpTo, tokenCount) => database.write(async (writer) => {
34382
+ assertConversationRevision(database, conversationId, revision2);
34383
+ await writer.callWriter(
34384
+ () => upsertConversationSummaryOp(
34385
+ summaryCtx,
34386
+ conversationId,
34387
+ summary,
34388
+ summarizedUpTo,
34389
+ tokenCount
34390
+ )
34391
+ );
34392
+ });
34334
34393
  let cachedSummary = await getConversationSummaryOp(summaryCtx, conversationId);
34394
+ assertConversationRevision(database, conversationId, revision2);
34335
34395
  const lastCompacted = lastCompactionTime.get(conversationId) ?? 0;
34336
34396
  const compactionCooledDown = Date.now() - lastCompacted > COMPACTION_COOLDOWN_MS;
34337
34397
  if (cachedSummary && cachedSummary.tokenCount > summaryTokenThreshold * MAX_SUMMARY_TOKEN_RATIO && compactionCooledDown) {
@@ -34347,13 +34407,7 @@ async function doSummarizeHistory(options) {
34347
34407
  );
34348
34408
  const compactedSummary = redactor ? redactor.deAnonymize(rawCompacted) : rawCompacted;
34349
34409
  const compactedTokens = estimateTokens(compactedSummary);
34350
- await upsertConversationSummaryOp(
34351
- summaryCtx,
34352
- conversationId,
34353
- compactedSummary,
34354
- cachedSummary.summarizedUpTo,
34355
- compactedTokens
34356
- );
34410
+ await persistSummary(compactedSummary, cachedSummary.summarizedUpTo, compactedTokens);
34357
34411
  cachedSummary = {
34358
34412
  ...cachedSummary,
34359
34413
  summary: compactedSummary,
@@ -34361,6 +34415,7 @@ async function doSummarizeHistory(options) {
34361
34415
  };
34362
34416
  lastCompactionTime.set(conversationId, Date.now());
34363
34417
  } catch {
34418
+ assertConversationRevision(database, conversationId, revision2);
34364
34419
  lastCompactionTime.set(conversationId, Date.now());
34365
34420
  getLogger().warn(
34366
34421
  "[summarize] Summary compaction failed, proceeding with oversized summary"
@@ -34392,10 +34447,9 @@ async function doSummarizeHistory(options) {
34392
34447
  redactor,
34393
34448
  onPiiRedacted
34394
34449
  });
34450
+ assertConversationRevision(database, conversationId, revision2);
34395
34451
  if (summarizeResult.didSummarize && summarizeResult.summary && summarizeResult.summarizedUpTo) {
34396
- await upsertConversationSummaryOp(
34397
- summaryCtx,
34398
- conversationId,
34452
+ await persistSummary(
34399
34453
  summarizeResult.summary,
34400
34454
  summarizeResult.summarizedUpTo,
34401
34455
  summarizeResult.summaryTokenCount
@@ -34414,6 +34468,7 @@ async function doSummarizeHistory(options) {
34414
34468
  summarySystemMessage: summarizeResult.summary ? summaryToSystemMessage(summarizeResult.summary) : null
34415
34469
  };
34416
34470
  } catch (err) {
34471
+ assertConversationRevision(database, conversationId, revision2);
34417
34472
  getLogger().warn("[summarize] Summarization failed, falling back to verbatim:", err);
34418
34473
  return { messagesToConvert: messages, summarySystemMessage: null };
34419
34474
  }