@sentry/junior 0.153.0 → 0.155.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/{agent-hooks-7BWOB7SN.js → agent-hooks-AWVTLAV2.js} +11 -12
  2. package/dist/api/conversations/list.d.ts +5 -3
  3. package/dist/api/conversations/membership.d.ts +16 -0
  4. package/dist/api/locations/detail.d.ts +1 -0
  5. package/dist/api/schema/conversation.d.ts +3 -0
  6. package/dist/api/schema/location.d.ts +1 -0
  7. package/dist/api/schema/person.d.ts +1 -0
  8. package/dist/api/schema.js +1 -1
  9. package/dist/api.js +318 -187
  10. package/dist/app.js +39 -39
  11. package/dist/catalog-runtime-V6YD6KH5.js +16 -0
  12. package/dist/chat/conversations/sql/event-actor.d.ts +14 -0
  13. package/dist/chat/conversations/sql/event-lock.d.ts +1 -1
  14. package/dist/chat/conversations/sql/participants.d.ts +17 -0
  15. package/dist/chat/plugins/unfinished-work.d.ts +2 -0
  16. package/dist/chat/runtime/agent-runner.d.ts +2 -0
  17. package/dist/chat/runtime/slack-resume.d.ts +1 -1
  18. package/dist/chat/state/conversation.d.ts +1 -0
  19. package/dist/{chunk-O2YXWWPM.js → chunk-2AHVM3HK.js} +92 -9
  20. package/dist/{chunk-VXWTGOLW.js → chunk-2WLJDM23.js} +1 -1
  21. package/dist/{chunk-4TWLKHOM.js → chunk-37G5HJ2X.js} +4 -4
  22. package/dist/{chunk-ISEROVYZ.js → chunk-4K5N6HTX.js} +5 -5
  23. package/dist/{chunk-ET54Q4TD.js → chunk-773XC7P4.js} +116 -82
  24. package/dist/{chunk-HUO3UTAQ.js → chunk-7MA4HV4W.js} +1 -1
  25. package/dist/{chunk-HMU2QP5M.js → chunk-7NYEB2TM.js} +1 -1
  26. package/dist/{chunk-URFV5RWN.js → chunk-AENPRXCG.js} +23 -56
  27. package/dist/{chunk-TIV3PX5H.js → chunk-APHDJYN7.js} +2 -2
  28. package/dist/{chunk-RUIXF3YQ.js → chunk-BDUENQD3.js} +1 -1
  29. package/dist/{chunk-5TXDKTET.js → chunk-CPQBTTI6.js} +7 -7
  30. package/dist/{chunk-A5SROS6H.js → chunk-ELOTIL5F.js} +5 -5
  31. package/dist/{chunk-JJAMURMR.js → chunk-EORR34UB.js} +1 -1
  32. package/dist/{chunk-5QBK3QHJ.js → chunk-J2SYI36O.js} +6 -8
  33. package/dist/{chunk-K4LK6KYO.js → chunk-J7MWZFFP.js} +4 -4
  34. package/dist/{chunk-COC65LIW.js → chunk-JFZBGFNX.js} +3 -1
  35. package/dist/{chunk-YECBSG77.js → chunk-JIC33O5L.js} +2 -2
  36. package/dist/{chunk-XAYXN4EG.js → chunk-JJX77MB7.js} +366 -138
  37. package/dist/{chunk-FLEY546A.js → chunk-KBT2I5ER.js} +7 -7
  38. package/dist/{chunk-37LMRT7G.js → chunk-KTVHAHUV.js} +1 -1
  39. package/dist/{chunk-PMJAY6JS.js → chunk-LQT3SWFA.js} +5 -5
  40. package/dist/{chunk-HYEAR6HL.js → chunk-MLBH7J7J.js} +1 -1
  41. package/dist/{chunk-5DMPHA4V.js → chunk-NKFRRZIT.js} +27 -37
  42. package/dist/{chunk-HOK7MEWG.js → chunk-NWSKFYOH.js} +1 -1
  43. package/dist/{chunk-JY2HJYJT.js → chunk-RN3AWYEP.js} +2 -2
  44. package/dist/{chunk-RKW5QGGN.js → chunk-RQ62VKM7.js} +1 -1
  45. package/dist/{chunk-XQPKMLRI.js → chunk-SDRJ2LE3.js} +1 -1
  46. package/dist/{chunk-JAJVUQV7.js → chunk-TKJ7277U.js} +3 -3
  47. package/dist/{chunk-EPOA52SD.js → chunk-TVXAN43I.js} +1 -1
  48. package/dist/{chunk-2NS3ACHB.js → chunk-UWTXAYBP.js} +11 -11
  49. package/dist/{chunk-2J4VCHRX.js → chunk-V57LZDHN.js} +8 -10
  50. package/dist/{chunk-HZF5P5UN.js → chunk-V7YE4WCP.js} +58 -7
  51. package/dist/{chunk-PGJBNO3I.js → chunk-XFZLQANQ.js} +2 -2
  52. package/dist/{chunk-5XBRH3N7.js → chunk-Y6MVGU7L.js} +12 -11
  53. package/dist/{chunk-WTKAALLV.js → chunk-Y7ZUBP2K.js} +6 -6
  54. package/dist/{chunk-UG5UCHHJ.js → chunk-ZLSFOSDK.js} +2 -1
  55. package/dist/cli/chat.js +36 -36
  56. package/dist/cli/check.js +8 -9
  57. package/dist/cli/init.js +41 -7
  58. package/dist/cli/plugins.js +15 -16
  59. package/dist/cli/snapshot-create.js +11 -12
  60. package/dist/cli/upgrade.js +9 -10
  61. package/dist/db/schema/conversation-events.d.ts +20 -0
  62. package/dist/db/schema/conversation-participants.d.ts +63 -0
  63. package/dist/db/schema.d.ts +77 -1
  64. package/dist/{db-QNQM5YRR.js → db-WT7P56AH.js} +8 -8
  65. package/dist/instrumentation.js +4 -4
  66. package/dist/nitro.js +2 -2
  67. package/dist/{oauth-callback-server-ERQPIR27.js → oauth-callback-server-R2PK2MCA.js} +26 -26
  68. package/dist/{runner-BX46SQIE.js → runner-O7YYUIHT.js} +15 -16
  69. package/dist/{sandbox-egress-signals-EKPAVWQL.js → sandbox-egress-signals-U3ZX7C5W.js} +3 -4
  70. package/dist/{skills-JL44EIRX.js → skills-S6HLQRH7.js} +8 -9
  71. package/dist/spawn-B4SBFFA2.js +37 -0
  72. package/dist/{validation-UU2AIJIY.js → validation-46WD2OAR.js} +8 -9
  73. package/dist/version.js +1 -1
  74. package/dist/{work-SS7RU5CH.js → work-YT5QUBS3.js} +20 -21
  75. package/dist/worker-4C5BEDWN.js +24 -0
  76. package/migrations/0026_conversation_event_actor_and_participants.sql +140 -0
  77. package/migrations/meta/0026_snapshot.json +2424 -0
  78. package/migrations/meta/_journal.json +7 -0
  79. package/package.json +8 -6
  80. package/dist/catalog-runtime-CGUDNL3D.js +0 -17
  81. package/dist/chunk-F3B2YJ76.js +0 -57
  82. package/dist/spawn-W6FO32T4.js +0 -38
  83. package/dist/worker-5P2E7LVI.js +0 -25
@@ -2,29 +2,31 @@ import {
2
2
  createJuniorSqlExecutor,
3
3
  juniorConversationBindings,
4
4
  juniorConversationEvents,
5
+ juniorConversationParticipants,
5
6
  juniorConversations,
6
7
  juniorIdentities,
7
8
  juniorUsers
8
- } from "./chunk-ET54Q4TD.js";
9
+ } from "./chunk-773XC7P4.js";
9
10
  import {
10
11
  TURN_REASONING_LEVELS,
11
12
  getChatConfig,
12
13
  modelProfileSchema
13
- } from "./chunk-PGJBNO3I.js";
14
+ } from "./chunk-XFZLQANQ.js";
14
15
  import {
15
16
  juniorDestinations
16
17
  } from "./chunk-VFUK3X5B.js";
17
18
  import {
19
+ parseActorUserId,
18
20
  parseSlackChannelReferenceId,
19
21
  parseSlackTeamId
20
- } from "./chunk-F3B2YJ76.js";
22
+ } from "./chunk-V7YE4WCP.js";
21
23
  import {
22
24
  normalizeIdentityEmail
23
- } from "./chunk-HMU2QP5M.js";
25
+ } from "./chunk-7NYEB2TM.js";
24
26
 
25
27
  // src/chat/conversations/sql/store.ts
26
28
  import { randomUUID as randomUUID2 } from "crypto";
27
- import { and as and3, asc, desc, eq as eq3, isNull, sql as sql2 } from "drizzle-orm";
29
+ import { and as and4, asc, desc, eq as eq4, isNull, sql as sql3 } from "drizzle-orm";
28
30
 
29
31
  // src/chat/destination.ts
30
32
  import {
@@ -206,6 +208,42 @@ async function deleteProviderIdentityForSlackUser(executor, slackTeamId, slackUs
206
208
  );
207
209
  }
208
210
 
211
+ // src/chat/conversations/sql/participants.ts
212
+ import { and as and2, eq as eq2, inArray, sql as sql2 } from "drizzle-orm";
213
+ async function resolveRootConversationId(executor, conversationId) {
214
+ const [row] = await executor.db().select({
215
+ rootConversationId: juniorConversations.rootConversationId
216
+ }).from(juniorConversations).where(eq2(juniorConversations.conversationId, conversationId)).limit(1);
217
+ return row?.rootConversationId ?? conversationId;
218
+ }
219
+ async function recordConversationParticipant(executor, args) {
220
+ const [identity] = await executor.db().select({
221
+ kind: juniorIdentities.kind,
222
+ userId: juniorIdentities.userId
223
+ }).from(juniorIdentities).where(eq2(juniorIdentities.id, args.actorIdentityId)).limit(1);
224
+ if (!identity?.userId || identity.kind !== "user") {
225
+ return;
226
+ }
227
+ const rootConversationId = await resolveRootConversationId(
228
+ executor,
229
+ args.conversationId
230
+ );
231
+ const at = new Date(args.atMs);
232
+ await executor.db().insert(juniorConversationParticipants).values({
233
+ userId: identity.userId,
234
+ rootConversationId,
235
+ lastMessageAt: at
236
+ }).onConflictDoUpdate({
237
+ target: [
238
+ juniorConversationParticipants.userId,
239
+ juniorConversationParticipants.rootConversationId
240
+ ],
241
+ set: {
242
+ lastMessageAt: sql2`greatest(${juniorConversationParticipants.lastMessageAt}, excluded.last_message_at)`
243
+ }
244
+ });
245
+ }
246
+
209
247
  // src/chat/source.ts
210
248
  import { sourceSchema } from "@sentry/junior-plugin-api";
211
249
  function normalizeSessionSource(value) {
@@ -241,17 +279,17 @@ function parseSessionSource(value) {
241
279
  }
242
280
 
243
281
  // src/chat/conversations/sql/bindings.ts
244
- import { and as and2, eq as eq2 } from "drizzle-orm";
282
+ import { and as and3, eq as eq3 } from "drizzle-orm";
245
283
  async function getConversationIdByProviderConversation(executor, args) {
246
284
  const rows = await executor.db().select({ conversationId: juniorConversationBindings.conversationId }).from(juniorConversationBindings).where(
247
- and2(
248
- eq2(juniorConversationBindings.provider, args.provider),
249
- eq2(juniorConversationBindings.providerTenantId, args.providerTenantId),
250
- eq2(
285
+ and3(
286
+ eq3(juniorConversationBindings.provider, args.provider),
287
+ eq3(juniorConversationBindings.providerTenantId, args.providerTenantId),
288
+ eq3(
251
289
  juniorConversationBindings.providerDestinationId,
252
290
  args.providerDestinationId
253
291
  ),
254
- eq2(
292
+ eq3(
255
293
  juniorConversationBindings.providerConversationId,
256
294
  args.providerConversationId
257
295
  )
@@ -768,7 +806,7 @@ var SqlStore = class {
768
806
  metricRunId: args.execution.runId ?? null,
769
807
  executionDurationMs: args.metrics.durationMs,
770
808
  executionUsage: args.metrics.usage ?? (sameRun ? row?.executionUsage ?? null : null)
771
- }).where(eq3(juniorConversations.conversationId, args.conversationId));
809
+ }).where(eq4(juniorConversations.conversationId, args.conversationId));
772
810
  }
773
811
  });
774
812
  }
@@ -780,11 +818,11 @@ var SqlStore = class {
780
818
  actorUserDisplayName: juniorUsers.displayName
781
819
  }).from(juniorConversations).leftJoin(
782
820
  juniorDestinations,
783
- eq3(juniorDestinations.id, juniorConversations.destinationId)
821
+ eq4(juniorDestinations.id, juniorConversations.destinationId)
784
822
  ).leftJoin(
785
823
  juniorIdentities,
786
- eq3(juniorIdentities.id, juniorConversations.actorIdentityId)
787
- ).leftJoin(juniorUsers, eq3(juniorUsers.id, juniorIdentities.userId)).where(isNull(juniorConversations.parentConversationId)).orderBy(
824
+ eq4(juniorIdentities.id, juniorConversations.actorIdentityId)
825
+ ).leftJoin(juniorUsers, eq4(juniorUsers.id, juniorIdentities.userId)).where(isNull(juniorConversations.parentConversationId)).orderBy(
788
826
  desc(juniorConversations.lastActivityAt),
789
827
  asc(juniorConversations.conversationId)
790
828
  ).limit(Math.max(0, args.limit ?? 1e4)).offset(Math.max(0, args.offset ?? 0));
@@ -798,13 +836,13 @@ var SqlStore = class {
798
836
  const rows = await this.executor.db().select({
799
837
  visibility: juniorDestinations.visibility
800
838
  }).from(juniorDestinations).where(
801
- and3(
802
- eq3(juniorDestinations.provider, args.provider),
803
- eq3(
839
+ and4(
840
+ eq4(juniorDestinations.provider, args.provider),
841
+ eq4(
804
842
  juniorDestinations.providerTenantId,
805
843
  tenantId2(args.providerTenantId)
806
844
  ),
807
- eq3(
845
+ eq4(
808
846
  juniorDestinations.providerDestinationId,
809
847
  args.providerDestinationId
810
848
  )
@@ -835,19 +873,19 @@ var SqlStore = class {
835
873
  actorUserDisplayName: juniorUsers.displayName
836
874
  }).from(juniorConversations).leftJoin(
837
875
  juniorDestinations,
838
- eq3(juniorDestinations.id, juniorConversations.destinationId)
876
+ eq4(juniorDestinations.id, juniorConversations.destinationId)
839
877
  ).leftJoin(
840
878
  juniorIdentities,
841
- eq3(juniorIdentities.id, juniorConversations.actorIdentityId)
842
- ).leftJoin(juniorUsers, eq3(juniorUsers.id, juniorIdentities.userId)).where(eq3(juniorConversations.conversationId, conversationId));
879
+ eq4(juniorIdentities.id, juniorConversations.actorIdentityId)
880
+ ).leftJoin(juniorUsers, eq4(juniorUsers.id, juniorIdentities.userId)).where(eq4(juniorConversations.conversationId, conversationId));
843
881
  return rows[0];
844
882
  }
845
883
  /** Upsert the conversation row while preserving previously discovered nullable metadata fields. */
846
884
  async upsertConversation(args) {
847
885
  const { conversation } = args;
848
- const incomingExecutionVersion = sql2`coalesce(excluded.execution_updated_at, excluded.updated_at)`;
849
- const currentExecutionVersion = sql2`coalesce(${juniorConversations.executionUpdatedAt}, ${juniorConversations.updatedAt})`;
850
- const incomingExecutionIsFresh = sql2`${incomingExecutionVersion} >= ${currentExecutionVersion}`;
886
+ const incomingExecutionVersion = sql3`coalesce(excluded.execution_updated_at, excluded.updated_at)`;
887
+ const currentExecutionVersion = sql3`coalesce(${juniorConversations.executionUpdatedAt}, ${juniorConversations.updatedAt})`;
888
+ const incomingExecutionIsFresh = sql3`${incomingExecutionVersion} >= ${currentExecutionVersion}`;
851
889
  const destinationId = await this.upsertDestination(
852
890
  destinationUpsertFromDestination({
853
891
  channelName: conversation.channelName,
@@ -863,7 +901,7 @@ var SqlStore = class {
863
901
  actorIdentityObservation,
864
902
  conversation.updatedAtMs
865
903
  ) : void 0;
866
- const rootConversationId = conversation.lineage ? sql2`(
904
+ const rootConversationId = conversation.lineage ? sql3`(
867
905
  select parent.root_conversation_id
868
906
  from junior_conversations parent
869
907
  where parent.conversation_id = ${conversation.lineage.parentConversationId}
@@ -898,39 +936,49 @@ var SqlStore = class {
898
936
  target: juniorConversations.conversationId,
899
937
  set: {
900
938
  // Origin source is set-once so dashboard continues cannot rewrite a Slack root.
901
- source: sql2`coalesce(${juniorConversations.source}, excluded.source)`,
902
- sessionSource: sql2`coalesce(${juniorConversations.sessionSource}, excluded.source_json)`,
903
- originType: sql2`coalesce(excluded.origin_type, ${juniorConversations.originType})`,
904
- originId: sql2`coalesce(excluded.origin_id, ${juniorConversations.originId})`,
905
- originRunId: sql2`coalesce(excluded.origin_run_id, ${juniorConversations.originRunId})`,
906
- destinationId: sql2`coalesce(excluded.destination_id, ${juniorConversations.destinationId})`,
907
- actorIdentityId: sql2`coalesce(excluded.actor_identity_id, ${juniorConversations.actorIdentityId})`,
908
- creatorIdentityId: sql2`coalesce(excluded.creator_identity_id, ${juniorConversations.creatorIdentityId})`,
909
- credentialSubjectIdentityId: sql2`coalesce(excluded.credential_subject_identity_id, ${juniorConversations.credentialSubjectIdentityId})`,
910
- channelName: sql2`coalesce(excluded.channel_name, ${juniorConversations.channelName})`,
911
- title: sql2`coalesce(excluded.title, ${juniorConversations.title})`,
912
- createdAt: sql2`least(${juniorConversations.createdAt}, excluded.created_at)`,
913
- lastActivityAt: sql2`greatest(${juniorConversations.lastActivityAt}, excluded.last_activity_at)`,
914
- updatedAt: sql2`greatest(${juniorConversations.updatedAt}, excluded.updated_at)`,
915
- executionUpdatedAt: sql2`case when ${incomingExecutionIsFresh} then excluded.execution_updated_at else ${juniorConversations.executionUpdatedAt} end`,
916
- executionStatus: sql2`case when ${incomingExecutionIsFresh} then excluded.execution_status else ${juniorConversations.executionStatus} end`,
917
- runId: sql2`case when ${incomingExecutionIsFresh} then excluded.run_id else ${juniorConversations.runId} end`,
918
- lastCheckpointAt: sql2`case when ${incomingExecutionIsFresh} then coalesce(excluded.last_checkpoint_at, ${juniorConversations.lastCheckpointAt}) else ${juniorConversations.lastCheckpointAt} end`,
919
- lastEnqueuedAt: sql2`case when ${incomingExecutionIsFresh} then coalesce(excluded.last_enqueued_at, ${juniorConversations.lastEnqueuedAt}) else ${juniorConversations.lastEnqueuedAt} end`,
920
- rootConversationId: sql2`coalesce(${juniorConversations.rootConversationId}, excluded.root_conversation_id)`
939
+ source: sql3`coalesce(${juniorConversations.source}, excluded.source)`,
940
+ sessionSource: sql3`coalesce(${juniorConversations.sessionSource}, excluded.source_json)`,
941
+ originType: sql3`coalesce(excluded.origin_type, ${juniorConversations.originType})`,
942
+ originId: sql3`coalesce(excluded.origin_id, ${juniorConversations.originId})`,
943
+ originRunId: sql3`coalesce(excluded.origin_run_id, ${juniorConversations.originRunId})`,
944
+ destinationId: sql3`coalesce(excluded.destination_id, ${juniorConversations.destinationId})`,
945
+ actorIdentityId: sql3`coalesce(excluded.actor_identity_id, ${juniorConversations.actorIdentityId})`,
946
+ creatorIdentityId: sql3`coalesce(excluded.creator_identity_id, ${juniorConversations.creatorIdentityId})`,
947
+ credentialSubjectIdentityId: sql3`coalesce(excluded.credential_subject_identity_id, ${juniorConversations.credentialSubjectIdentityId})`,
948
+ channelName: sql3`coalesce(excluded.channel_name, ${juniorConversations.channelName})`,
949
+ title: sql3`coalesce(excluded.title, ${juniorConversations.title})`,
950
+ createdAt: sql3`least(${juniorConversations.createdAt}, excluded.created_at)`,
951
+ lastActivityAt: sql3`greatest(${juniorConversations.lastActivityAt}, excluded.last_activity_at)`,
952
+ updatedAt: sql3`greatest(${juniorConversations.updatedAt}, excluded.updated_at)`,
953
+ executionUpdatedAt: sql3`case when ${incomingExecutionIsFresh} then excluded.execution_updated_at else ${juniorConversations.executionUpdatedAt} end`,
954
+ executionStatus: sql3`case when ${incomingExecutionIsFresh} then excluded.execution_status else ${juniorConversations.executionStatus} end`,
955
+ runId: sql3`case when ${incomingExecutionIsFresh} then excluded.run_id else ${juniorConversations.runId} end`,
956
+ lastCheckpointAt: sql3`case when ${incomingExecutionIsFresh} then coalesce(excluded.last_checkpoint_at, ${juniorConversations.lastCheckpointAt}) else ${juniorConversations.lastCheckpointAt} end`,
957
+ lastEnqueuedAt: sql3`case when ${incomingExecutionIsFresh} then coalesce(excluded.last_enqueued_at, ${juniorConversations.lastEnqueuedAt}) else ${juniorConversations.lastEnqueuedAt} end`,
958
+ rootConversationId: sql3`coalesce(${juniorConversations.rootConversationId}, excluded.root_conversation_id)`
921
959
  }
922
960
  }).returning({
961
+ actorIdentityId: juniorConversations.actorIdentityId,
962
+ parentConversationId: juniorConversations.parentConversationId,
923
963
  rootConversationId: juniorConversations.rootConversationId
924
964
  });
925
- if (!rows[0]?.rootConversationId) {
965
+ const row = rows[0];
966
+ if (!row?.rootConversationId) {
926
967
  throw new Error("Conversation parent is missing its persisted root");
927
968
  }
969
+ if (row.actorIdentityId && row.parentConversationId === null) {
970
+ await recordConversationParticipant(this.executor, {
971
+ actorIdentityId: row.actorIdentityId,
972
+ conversationId: conversation.conversationId,
973
+ atMs: conversation.lastActivityAtMs
974
+ });
975
+ }
928
976
  }
929
977
  async upsertDestination(destination, nowMs) {
930
978
  if (!destination) {
931
979
  return void 0;
932
980
  }
933
- const visibilityUpdate = destination.refreshVisibility ? sql2`excluded.visibility` : juniorDestinations.visibility;
981
+ const visibilityUpdate = destination.refreshVisibility ? sql3`excluded.visibility` : juniorDestinations.visibility;
934
982
  const rows = await this.executor.db().insert(juniorDestinations).values({
935
983
  id: randomUUID2(),
936
984
  provider: destination.provider,
@@ -950,14 +998,14 @@ var SqlStore = class {
950
998
  juniorDestinations.providerDestinationId
951
999
  ],
952
1000
  set: {
953
- kind: sql2`excluded.kind`,
954
- displayName: sql2`coalesce(excluded.display_name, ${juniorDestinations.displayName})`,
1001
+ kind: sql3`excluded.kind`,
1002
+ displayName: sql3`coalesce(excluded.display_name, ${juniorDestinations.displayName})`,
955
1003
  // Signal-less writes remain unknown and must not clobber an existing
956
1004
  // public/private value. Live source signals refresh this field so
957
1005
  // converted channels converge on the next message.
958
1006
  visibility: visibilityUpdate,
959
- metadata: sql2`coalesce(excluded.metadata_json, ${juniorDestinations.metadata})`,
960
- updatedAt: sql2`excluded.updated_at`
1007
+ metadata: sql3`coalesce(excluded.metadata_json, ${juniorDestinations.metadata})`,
1008
+ updatedAt: sql3`excluded.updated_at`
961
1009
  }
962
1010
  }).returning({ id: juniorDestinations.id });
963
1011
  return rows[0]?.id;
@@ -969,17 +1017,17 @@ function createSqlStore(executor) {
969
1017
 
970
1018
  // src/chat/conversations/sql/history.ts
971
1019
  import {
972
- and as and4,
1020
+ and as and6,
973
1021
  asc as asc2,
974
1022
  desc as desc2,
975
- eq as eq4,
1023
+ eq as eq6,
976
1024
  gt,
977
1025
  gte,
978
- inArray,
1026
+ inArray as inArray2,
979
1027
  isNotNull,
980
1028
  lt,
981
1029
  lte,
982
- sql as sql4
1030
+ sql as sql6
983
1031
  } from "drizzle-orm";
984
1032
 
985
1033
  // src/chat/conversations/history.ts
@@ -1344,7 +1392,7 @@ var newConversationEventSchema = z3.object({
1344
1392
  }).strict();
1345
1393
 
1346
1394
  // src/chat/conversations/sql/conversation-row.ts
1347
- import { sql as sql3 } from "drizzle-orm";
1395
+ import { sql as sql4 } from "drizzle-orm";
1348
1396
  async function ensureConversationRow(executor, conversationId, atMs, options = {}) {
1349
1397
  const at = new Date(atMs);
1350
1398
  const insert = executor.db().insert(juniorConversations).values({
@@ -1363,13 +1411,169 @@ async function ensureConversationRow(executor, conversationId, atMs, options = {
1363
1411
  await insert.onConflictDoUpdate({
1364
1412
  target: juniorConversations.conversationId,
1365
1413
  set: {
1366
- lastActivityAt: sql3`greatest(${juniorConversations.lastActivityAt}, excluded.last_activity_at)`,
1367
- updatedAt: sql3`greatest(${juniorConversations.updatedAt}, excluded.updated_at)`,
1414
+ lastActivityAt: sql4`greatest(${juniorConversations.lastActivityAt}, excluded.last_activity_at)`,
1415
+ updatedAt: sql4`greatest(${juniorConversations.updatedAt}, excluded.updated_at)`,
1368
1416
  transcriptPurgedAt: null
1369
1417
  }
1370
1418
  });
1371
1419
  }
1372
1420
 
1421
+ // src/chat/conversations/sql/event-actor.ts
1422
+ import { and as and5, eq as eq5, or, sql as sql5 } from "drizzle-orm";
1423
+ var SLACK_USER_ID_PATTERN = /^[UW][A-Z0-9]{5,}$/;
1424
+ function isRecord(value) {
1425
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1426
+ }
1427
+ function readAuthor(meta) {
1428
+ if (!isRecord(meta) || !isRecord(meta.author)) {
1429
+ return {};
1430
+ }
1431
+ const author = meta.author;
1432
+ return {
1433
+ ...typeof author.email === "string" ? { email: author.email } : {},
1434
+ ...typeof author.fullName === "string" ? { fullName: author.fullName } : {},
1435
+ ...typeof author.isBot === "boolean" ? { isBot: author.isBot } : {},
1436
+ ...typeof author.userId === "string" ? { userId: author.userId } : {},
1437
+ ...typeof author.userName === "string" ? { userName: author.userName } : {}
1438
+ };
1439
+ }
1440
+ async function loadConversationSlackTenantId(executor, conversationId) {
1441
+ const [row] = await executor.db().select({
1442
+ providerTenantId: juniorDestinations.providerTenantId,
1443
+ sessionSource: juniorConversations.sessionSource
1444
+ }).from(juniorConversations).leftJoin(
1445
+ juniorDestinations,
1446
+ eq5(juniorDestinations.id, juniorConversations.destinationId)
1447
+ ).where(eq5(juniorConversations.conversationId, conversationId)).limit(1);
1448
+ const destinationTenant = row?.providerTenantId?.trim();
1449
+ if (destinationTenant) {
1450
+ return destinationTenant;
1451
+ }
1452
+ const sessionSource = row?.sessionSource;
1453
+ if (isRecord(sessionSource) && sessionSource.platform === "slack" && typeof sessionSource.teamId === "string" && sessionSource.teamId.trim()) {
1454
+ return sessionSource.teamId.trim();
1455
+ }
1456
+ return void 0;
1457
+ }
1458
+ async function findIdentityIdByProviderSubject(executor, args) {
1459
+ const rows = await executor.db().select({ id: juniorIdentities.id }).from(juniorIdentities).where(
1460
+ and5(
1461
+ eq5(juniorIdentities.provider, args.provider),
1462
+ eq5(juniorIdentities.providerSubjectId, args.providerSubjectId),
1463
+ args.providerTenantId === void 0 ? void 0 : eq5(juniorIdentities.providerTenantId, args.providerTenantId)
1464
+ )
1465
+ ).limit(1);
1466
+ return rows[0]?.id;
1467
+ }
1468
+ async function findJuniorIdentityIdByEmail(executor, email) {
1469
+ const normalized = email.trim().toLowerCase();
1470
+ if (!normalized) return void 0;
1471
+ const rows = await executor.db().select({ id: juniorIdentities.id }).from(juniorIdentities).where(
1472
+ and5(
1473
+ eq5(juniorIdentities.provider, "junior"),
1474
+ eq5(juniorIdentities.kind, "user"),
1475
+ or(
1476
+ eq5(juniorIdentities.providerSubjectId, normalized),
1477
+ and5(
1478
+ eq5(juniorIdentities.emailNormalized, normalized),
1479
+ eq5(juniorIdentities.emailVerified, true)
1480
+ )
1481
+ )
1482
+ )
1483
+ ).limit(1);
1484
+ return rows[0]?.id;
1485
+ }
1486
+ async function findJuniorIdentityIdByDashboardAuthorId(executor, dashboardAuthorId) {
1487
+ if (!dashboardAuthorId.startsWith("dashboard:")) {
1488
+ return void 0;
1489
+ }
1490
+ const rows = await executor.db().select({ id: juniorIdentities.id }).from(juniorIdentities).where(
1491
+ and5(
1492
+ eq5(juniorIdentities.provider, "junior"),
1493
+ eq5(juniorIdentities.kind, "user"),
1494
+ eq5(juniorIdentities.emailVerified, true),
1495
+ sql5`${juniorIdentities.emailNormalized} is not null`,
1496
+ // Match webActorFromEmail(): dashboard:${sha256(email).slice(0,24)}
1497
+ sql5`concat(
1498
+ 'dashboard:',
1499
+ left(encode(digest(${juniorIdentities.emailNormalized}, 'sha256'), 'hex'), 24)
1500
+ ) = ${dashboardAuthorId}`
1501
+ )
1502
+ ).limit(1);
1503
+ return rows[0]?.id;
1504
+ }
1505
+ async function resolveEventActorIdentityId(executor, args) {
1506
+ const data = args.data;
1507
+ if (data.type !== "message" && data.type !== "message_updated") {
1508
+ return void 0;
1509
+ }
1510
+ if (typeof data.authorIdentityId === "string" && data.authorIdentityId) {
1511
+ return data.authorIdentityId;
1512
+ }
1513
+ if (data.role !== "user") {
1514
+ return void 0;
1515
+ }
1516
+ const author = readAuthor(data.meta);
1517
+ if (author.isBot === true) {
1518
+ return void 0;
1519
+ }
1520
+ const userId = parseActorUserId(author.userId);
1521
+ if (!userId) {
1522
+ return void 0;
1523
+ }
1524
+ if (SLACK_USER_ID_PATTERN.test(userId)) {
1525
+ const tenantId3 = await loadConversationSlackTenantId(
1526
+ executor,
1527
+ args.conversationId
1528
+ );
1529
+ const observation = {
1530
+ kind: "user",
1531
+ provider: "slack",
1532
+ providerSubjectId: userId,
1533
+ ...tenantId3 ? { providerTenantId: tenantId3 } : {},
1534
+ ...author.fullName ? { displayName: author.fullName } : {},
1535
+ ...author.userName ? { handle: author.userName } : {},
1536
+ ...author.email ? { email: author.email, emailVerified: true } : {}
1537
+ };
1538
+ if (tenantId3) {
1539
+ const stored = await upsertIdentity(executor, observation, args.nowMs);
1540
+ return stored.id;
1541
+ }
1542
+ return await findIdentityIdByProviderSubject(executor, {
1543
+ provider: "slack",
1544
+ providerSubjectId: userId
1545
+ }) ?? void 0;
1546
+ }
1547
+ const email = typeof author.email === "string" && author.email.includes("@") ? author.email.trim().toLowerCase() : userId.includes("@") ? userId.trim().toLowerCase() : void 0;
1548
+ if (email) {
1549
+ const stored = await upsertIdentity(
1550
+ executor,
1551
+ {
1552
+ kind: "user",
1553
+ provider: "junior",
1554
+ providerSubjectId: email,
1555
+ email,
1556
+ emailVerified: true,
1557
+ ...author.fullName ? { displayName: author.fullName } : {},
1558
+ metadata: { platform: "web" }
1559
+ },
1560
+ args.nowMs
1561
+ );
1562
+ return stored.id;
1563
+ }
1564
+ if (userId.startsWith("dashboard:")) {
1565
+ return findJuniorIdentityIdByDashboardAuthorId(executor, userId);
1566
+ }
1567
+ return findJuniorIdentityIdByEmail(executor, userId);
1568
+ }
1569
+ function stripPayloadAuthorIdentityId(data) {
1570
+ if (data.type !== "message" && data.type !== "message_updated" || data.authorIdentityId === void 0) {
1571
+ return data;
1572
+ }
1573
+ const { authorIdentityId: _authorIdentityId, ...rest } = data;
1574
+ return rest;
1575
+ }
1576
+
1373
1577
  // src/db/postgres-json.ts
1374
1578
  function sanitizePostgresJson(value) {
1375
1579
  if (typeof value === "string") {
@@ -1395,10 +1599,7 @@ function sanitizePostgresJson(value) {
1395
1599
 
1396
1600
  // src/chat/conversations/sql/event-lock.ts
1397
1601
  async function withConversationEventLock(executor, conversationId, callback) {
1398
- return executor.withLock(
1399
- `junior_conversation:event:${conversationId}`,
1400
- callback
1401
- );
1602
+ return executor.withLock(`junior_conversation:${conversationId}`, callback);
1402
1603
  }
1403
1604
 
1404
1605
  // src/chat/conversations/sql/history.ts
@@ -1407,8 +1608,9 @@ var messageHistoryEventTypes = [
1407
1608
  "message_updated",
1408
1609
  "message_handled"
1409
1610
  ];
1410
- function insertFromEvent(conversationId, seq, historyVersion, event) {
1411
- const { type, ...payload } = conversationEventDataSchema.parse(event.data);
1611
+ function insertFromEvent(conversationId, seq, historyVersion, event, actorIdentityId) {
1612
+ const stripped = stripPayloadAuthorIdentityId(event.data);
1613
+ const { type, ...payload } = conversationEventDataSchema.parse(stripped);
1412
1614
  return {
1413
1615
  conversationId,
1414
1616
  seq,
@@ -1417,10 +1619,12 @@ function insertFromEvent(conversationId, seq, historyVersion, event) {
1417
1619
  idempotencyKey: event.idempotencyKey ?? null,
1418
1620
  type,
1419
1621
  payload: sanitizePostgresJson(payload),
1622
+ actorIdentityId: actorIdentityId ?? null,
1420
1623
  createdAt: new Date(event.createdAtMs)
1421
1624
  };
1422
1625
  }
1423
1626
  function eventFromRow(row) {
1627
+ const payload = row.actorIdentityId && typeof row.payload === "object" && row.payload !== null && !Array.isArray(row.payload) && (row.type === "message" || row.type === "message_updated") && !("authorIdentityId" in row.payload) ? { ...row.payload, authorIdentityId: row.actorIdentityId } : row.payload;
1424
1628
  return decodeStoredConversationEvent({
1425
1629
  schemaVersion: row.schemaVersion,
1426
1630
  seq: row.seq,
@@ -1428,7 +1632,7 @@ function eventFromRow(row) {
1428
1632
  ...row.idempotencyKey ? { idempotencyKey: row.idempotencyKey } : {},
1429
1633
  createdAtMs: row.createdAt.getTime(),
1430
1634
  type: row.type,
1431
- payload: row.payload
1635
+ payload
1432
1636
  });
1433
1637
  }
1434
1638
  function messagesSummarizedEventFromRow(row) {
@@ -1456,12 +1660,12 @@ var SqlConversationEventStore = class {
1456
1660
  const existingKeys = parsed.map((event) => event.idempotencyKey).filter((key) => key !== void 0);
1457
1661
  const persistedKeys = existingKeys.length === 0 ? /* @__PURE__ */ new Set() : new Set(
1458
1662
  (await this.executor.db().select({ key: juniorConversationEvents.idempotencyKey }).from(juniorConversationEvents).where(
1459
- and4(
1460
- eq4(
1663
+ and6(
1664
+ eq6(
1461
1665
  juniorConversationEvents.conversationId,
1462
1666
  conversationId
1463
1667
  ),
1464
- inArray(
1668
+ inArray2(
1465
1669
  juniorConversationEvents.idempotencyKey,
1466
1670
  existingKeys
1467
1671
  )
@@ -1489,8 +1693,8 @@ var SqlConversationEventStore = class {
1489
1693
  );
1490
1694
  if (options.activity !== "preserve") {
1491
1695
  await this.executor.db().update(juniorConversations).set({ archivedAt: null }).where(
1492
- and4(
1493
- eq4(juniorConversations.conversationId, conversationId),
1696
+ and6(
1697
+ eq6(juniorConversations.conversationId, conversationId),
1494
1698
  isNotNull(juniorConversations.archivedAt)
1495
1699
  )
1496
1700
  );
@@ -1498,9 +1702,33 @@ var SqlConversationEventStore = class {
1498
1702
  const cursor = await this.readCursor(conversationId);
1499
1703
  const historyVersion = cursor.maxHistoryVersion ?? 0;
1500
1704
  let seq = cursor.nextSeq;
1501
- const rows = pending.map(
1502
- (event) => insertFromEvent(conversationId, seq++, historyVersion, event)
1503
- );
1705
+ const rows = [];
1706
+ for (const event of pending) {
1707
+ const actorIdentityId = await resolveEventActorIdentityId(
1708
+ this.executor,
1709
+ {
1710
+ conversationId,
1711
+ data: event.data,
1712
+ nowMs: event.createdAtMs
1713
+ }
1714
+ );
1715
+ rows.push(
1716
+ insertFromEvent(
1717
+ conversationId,
1718
+ seq++,
1719
+ historyVersion,
1720
+ event,
1721
+ actorIdentityId
1722
+ )
1723
+ );
1724
+ if (actorIdentityId) {
1725
+ await recordConversationParticipant(this.executor, {
1726
+ actorIdentityId,
1727
+ conversationId,
1728
+ atMs: event.createdAtMs
1729
+ });
1730
+ }
1731
+ }
1504
1732
  await this.executor.db().insert(juniorConversationEvents).values(rows);
1505
1733
  });
1506
1734
  }
@@ -1509,8 +1737,8 @@ var SqlConversationEventStore = class {
1509
1737
  await withConversationEventLock(this.executor, conversationId, async () => {
1510
1738
  await ensureConversationRow(this.executor, conversationId, Date.now());
1511
1739
  await this.executor.db().update(juniorConversations).set({ archivedAt: null }).where(
1512
- and4(
1513
- eq4(juniorConversations.conversationId, conversationId),
1740
+ and6(
1741
+ eq6(juniorConversations.conversationId, conversationId),
1514
1742
  isNotNull(juniorConversations.archivedAt)
1515
1743
  )
1516
1744
  );
@@ -1532,34 +1760,34 @@ var SqlConversationEventStore = class {
1532
1760
  return [];
1533
1761
  }
1534
1762
  const rows = await this.executor.db().select().from(juniorConversationEvents).where(
1535
- and4(
1536
- eq4(juniorConversationEvents.conversationId, conversationId),
1537
- eq4(juniorConversationEvents.historyVersion, cursor.maxHistoryVersion)
1763
+ and6(
1764
+ eq6(juniorConversationEvents.conversationId, conversationId),
1765
+ eq6(juniorConversationEvents.historyVersion, cursor.maxHistoryVersion)
1538
1766
  )
1539
1767
  ).orderBy(asc2(juniorConversationEvents.seq));
1540
1768
  return rows.map(eventFromRow);
1541
1769
  }
1542
1770
  async loadByIdempotencyKey(conversationId, idempotencyKey) {
1543
1771
  const [row] = await this.executor.db().select().from(juniorConversationEvents).where(
1544
- and4(
1545
- eq4(juniorConversationEvents.conversationId, conversationId),
1546
- eq4(juniorConversationEvents.idempotencyKey, idempotencyKey)
1772
+ and6(
1773
+ eq6(juniorConversationEvents.conversationId, conversationId),
1774
+ eq6(juniorConversationEvents.idempotencyKey, idempotencyKey)
1547
1775
  )
1548
1776
  ).limit(1);
1549
1777
  return row ? eventFromRow(row) : void 0;
1550
1778
  }
1551
1779
  async loadHistoryContaining(conversationId, seq, throughSeq) {
1552
1780
  const [boundary] = await this.executor.db().select({ historyVersion: juniorConversationEvents.historyVersion }).from(juniorConversationEvents).where(
1553
- and4(
1554
- eq4(juniorConversationEvents.conversationId, conversationId),
1555
- eq4(juniorConversationEvents.seq, seq)
1781
+ and6(
1782
+ eq6(juniorConversationEvents.conversationId, conversationId),
1783
+ eq6(juniorConversationEvents.seq, seq)
1556
1784
  )
1557
1785
  ).limit(1);
1558
1786
  if (!boundary) return void 0;
1559
1787
  const rows = await this.executor.db().select().from(juniorConversationEvents).where(
1560
- and4(
1561
- eq4(juniorConversationEvents.conversationId, conversationId),
1562
- eq4(juniorConversationEvents.historyVersion, boundary.historyVersion),
1788
+ and6(
1789
+ eq6(juniorConversationEvents.conversationId, conversationId),
1790
+ eq6(juniorConversationEvents.historyVersion, boundary.historyVersion),
1563
1791
  throughSeq === void 0 ? void 0 : lte(juniorConversationEvents.seq, throughSeq)
1564
1792
  )
1565
1793
  ).orderBy(asc2(juniorConversationEvents.seq));
@@ -1567,45 +1795,45 @@ var SqlConversationEventStore = class {
1567
1795
  }
1568
1796
  async loadLatestStructuredEvent(conversationId, namespace, name) {
1569
1797
  const [row] = await this.executor.db().select().from(juniorConversationEvents).where(
1570
- and4(
1571
- eq4(juniorConversationEvents.conversationId, conversationId),
1572
- eq4(juniorConversationEvents.type, "structured_event"),
1573
- sql4`${juniorConversationEvents.payload}->>'namespace' = ${namespace}`,
1574
- sql4`${juniorConversationEvents.payload}->>'name' = ${name}`
1798
+ and6(
1799
+ eq6(juniorConversationEvents.conversationId, conversationId),
1800
+ eq6(juniorConversationEvents.type, "structured_event"),
1801
+ sql6`${juniorConversationEvents.payload}->>'namespace' = ${namespace}`,
1802
+ sql6`${juniorConversationEvents.payload}->>'name' = ${name}`
1575
1803
  )
1576
1804
  ).orderBy(desc2(juniorConversationEvents.seq)).limit(1);
1577
1805
  return row ? eventFromRow(row) : void 0;
1578
1806
  }
1579
1807
  async loadLatestInstruction(conversationId) {
1580
1808
  const [row] = await this.executor.db().select().from(juniorConversationEvents).where(
1581
- and4(
1582
- eq4(juniorConversationEvents.conversationId, conversationId),
1583
- eq4(juniorConversationEvents.type, "user_message"),
1584
- sql4`${juniorConversationEvents.payload}->'provenance'->>'authority' = 'instruction'`
1809
+ and6(
1810
+ eq6(juniorConversationEvents.conversationId, conversationId),
1811
+ eq6(juniorConversationEvents.type, "user_message"),
1812
+ sql6`${juniorConversationEvents.payload}->'provenance'->>'authority' = 'instruction'`
1585
1813
  )
1586
1814
  ).orderBy(desc2(juniorConversationEvents.seq)).limit(1);
1587
1815
  return row ? eventFromRow(row) : void 0;
1588
1816
  }
1589
1817
  async loadMessageHistory(conversationId) {
1590
1818
  const [compactionRow] = await this.executor.db().select().from(juniorConversationEvents).where(
1591
- and4(
1592
- eq4(juniorConversationEvents.conversationId, conversationId),
1593
- eq4(juniorConversationEvents.type, "messages_summarized")
1819
+ and6(
1820
+ eq6(juniorConversationEvents.conversationId, conversationId),
1821
+ eq6(juniorConversationEvents.type, "messages_summarized")
1594
1822
  )
1595
1823
  ).orderBy(desc2(juniorConversationEvents.seq)).limit(1);
1596
1824
  const compaction = compactionRow ? messagesSummarizedEventFromRow(compactionRow) : void 0;
1597
1825
  const historyFromSeq = compaction?.data.historyFromSeq ?? 0;
1598
1826
  const rows = await this.executor.db().select().from(juniorConversationEvents).where(
1599
- and4(
1600
- eq4(juniorConversationEvents.conversationId, conversationId),
1601
- inArray(juniorConversationEvents.type, messageHistoryEventTypes),
1827
+ and6(
1828
+ eq6(juniorConversationEvents.conversationId, conversationId),
1829
+ inArray2(juniorConversationEvents.type, messageHistoryEventTypes),
1602
1830
  gte(juniorConversationEvents.seq, historyFromSeq)
1603
1831
  )
1604
1832
  ).orderBy(asc2(juniorConversationEvents.seq));
1605
1833
  return { events: rows.map(eventFromRow), compaction, historyFromSeq };
1606
1834
  }
1607
1835
  async loadHistory(conversationId) {
1608
- const rows = await this.executor.db().select().from(juniorConversationEvents).where(eq4(juniorConversationEvents.conversationId, conversationId)).orderBy(asc2(juniorConversationEvents.seq));
1836
+ const rows = await this.executor.db().select().from(juniorConversationEvents).where(eq6(juniorConversationEvents.conversationId, conversationId)).orderBy(asc2(juniorConversationEvents.seq));
1609
1837
  return rows.map(eventFromRow);
1610
1838
  }
1611
1839
  async query(conversationId, query) {
@@ -1615,9 +1843,9 @@ var SqlConversationEventStore = class {
1615
1843
  if (query.afterSeq !== void 0 && query.beforeSeq !== void 0 && query.afterSeq >= query.beforeSeq) {
1616
1844
  return { events: [], hasOlder: false, hasNewer: false };
1617
1845
  }
1618
- const typeFilter = query.types && query.types.length > 0 ? inArray(juniorConversationEvents.type, [...query.types]) : void 0;
1619
- const bounds = and4(
1620
- eq4(juniorConversationEvents.conversationId, conversationId),
1846
+ const typeFilter = query.types && query.types.length > 0 ? inArray2(juniorConversationEvents.type, [...query.types]) : void 0;
1847
+ const bounds = and6(
1848
+ eq6(juniorConversationEvents.conversationId, conversationId),
1621
1849
  query.afterSeq === void 0 ? void 0 : gt(juniorConversationEvents.seq, query.afterSeq),
1622
1850
  query.beforeSeq === void 0 ? void 0 : lt(juniorConversationEvents.seq, query.beforeSeq),
1623
1851
  typeFilter
@@ -1654,8 +1882,8 @@ var SqlConversationEventStore = class {
1654
1882
  return false;
1655
1883
  }
1656
1884
  const [row] = await this.executor.db().select({ seq: juniorConversationEvents.seq }).from(juniorConversationEvents).where(
1657
- and4(
1658
- eq4(juniorConversationEvents.conversationId, args.conversationId),
1885
+ and6(
1886
+ eq6(juniorConversationEvents.conversationId, args.conversationId),
1659
1887
  args.afterSeq === void 0 ? void 0 : gt(juniorConversationEvents.seq, args.afterSeq),
1660
1888
  args.beforeSeq === void 0 ? void 0 : lt(juniorConversationEvents.seq, args.beforeSeq),
1661
1889
  args.typeFilter
@@ -1666,9 +1894,9 @@ var SqlConversationEventStore = class {
1666
1894
  /** Read the next sequence and active model-history version. */
1667
1895
  async readCursor(conversationId) {
1668
1896
  const rows = await this.executor.db().select({
1669
- maxSeq: sql4`max(${juniorConversationEvents.seq})`,
1670
- maxHistoryVersion: sql4`max(${juniorConversationEvents.historyVersion})`
1671
- }).from(juniorConversationEvents).where(eq4(juniorConversationEvents.conversationId, conversationId));
1897
+ maxSeq: sql6`max(${juniorConversationEvents.seq})`,
1898
+ maxHistoryVersion: sql6`max(${juniorConversationEvents.historyVersion})`
1899
+ }).from(juniorConversationEvents).where(eq6(juniorConversationEvents.conversationId, conversationId));
1672
1900
  const maxSeq = rows[0]?.maxSeq;
1673
1901
  const maxHistoryVersion = rows[0]?.maxHistoryVersion;
1674
1902
  return {
@@ -1682,7 +1910,7 @@ function createSqlConversationEventStore(executor) {
1682
1910
  }
1683
1911
 
1684
1912
  // src/chat/conversations/sql/message-search.ts
1685
- import { and as and5, desc as desc3, eq as eq5, isNull as isNull2, ne, sql as sql5 } from "drizzle-orm";
1913
+ import { and as and7, desc as desc3, eq as eq7, isNull as isNull2, ne, sql as sql7 } from "drizzle-orm";
1686
1914
  var EXCERPT_WITHOUT_QUERY_CHARS = 240;
1687
1915
  var SqlConversationMessageSearchStore = class {
1688
1916
  constructor(executor) {
@@ -1692,29 +1920,29 @@ var SqlConversationMessageSearchStore = class {
1692
1920
  async search(args) {
1693
1921
  const db = this.executor.db();
1694
1922
  const query = args.filters.query?.trim() || void 0;
1695
- const text = sql5`${juniorConversationEvents.payload}->>'text'`;
1696
- const role = sql5`${juniorConversationEvents.payload}->>'role'`;
1697
- const messageId = sql5`${juniorConversationEvents.payload}->>'messageId'`;
1698
- const tsquery = query ? sql5`websearch_to_tsquery('english', ${query})` : void 0;
1699
- const rank = tsquery ? sql5`ts_rank_cd(to_tsvector('english', ${text}), ${tsquery})` : sql5`1`;
1700
- const excerpt = tsquery ? sql5`ts_headline('english', ${text}, ${tsquery}, 'MaxFragments=2, MinWords=8, MaxWords=40, FragmentDelimiter=" … ", StartSel=**, StopSel=**')` : sql5`left(${text}, ${EXCERPT_WITHOUT_QUERY_CHARS})`;
1923
+ const text = sql7`${juniorConversationEvents.payload}->>'text'`;
1924
+ const role = sql7`${juniorConversationEvents.payload}->>'role'`;
1925
+ const messageId = sql7`${juniorConversationEvents.payload}->>'messageId'`;
1926
+ const tsquery = query ? sql7`websearch_to_tsquery('english', ${query})` : void 0;
1927
+ const rank = tsquery ? sql7`ts_rank_cd(to_tsvector('english', ${text}), ${tsquery})` : sql7`1`;
1928
+ const excerpt = tsquery ? sql7`ts_headline('english', ${text}, ${tsquery}, 'MaxFragments=2, MinWords=8, MaxWords=40, FragmentDelimiter=" … ", StartSel=**, StopSel=**')` : sql7`left(${text}, ${EXCERPT_WITHOUT_QUERY_CHARS})`;
1701
1929
  const conditions = [
1702
- eq5(juniorConversations.source, "slack"),
1930
+ eq7(juniorConversations.source, "slack"),
1703
1931
  isNull2(juniorConversations.parentConversationId),
1704
1932
  isNull2(juniorConversations.transcriptPurgedAt),
1705
1933
  ne(juniorConversations.conversationId, args.currentConversationId),
1706
- eq5(juniorDestinations.provider, args.scope.provider),
1707
- eq5(juniorDestinations.providerTenantId, args.scope.providerTenantId),
1708
- eq5(juniorDestinations.visibility, "public"),
1709
- eq5(juniorConversationEvents.type, "message"),
1710
- sql5`${role} in ('user', 'assistant')`
1934
+ eq7(juniorDestinations.provider, args.scope.provider),
1935
+ eq7(juniorDestinations.providerTenantId, args.scope.providerTenantId),
1936
+ eq7(juniorDestinations.visibility, "public"),
1937
+ eq7(juniorConversationEvents.type, "message"),
1938
+ sql7`${role} in ('user', 'assistant')`
1711
1939
  ];
1712
1940
  if (tsquery) {
1713
- conditions.push(sql5`to_tsvector('english', ${text}) @@ ${tsquery}`);
1941
+ conditions.push(sql7`to_tsvector('english', ${text}) @@ ${tsquery}`);
1714
1942
  }
1715
1943
  if (args.filters.channelId) {
1716
1944
  conditions.push(
1717
- eq5(juniorDestinations.providerDestinationId, args.filters.channelId)
1945
+ eq7(juniorDestinations.providerDestinationId, args.filters.channelId)
1718
1946
  );
1719
1947
  }
1720
1948
  const bestPerConversation = db.selectDistinctOn([juniorConversations.conversationId], {
@@ -1729,14 +1957,14 @@ var SqlConversationMessageSearchStore = class {
1729
1957
  role: role.as("role")
1730
1958
  }).from(juniorConversationEvents).innerJoin(
1731
1959
  juniorConversations,
1732
- eq5(
1960
+ eq7(
1733
1961
  juniorConversations.conversationId,
1734
1962
  juniorConversationEvents.conversationId
1735
1963
  )
1736
1964
  ).innerJoin(
1737
1965
  juniorDestinations,
1738
- eq5(juniorDestinations.id, juniorConversations.destinationId)
1739
- ).where(and5(...conditions)).orderBy(
1966
+ eq7(juniorDestinations.id, juniorConversations.destinationId)
1967
+ ).where(and7(...conditions)).orderBy(
1740
1968
  juniorConversations.conversationId,
1741
1969
  desc3(rank),
1742
1970
  desc3(juniorConversationEvents.createdAt)
@@ -1771,22 +1999,22 @@ function createDb(args) {
1771
1999
  });
1772
2000
  }
1773
2001
  function getSqlExecutor() {
1774
- const { sql: sql6 } = getChatConfig();
1775
- if (current?.databaseUrl !== sql6.databaseUrl || current.driver !== sql6.driver || current.statementTimeoutMs !== sql6.statementTimeoutMs) {
2002
+ const { sql: sql8 } = getChatConfig();
2003
+ if (current?.databaseUrl !== sql8.databaseUrl || current.driver !== sql8.driver || current.statementTimeoutMs !== sql8.statementTimeoutMs) {
1776
2004
  if (current) {
1777
2005
  const previous = current;
1778
2006
  current = void 0;
1779
2007
  void previous.db.close().catch(() => void 0);
1780
2008
  }
1781
2009
  const db = createDb({
1782
- databaseUrl: sql6.databaseUrl,
1783
- driver: sql6.driver,
1784
- statementTimeoutMs: sql6.statementTimeoutMs
2010
+ databaseUrl: sql8.databaseUrl,
2011
+ driver: sql8.driver,
2012
+ statementTimeoutMs: sql8.statementTimeoutMs
1785
2013
  });
1786
2014
  current = {
1787
- databaseUrl: sql6.databaseUrl,
1788
- driver: sql6.driver,
1789
- statementTimeoutMs: sql6.statementTimeoutMs,
2015
+ databaseUrl: sql8.databaseUrl,
2016
+ driver: sql8.driver,
2017
+ statementTimeoutMs: sql8.statementTimeoutMs,
1790
2018
  db,
1791
2019
  store: createSqlStore(db),
1792
2020
  eventStore: createSqlConversationEventStore(db),