@sentry/junior 0.202.0 → 0.204.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.
- package/dist/agent-CMyTD4DD.js +17509 -0
- package/dist/agent-hooks-Bbcp9e33.js +4040 -0
- package/dist/agent-runner-DNb1A49M.js +678 -0
- package/dist/api/schema.d.ts +2728 -2639
- package/dist/api/schema.js +4 -169
- package/dist/api.d.ts +23 -17
- package/dist/api.js +3881 -5326
- package/dist/app-B1TOqBI8.d.ts +246 -0
- package/dist/app.d.ts +4 -520
- package/dist/app.js +9522 -11875
- package/dist/auth-pause-state-DosEalIG.js +168 -0
- package/dist/catalog-runtime-BReos-D4.js +7 -0
- package/dist/checkpoint-CNrPyRJN.js +2450 -0
- package/dist/cli/chat.d.ts +20 -0
- package/dist/cli/chat.js +229 -336
- package/dist/cli/check.d.ts +8 -0
- package/dist/cli/check.js +513 -806
- package/dist/cli/env.d.ts +13 -0
- package/dist/cli/env.js +63 -12
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.js +90 -159
- package/dist/cli/main.d.ts +6 -0
- package/dist/cli/main.js +43 -64
- package/dist/cli/plugins.d.ts +13 -0
- package/dist/cli/plugins.js +148 -227
- package/dist/cli/run.d.ts +16 -0
- package/dist/cli/run.js +52 -8
- package/dist/cli/snapshot-create.d.ts +4 -0
- package/dist/cli/snapshot-create.js +71 -125
- package/dist/cli/upgrade.d.ts +15 -0
- package/dist/cli/upgrade.js +232 -335
- package/dist/config-nGCW1OTG.js +941 -0
- package/dist/context-B45_WqVX.js +298 -0
- package/dist/conversation-privacy-B4voFRSm.js +182 -0
- package/dist/conversation-work-C6y3T5Hx.js +51 -0
- package/dist/credential-sync-kXr1hvO1.js +2660 -0
- package/dist/db-BeyXKJOI.d.ts +5 -0
- package/dist/destinations-BeBiJeEM.js +29 -0
- package/dist/execution-stats-DWfSihcH.js +373 -0
- package/dist/executor-DcMSlI5c.js +721 -0
- package/dist/experimental-CIXf7Uye.js +46 -0
- package/dist/history-ClE4toxe.d.ts +32 -0
- package/dist/history-CqTuSAdI.js +441 -0
- package/dist/instrumentation.d.ts +3 -3
- package/dist/instrumentation.js +130 -176
- package/dist/job-queue-Drn_LXlM.js +63 -0
- package/dist/logging-BzAk1S_s.js +1210 -0
- package/dist/model-profile-CZmVoGdX.js +49 -0
- package/dist/nitro.d.ts +31 -36
- package/dist/nitro.js +275 -456
- package/dist/oauth-callback-server-JiftokvA.js +130 -0
- package/dist/oauth-relay-CdCnu80W.js +62 -0
- package/dist/package-discovery-7a9YqLhE.js +455 -0
- package/dist/pending-auth-CWmSdZVg.js +185 -0
- package/dist/plugin-module-BKGOXca2.js +81 -0
- package/dist/plugins-BI9A1vKA.d.ts +95 -0
- package/dist/plugins-egKWjgue.js +99 -0
- package/dist/private-trace-result-BLvBjy_e.js +16 -0
- package/dist/profile-CrT5nXbw.js +861 -0
- package/dist/registry-DH1xUo2N.js +1419 -0
- package/dist/reporting-schema-DosTN__Q.js +105 -0
- package/dist/resolve-CZHnfxaS.js +546 -0
- package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
- package/dist/runner-CZV2sC46.js +392 -0
- package/dist/sandbox-egress-signals-bHZfmhbd.js +46 -0
- package/dist/schema-Rn8-XEaN.js +1140 -0
- package/dist/sentry-CD3SdJl-.js +26 -0
- package/dist/skills-CIcDQSgM.js +316 -0
- package/dist/spawn-DdkUFRmq.js +29 -0
- package/dist/stats-DTUbAb88.js +2634 -0
- package/dist/store-C5qxF2ac.d.ts +208 -0
- package/dist/task-queue-CJIR4RF7.js +136 -0
- package/dist/task-runner-D-O3A-Cp.js +639 -0
- package/dist/thread-state-CRc9jTJS.js +431 -0
- package/dist/turn-execution-BkinIdJF.js +47 -0
- package/dist/turn-lifecycle-DQV19VTW.js +54 -0
- package/dist/usage-D3EbSO7w.js +296 -0
- package/dist/usage-schema-CKaDkH_j.js +20 -0
- package/dist/validation-C2CR-OX3.js +40 -0
- package/dist/vercel-queue-DIkVcfK4.js +167 -0
- package/dist/vercel.d.ts +6 -6
- package/dist/vercel.js +14 -6
- package/dist/version-CnXZ614E.d.ts +5 -0
- package/dist/version-DxcWdoKa.js +8 -0
- package/dist/version.d.ts +2 -4
- package/dist/version.js +2 -6
- package/dist/web-authorization-RMBxAR_t.js +76 -0
- package/dist/web-input-3EPfpf55.js +494 -0
- package/dist/work-fGofI7Op.js +509 -0
- package/dist/worker-CsOLq-mR.js +625 -0
- package/package.json +9 -9
- package/dist/agent-hooks-UXITLYOK.js +0 -51
- package/dist/catalog-runtime-BG3JLLK2.js +0 -14
- package/dist/chunk-2LYHWMR4.js +0 -46
- package/dist/chunk-2MK3QBGA.js +0 -321
- package/dist/chunk-3PGQSKJV.js +0 -692
- package/dist/chunk-3UI3WFTX.js +0 -519
- package/dist/chunk-3Y47VMHV.js +0 -6
- package/dist/chunk-4UO6FK4G.js +0 -64
- package/dist/chunk-5NOPO64K.js +0 -198
- package/dist/chunk-5PKWYPFT.js +0 -2943
- package/dist/chunk-63NKKFJL.js +0 -1228
- package/dist/chunk-6AYH6252.js +0 -787
- package/dist/chunk-6Y5B5PEX.js +0 -80
- package/dist/chunk-7DHZP5KJ.js +0 -333
- package/dist/chunk-7H2VZTWN.js +0 -103
- package/dist/chunk-7NL7T6VU.js +0 -406
- package/dist/chunk-A76OIMYN.js +0 -102
- package/dist/chunk-AWMS3SPP.js +0 -58
- package/dist/chunk-B3LY5RCL.js +0 -229
- package/dist/chunk-BD2KT3OB.js +0 -36
- package/dist/chunk-BXCX5QKA.js +0 -2086
- package/dist/chunk-C6VVF43U.js +0 -81
- package/dist/chunk-CEMMLV5L.js +0 -98
- package/dist/chunk-CM5HNV2W.js +0 -131
- package/dist/chunk-DA2KGZZI.js +0 -13
- package/dist/chunk-DBVY6HLX.js +0 -64
- package/dist/chunk-DIB4GX3G.js +0 -8
- package/dist/chunk-DKIJ2RP5.js +0 -68
- package/dist/chunk-DL2KLKVH.js +0 -931
- package/dist/chunk-DWPN6SCH.js +0 -172
- package/dist/chunk-ELWOYVOY.js +0 -206
- package/dist/chunk-EWT7H65X.js +0 -506
- package/dist/chunk-FA6POGLH.js +0 -70
- package/dist/chunk-HMREVIO2.js +0 -135
- package/dist/chunk-IIWUT4FO.js +0 -820
- package/dist/chunk-JAL3CH4G.js +0 -27
- package/dist/chunk-JSJQEWBJ.js +0 -3295
- package/dist/chunk-KHKKHDLD.js +0 -387
- package/dist/chunk-LA6R4A7Q.js +0 -706
- package/dist/chunk-LOOU2DUR.js +0 -20428
- package/dist/chunk-M6FHWXE3.js +0 -700
- package/dist/chunk-M76HMB7M.js +0 -1856
- package/dist/chunk-MAGNK5J4.js +0 -1520
- package/dist/chunk-MTM5IFCY.js +0 -1190
- package/dist/chunk-N7TMSOZH.js +0 -235
- package/dist/chunk-NHJU2ZAL.js +0 -56
- package/dist/chunk-NSXKRGRT.js +0 -717
- package/dist/chunk-OWMPFXJA.js +0 -1764
- package/dist/chunk-PDO5BLNM.js +0 -22
- package/dist/chunk-PEQXYSSE.js +0 -45
- package/dist/chunk-PW4P4JYF.js +0 -1135
- package/dist/chunk-QB54UQUS.js +0 -320
- package/dist/chunk-QP3OGJXF.js +0 -105
- package/dist/chunk-RC745GGZ.js +0 -122
- package/dist/chunk-REOIRYPR.js +0 -37
- package/dist/chunk-SCOZRLZ4.js +0 -164
- package/dist/chunk-TXJSXBV5.js +0 -1433
- package/dist/chunk-TXKUKMVO.js +0 -417
- package/dist/chunk-U2GPUYAL.js +0 -3656
- package/dist/chunk-UIE3R5XU.js +0 -17
- package/dist/chunk-UXPG6ZIN.js +0 -84
- package/dist/chunk-VFUK3X5B.js +0 -50
- package/dist/chunk-WQSHDTTI.js +0 -1163
- package/dist/chunk-X6GDDWQH.js +0 -60
- package/dist/chunk-Y2CM7HXH.js +0 -111
- package/dist/chunk-Y7X25LFY.js +0 -15
- package/dist/chunk-YDUR3ZYW.js +0 -10
- package/dist/conversation-work-VIOQ5ZF3.js +0 -54
- package/dist/db-3L2MCVRI.js +0 -26
- package/dist/discovery-DWVDM7UK.js +0 -44
- package/dist/experimental-P5FZM4CU.js +0 -12
- package/dist/oauth-callback-server-YVV6C6T2.js +0 -243
- package/dist/oauth-relay-5XPVRPYB.js +0 -8
- package/dist/plugins-YTYJMMJF.js +0 -14
- package/dist/runner-LQ7RETDP.js +0 -522
- package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
- package/dist/sentry-MB3NL3IR.js +0 -42
- package/dist/skills-XRWYEDCD.js +0 -27
- package/dist/spawn-RC6SJUAI.js +0 -42
- package/dist/task-runner-7DY7ARYH.js +0 -36
- package/dist/validation-7MNQGCJA.js +0 -17
- package/dist/work-COALHUCG.js +0 -51
- package/dist/worker-6MURZIPD.js +0 -24
package/dist/chunk-M76HMB7M.js
DELETED
|
@@ -1,1856 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
conversationReadColumns,
|
|
3
|
-
createJuniorSqlExecutor,
|
|
4
|
-
juniorConversationAnnotations,
|
|
5
|
-
juniorConversationBindings,
|
|
6
|
-
juniorConversationEvents,
|
|
7
|
-
juniorConversationParticipants,
|
|
8
|
-
juniorConversations,
|
|
9
|
-
juniorIdentities,
|
|
10
|
-
juniorUsers
|
|
11
|
-
} from "./chunk-PW4P4JYF.js";
|
|
12
|
-
import {
|
|
13
|
-
conversationEventDataSchema,
|
|
14
|
-
decodeStoredConversationEvent,
|
|
15
|
-
historyReplacementSchema,
|
|
16
|
-
newConversationEventSchema
|
|
17
|
-
} from "./chunk-7NL7T6VU.js";
|
|
18
|
-
import {
|
|
19
|
-
juniorDestinations
|
|
20
|
-
} from "./chunk-VFUK3X5B.js";
|
|
21
|
-
import {
|
|
22
|
-
getChatConfig
|
|
23
|
-
} from "./chunk-63NKKFJL.js";
|
|
24
|
-
import {
|
|
25
|
-
parseActorUserId,
|
|
26
|
-
parseSlackChannelReferenceId,
|
|
27
|
-
parseSlackTeamId
|
|
28
|
-
} from "./chunk-N7TMSOZH.js";
|
|
29
|
-
import {
|
|
30
|
-
normalizeIdentityEmail
|
|
31
|
-
} from "./chunk-MAGNK5J4.js";
|
|
32
|
-
|
|
33
|
-
// src/chat/conversations/sql/store.ts
|
|
34
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
35
|
-
import { and as and4, asc, desc, eq as eq4, isNull, sql as sql3 } from "drizzle-orm";
|
|
36
|
-
|
|
37
|
-
// src/chat/destination.ts
|
|
38
|
-
import {
|
|
39
|
-
destinationSchema
|
|
40
|
-
} from "@sentry/junior-plugin-api";
|
|
41
|
-
function createSlackDestination(input) {
|
|
42
|
-
const channelId = parseSlackChannelReferenceId(input.channelId);
|
|
43
|
-
const teamId = parseSlackTeamId(input.teamId);
|
|
44
|
-
if (!channelId || !teamId) {
|
|
45
|
-
return void 0;
|
|
46
|
-
}
|
|
47
|
-
return { platform: "slack", teamId, channelId };
|
|
48
|
-
}
|
|
49
|
-
function parseDestination(value) {
|
|
50
|
-
const parsed = destinationSchema.safeParse(value);
|
|
51
|
-
return parsed.success ? parsed.data : void 0;
|
|
52
|
-
}
|
|
53
|
-
function requireSlackDestination(destination, action) {
|
|
54
|
-
if (destination?.platform === "slack") {
|
|
55
|
-
return destination;
|
|
56
|
-
}
|
|
57
|
-
throw new Error(`${action} requires a Slack destination`);
|
|
58
|
-
}
|
|
59
|
-
function sameDestination(left, right) {
|
|
60
|
-
if (left.platform !== right.platform) {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
if (left.platform === "local" && right.platform === "local") {
|
|
64
|
-
return left.conversationId === right.conversationId;
|
|
65
|
-
}
|
|
66
|
-
if (left.platform === "slack" && right.platform === "slack") {
|
|
67
|
-
return left.teamId === right.teamId && left.channelId === right.channelId;
|
|
68
|
-
}
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// src/chat/identities/sql.ts
|
|
73
|
-
import { randomUUID } from "crypto";
|
|
74
|
-
import { and, eq, sql } from "drizzle-orm";
|
|
75
|
-
function dateFromMs(ms) {
|
|
76
|
-
return new Date(ms);
|
|
77
|
-
}
|
|
78
|
-
function tenantId(value) {
|
|
79
|
-
return value ?? "";
|
|
80
|
-
}
|
|
81
|
-
async function upsertUser(executor, args) {
|
|
82
|
-
const rows = await executor.db().insert(juniorUsers).values({
|
|
83
|
-
id: randomUUID(),
|
|
84
|
-
primaryEmail: args.email,
|
|
85
|
-
primaryEmailNormalized: args.emailNormalized,
|
|
86
|
-
displayName: args.displayName ?? null,
|
|
87
|
-
createdAt: dateFromMs(args.nowMs),
|
|
88
|
-
updatedAt: dateFromMs(args.nowMs)
|
|
89
|
-
}).onConflictDoUpdate({
|
|
90
|
-
target: juniorUsers.primaryEmailNormalized,
|
|
91
|
-
set: {
|
|
92
|
-
displayName: sql`coalesce(${juniorUsers.displayName}, excluded.display_name)`,
|
|
93
|
-
updatedAt: sql`excluded.updated_at`
|
|
94
|
-
}
|
|
95
|
-
}).returning({ id: juniorUsers.id });
|
|
96
|
-
const id = rows[0]?.id;
|
|
97
|
-
if (!id) {
|
|
98
|
-
throw new Error("User identity upsert returned no row");
|
|
99
|
-
}
|
|
100
|
-
return id;
|
|
101
|
-
}
|
|
102
|
-
async function existingIdentity(executor, identity) {
|
|
103
|
-
const rows = await executor.db().select().from(juniorIdentities).where(
|
|
104
|
-
and(
|
|
105
|
-
eq(juniorIdentities.provider, identity.provider),
|
|
106
|
-
eq(
|
|
107
|
-
juniorIdentities.providerTenantId,
|
|
108
|
-
tenantId(identity.providerTenantId)
|
|
109
|
-
),
|
|
110
|
-
eq(juniorIdentities.providerSubjectId, identity.providerSubjectId)
|
|
111
|
-
)
|
|
112
|
-
);
|
|
113
|
-
return rows[0];
|
|
114
|
-
}
|
|
115
|
-
async function upsertIdentityRecord(executor, identity, linkedUserId, nowMs) {
|
|
116
|
-
const emailNormalized = normalizeIdentityEmail(identity.email);
|
|
117
|
-
const email = emailNormalized ? identity.email?.trim() || emailNormalized : void 0;
|
|
118
|
-
const existing = await existingIdentity(executor, identity);
|
|
119
|
-
const userEmailNormalized = existing?.emailVerified && existing.emailNormalized ? existing.emailNormalized : identity.emailVerified ? emailNormalized : void 0;
|
|
120
|
-
const userEmail = existing?.emailVerified && existing.email ? existing.email : email ?? userEmailNormalized;
|
|
121
|
-
const verifiedUserId = identity.kind === "user" && userEmailNormalized ? await upsertUser(executor, {
|
|
122
|
-
email: userEmail ?? userEmailNormalized,
|
|
123
|
-
emailNormalized: userEmailNormalized,
|
|
124
|
-
nowMs,
|
|
125
|
-
...existing?.displayName || identity.displayName ? { displayName: existing?.displayName ?? identity.displayName } : void 0
|
|
126
|
-
}) : void 0;
|
|
127
|
-
if (existing?.userId && verifiedUserId && existing.userId !== verifiedUserId) {
|
|
128
|
-
throw new Error("Identity verified email conflicts with linked user");
|
|
129
|
-
}
|
|
130
|
-
if (linkedUserId && verifiedUserId && linkedUserId !== verifiedUserId) {
|
|
131
|
-
throw new Error("Linked identity conflicts with verified email user");
|
|
132
|
-
}
|
|
133
|
-
if (existing?.userId && linkedUserId && existing.userId !== linkedUserId) {
|
|
134
|
-
throw new Error("Identity conflicts with linked user");
|
|
135
|
-
}
|
|
136
|
-
const userId = existing?.userId ?? linkedUserId ?? verifiedUserId;
|
|
137
|
-
const rows = await executor.db().insert(juniorIdentities).values({
|
|
138
|
-
id: randomUUID(),
|
|
139
|
-
userId: userId ?? null,
|
|
140
|
-
kind: identity.kind,
|
|
141
|
-
provider: identity.provider,
|
|
142
|
-
providerTenantId: tenantId(identity.providerTenantId),
|
|
143
|
-
providerSubjectId: identity.providerSubjectId,
|
|
144
|
-
displayName: identity.displayName ?? null,
|
|
145
|
-
handle: identity.handle ?? null,
|
|
146
|
-
email: email ?? null,
|
|
147
|
-
emailNormalized: emailNormalized ?? null,
|
|
148
|
-
emailVerified: Boolean(identity.emailVerified && emailNormalized),
|
|
149
|
-
avatarUrl: null,
|
|
150
|
-
metadata: identity.metadata ?? null,
|
|
151
|
-
createdAt: dateFromMs(nowMs),
|
|
152
|
-
updatedAt: dateFromMs(nowMs)
|
|
153
|
-
}).onConflictDoUpdate({
|
|
154
|
-
target: [
|
|
155
|
-
juniorIdentities.provider,
|
|
156
|
-
juniorIdentities.providerTenantId,
|
|
157
|
-
juniorIdentities.providerSubjectId
|
|
158
|
-
],
|
|
159
|
-
set: {
|
|
160
|
-
kind: sql`excluded.kind`,
|
|
161
|
-
userId: sql`coalesce(${juniorIdentities.userId}, excluded.user_id)`,
|
|
162
|
-
displayName: linkedUserId ? sql`coalesce(excluded.display_name, ${juniorIdentities.displayName})` : sql`coalesce(${juniorIdentities.displayName}, excluded.display_name)`,
|
|
163
|
-
handle: linkedUserId ? sql`coalesce(excluded.handle, ${juniorIdentities.handle})` : sql`coalesce(${juniorIdentities.handle}, excluded.handle)`,
|
|
164
|
-
email: sql`case when ${juniorIdentities.emailVerified} then coalesce(${juniorIdentities.email}, excluded.email) when excluded.email_verified then excluded.email else coalesce(${juniorIdentities.email}, excluded.email) end`,
|
|
165
|
-
emailNormalized: sql`case when ${juniorIdentities.emailVerified} then coalesce(${juniorIdentities.emailNormalized}, excluded.email_normalized) when excluded.email_verified then excluded.email_normalized else coalesce(${juniorIdentities.emailNormalized}, excluded.email_normalized) end`,
|
|
166
|
-
emailVerified: sql`${juniorIdentities.emailVerified} OR excluded.email_verified`,
|
|
167
|
-
avatarUrl: sql`coalesce(${juniorIdentities.avatarUrl}, excluded.avatar_url)`,
|
|
168
|
-
metadata: sql`coalesce(${juniorIdentities.metadata}, excluded.metadata_json)`,
|
|
169
|
-
updatedAt: sql`excluded.updated_at`
|
|
170
|
-
},
|
|
171
|
-
...linkedUserId ? {
|
|
172
|
-
setWhere: sql`${juniorIdentities.userId} IS NULL OR ${juniorIdentities.userId} = excluded.user_id`
|
|
173
|
-
} : void 0
|
|
174
|
-
}).returning({
|
|
175
|
-
id: juniorIdentities.id,
|
|
176
|
-
userId: juniorIdentities.userId
|
|
177
|
-
});
|
|
178
|
-
const row = rows[0];
|
|
179
|
-
if (!row) {
|
|
180
|
-
if (linkedUserId) {
|
|
181
|
-
throw new Error("Identity conflicts with linked user");
|
|
182
|
-
}
|
|
183
|
-
throw new Error("Identity upsert returned no row");
|
|
184
|
-
}
|
|
185
|
-
return {
|
|
186
|
-
id: row.id,
|
|
187
|
-
...row.userId ? { userId: row.userId } : void 0
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
async function upsertIdentity(executor, identity, nowMs = Date.now()) {
|
|
191
|
-
return await upsertIdentityRecord(executor, identity, void 0, nowMs);
|
|
192
|
-
}
|
|
193
|
-
async function upsertLinkedIdentity(executor, userId, identity, nowMs = Date.now()) {
|
|
194
|
-
return await upsertIdentityRecord(executor, identity, userId, nowMs);
|
|
195
|
-
}
|
|
196
|
-
async function deleteProviderIdentityForSlackUser(executor, slackTeamId, slackUserId, provider, providerSubjectId) {
|
|
197
|
-
const slackRows = await executor.db().select({ userId: juniorIdentities.userId }).from(juniorIdentities).where(
|
|
198
|
-
and(
|
|
199
|
-
eq(juniorIdentities.kind, "user"),
|
|
200
|
-
eq(juniorIdentities.provider, "slack"),
|
|
201
|
-
eq(juniorIdentities.providerTenantId, slackTeamId),
|
|
202
|
-
eq(juniorIdentities.providerSubjectId, slackUserId)
|
|
203
|
-
)
|
|
204
|
-
).limit(1);
|
|
205
|
-
const userId = slackRows[0]?.userId;
|
|
206
|
-
if (!userId) return;
|
|
207
|
-
await executor.db().delete(juniorIdentities).where(
|
|
208
|
-
and(
|
|
209
|
-
eq(juniorIdentities.userId, userId),
|
|
210
|
-
eq(juniorIdentities.provider, provider),
|
|
211
|
-
eq(juniorIdentities.providerTenantId, ""),
|
|
212
|
-
eq(juniorIdentities.providerSubjectId, providerSubjectId)
|
|
213
|
-
)
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// src/chat/conversations/sql/participants.ts
|
|
218
|
-
import { and as and2, eq as eq2, inArray, sql as sql2 } from "drizzle-orm";
|
|
219
|
-
async function resolveRootConversationId(executor, conversationId) {
|
|
220
|
-
const [row] = await executor.db().select({
|
|
221
|
-
rootConversationId: juniorConversations.rootConversationId
|
|
222
|
-
}).from(juniorConversations).where(eq2(juniorConversations.conversationId, conversationId)).limit(1);
|
|
223
|
-
return row?.rootConversationId ?? conversationId;
|
|
224
|
-
}
|
|
225
|
-
async function recordConversationParticipant(executor, args) {
|
|
226
|
-
const [identity] = await executor.db().select({
|
|
227
|
-
kind: juniorIdentities.kind,
|
|
228
|
-
userId: juniorIdentities.userId
|
|
229
|
-
}).from(juniorIdentities).where(eq2(juniorIdentities.id, args.actorIdentityId)).limit(1);
|
|
230
|
-
if (!identity?.userId || identity.kind !== "user") {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
const rootConversationId = await resolveRootConversationId(
|
|
234
|
-
executor,
|
|
235
|
-
args.conversationId
|
|
236
|
-
);
|
|
237
|
-
const at = new Date(args.atMs);
|
|
238
|
-
await executor.db().insert(juniorConversationParticipants).values({
|
|
239
|
-
userId: identity.userId,
|
|
240
|
-
rootConversationId,
|
|
241
|
-
lastMessageAt: at
|
|
242
|
-
}).onConflictDoUpdate({
|
|
243
|
-
target: [
|
|
244
|
-
juniorConversationParticipants.userId,
|
|
245
|
-
juniorConversationParticipants.rootConversationId
|
|
246
|
-
],
|
|
247
|
-
set: {
|
|
248
|
-
lastMessageAt: sql2`greatest(${juniorConversationParticipants.lastMessageAt}, excluded.last_message_at)`,
|
|
249
|
-
...args.restoreArchive ? { archivedAt: null } : void 0
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// src/chat/source.ts
|
|
255
|
-
import { sourceSchema } from "@sentry/junior-plugin-api";
|
|
256
|
-
function normalizeSessionSource(value) {
|
|
257
|
-
if (!value) {
|
|
258
|
-
return void 0;
|
|
259
|
-
}
|
|
260
|
-
if (value.kind === "local") {
|
|
261
|
-
return {
|
|
262
|
-
kind: "local",
|
|
263
|
-
visibility: value.visibility,
|
|
264
|
-
conversationId: value.conversationId
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
if (value.kind === "web") {
|
|
268
|
-
return {
|
|
269
|
-
kind: "web",
|
|
270
|
-
visibility: value.visibility,
|
|
271
|
-
conversationId: value.conversationId
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
if (value.kind === "resource_event" || value.kind === "scheduled_task" || value.kind === "event_task" || value.kind === "plugin_dispatch" || value.kind === "agent_invocation") {
|
|
275
|
-
return void 0;
|
|
276
|
-
}
|
|
277
|
-
const threadTs = value.threadTs?.trim();
|
|
278
|
-
return {
|
|
279
|
-
kind: "slack",
|
|
280
|
-
visibility: value.visibility,
|
|
281
|
-
teamId: value.teamId,
|
|
282
|
-
channelId: value.channelId,
|
|
283
|
-
...threadTs ? { threadTs } : void 0
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
function parseSessionSource(value) {
|
|
287
|
-
const parsed = sourceSchema.safeParse(value);
|
|
288
|
-
return parsed.success ? normalizeSessionSource(parsed.data) : void 0;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// src/chat/conversations/sql/bindings.ts
|
|
292
|
-
import { and as and3, eq as eq3 } from "drizzle-orm";
|
|
293
|
-
async function getConversationIdByProviderConversation(executor, args) {
|
|
294
|
-
const rows = await executor.db().select({ conversationId: juniorConversationBindings.conversationId }).from(juniorConversationBindings).where(
|
|
295
|
-
and3(
|
|
296
|
-
eq3(juniorConversationBindings.provider, args.provider),
|
|
297
|
-
eq3(juniorConversationBindings.providerTenantId, args.providerTenantId),
|
|
298
|
-
eq3(
|
|
299
|
-
juniorConversationBindings.providerDestinationId,
|
|
300
|
-
args.providerDestinationId
|
|
301
|
-
),
|
|
302
|
-
eq3(
|
|
303
|
-
juniorConversationBindings.providerConversationId,
|
|
304
|
-
args.providerConversationId
|
|
305
|
-
)
|
|
306
|
-
)
|
|
307
|
-
).limit(1);
|
|
308
|
-
return rows[0]?.conversationId;
|
|
309
|
-
}
|
|
310
|
-
async function bindProviderConversation(executor, args) {
|
|
311
|
-
const rows = await executor.db().insert(juniorConversationBindings).values({ ...args, createdAt: /* @__PURE__ */ new Date() }).onConflictDoNothing().returning({ conversationId: juniorConversationBindings.conversationId });
|
|
312
|
-
const boundConversationId = rows[0]?.conversationId ?? await getConversationIdByProviderConversation(executor, args);
|
|
313
|
-
if (boundConversationId !== args.conversationId) {
|
|
314
|
-
throw new Error(
|
|
315
|
-
"Provider conversation is already bound to another conversation"
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// src/chat/conversations/sql/actor-identity.ts
|
|
321
|
-
function identityFromActor(actor) {
|
|
322
|
-
if (actor?.slackUserId) {
|
|
323
|
-
return {
|
|
324
|
-
kind: "user",
|
|
325
|
-
provider: "slack",
|
|
326
|
-
providerTenantId: actor.teamId,
|
|
327
|
-
providerSubjectId: actor.slackUserId,
|
|
328
|
-
...actor.fullName ? { displayName: actor.fullName } : void 0,
|
|
329
|
-
...actor.slackUserName ? { handle: actor.slackUserName } : void 0,
|
|
330
|
-
...actor.email ? { email: actor.email, emailVerified: true } : void 0,
|
|
331
|
-
metadata: { platform: "slack" }
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
const email = actor?.email?.trim().toLowerCase();
|
|
335
|
-
if (!email) {
|
|
336
|
-
return void 0;
|
|
337
|
-
}
|
|
338
|
-
return {
|
|
339
|
-
kind: "user",
|
|
340
|
-
provider: "junior",
|
|
341
|
-
providerSubjectId: email,
|
|
342
|
-
email,
|
|
343
|
-
emailVerified: true,
|
|
344
|
-
...actor?.fullName ? { displayName: actor.fullName } : void 0,
|
|
345
|
-
metadata: { platform: "web" }
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
function systemIdentityFromSource(source) {
|
|
349
|
-
if (source === "scheduler") {
|
|
350
|
-
return {
|
|
351
|
-
kind: "system",
|
|
352
|
-
provider: "junior",
|
|
353
|
-
providerSubjectId: "scheduler",
|
|
354
|
-
displayName: "Junior Scheduler"
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
if (source === "local") {
|
|
358
|
-
return {
|
|
359
|
-
kind: "system",
|
|
360
|
-
provider: "junior",
|
|
361
|
-
providerSubjectId: "local-cli",
|
|
362
|
-
displayName: "Local CLI"
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
if (source === "resource_event") {
|
|
366
|
-
return {
|
|
367
|
-
kind: "system",
|
|
368
|
-
provider: "junior",
|
|
369
|
-
providerSubjectId: "resource-event",
|
|
370
|
-
displayName: "Resource Event"
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
return void 0;
|
|
374
|
-
}
|
|
375
|
-
function actorIdentityForConversation(conversation) {
|
|
376
|
-
return identityFromActor(conversation.actor) ?? systemIdentityFromSource(conversation.source);
|
|
377
|
-
}
|
|
378
|
-
function actorFromIdentityRow(identity, userDisplayName) {
|
|
379
|
-
if (!identity) {
|
|
380
|
-
return void 0;
|
|
381
|
-
}
|
|
382
|
-
const fullName = userDisplayName?.trim() ? userDisplayName : identity.displayName;
|
|
383
|
-
const email = identity.emailNormalized ?? identity.email ?? void 0;
|
|
384
|
-
if (identity.provider === "slack") {
|
|
385
|
-
return {
|
|
386
|
-
...email ? { email } : void 0,
|
|
387
|
-
...fullName ? { fullName } : void 0,
|
|
388
|
-
platform: "slack",
|
|
389
|
-
slackUserId: identity.providerSubjectId,
|
|
390
|
-
...identity.handle ? { slackUserName: identity.handle } : void 0,
|
|
391
|
-
...identity.providerTenantId ? { teamId: identity.providerTenantId } : void 0
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
if (identity.provider === "junior" && email) {
|
|
395
|
-
return {
|
|
396
|
-
email,
|
|
397
|
-
...fullName ? { fullName } : void 0
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
return void 0;
|
|
401
|
-
}
|
|
402
|
-
function mergeActor(current2, next) {
|
|
403
|
-
if (!current2) {
|
|
404
|
-
return next;
|
|
405
|
-
}
|
|
406
|
-
if (!next) {
|
|
407
|
-
return current2;
|
|
408
|
-
}
|
|
409
|
-
if (current2.slackUserId && next.slackUserId && current2.slackUserId !== next.slackUserId) {
|
|
410
|
-
return current2;
|
|
411
|
-
}
|
|
412
|
-
return {
|
|
413
|
-
...current2,
|
|
414
|
-
...current2.email ?? next.email ? { email: current2.email ?? next.email } : void 0,
|
|
415
|
-
...current2.fullName ?? next.fullName ? { fullName: current2.fullName ?? next.fullName } : void 0,
|
|
416
|
-
...current2.platform ?? next.platform ? { platform: current2.platform ?? next.platform } : void 0,
|
|
417
|
-
...current2.slackUserId ?? next.slackUserId ? { slackUserId: current2.slackUserId ?? next.slackUserId } : void 0,
|
|
418
|
-
...current2.slackUserName ?? next.slackUserName ? { slackUserName: current2.slackUserName ?? next.slackUserName } : void 0,
|
|
419
|
-
...current2.teamId ?? next.teamId ? { teamId: current2.teamId ?? next.teamId } : void 0
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// src/chat/conversations/location.ts
|
|
424
|
-
import { locationSchema } from "@sentry/junior-plugin-api";
|
|
425
|
-
|
|
426
|
-
// src/chat/conversations/sql/location.ts
|
|
427
|
-
function locationForWrite(args) {
|
|
428
|
-
const location = args.location ? locationSchema.parse(args.location) : void 0;
|
|
429
|
-
const destination = args.destination?.platform === "slack" ? args.destination : void 0;
|
|
430
|
-
const source = args.sessionSource?.kind === "slack" ? args.sessionSource : void 0;
|
|
431
|
-
if (location) {
|
|
432
|
-
if (destination && (location.id !== args.destinationId || location.teamId !== destination.teamId || location.channelId !== destination.channelId) || source && (location.teamId !== source.teamId || location.channelId !== source.channelId)) {
|
|
433
|
-
throw new Error("Conversation Location changed");
|
|
434
|
-
}
|
|
435
|
-
return source?.threadTs && !location.threadTs ? { ...location, threadTs: source.threadTs } : location;
|
|
436
|
-
}
|
|
437
|
-
if (destination && source && (destination.teamId !== source.teamId || destination.channelId !== source.channelId)) {
|
|
438
|
-
throw new Error("Conversation Location does not match its session Source");
|
|
439
|
-
}
|
|
440
|
-
if (!destination || !args.destinationId) {
|
|
441
|
-
return void 0;
|
|
442
|
-
}
|
|
443
|
-
return locationSchema.parse({
|
|
444
|
-
id: args.destinationId,
|
|
445
|
-
provider: "slack",
|
|
446
|
-
teamId: destination.teamId,
|
|
447
|
-
channelId: destination.channelId,
|
|
448
|
-
...source?.threadTs ? { threadTs: source.threadTs } : void 0
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
function locationFromRow(value, row, sessionSource) {
|
|
452
|
-
if (value !== void 0 && value !== null) {
|
|
453
|
-
const location = locationSchema.parse(value);
|
|
454
|
-
const slackSource2 = !location.threadTs && sessionSource?.kind === "slack" && sessionSource.teamId === location.teamId && sessionSource.channelId === location.channelId ? sessionSource : void 0;
|
|
455
|
-
return slackSource2?.threadTs ? { ...location, threadTs: slackSource2.threadTs } : location;
|
|
456
|
-
}
|
|
457
|
-
if (!row || row.provider === "local") {
|
|
458
|
-
return void 0;
|
|
459
|
-
}
|
|
460
|
-
if (row.provider !== "slack") {
|
|
461
|
-
throw new Error("Conversation Location provider is not supported");
|
|
462
|
-
}
|
|
463
|
-
const slackSource = sessionSource?.kind === "slack" && sessionSource.teamId === row.providerTenantId && sessionSource.channelId === row.providerDestinationId ? sessionSource : void 0;
|
|
464
|
-
return locationSchema.parse({
|
|
465
|
-
id: row.id,
|
|
466
|
-
provider: "slack",
|
|
467
|
-
teamId: row.providerTenantId,
|
|
468
|
-
channelId: row.providerDestinationId,
|
|
469
|
-
...slackSource?.threadTs ? { threadTs: slackSource.threadTs } : void 0
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
function visibilityFromLocationRow(row) {
|
|
473
|
-
if (!row) {
|
|
474
|
-
return void 0;
|
|
475
|
-
}
|
|
476
|
-
if (row.visibility === "public" || row.visibility === "private") {
|
|
477
|
-
return row.visibility;
|
|
478
|
-
}
|
|
479
|
-
return void 0;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// src/chat/conversations/sql/store.ts
|
|
483
|
-
var CONVERSATION_MUTATION_LOCK_PREFIX = "junior_conversation";
|
|
484
|
-
async function withConversationMutationLock(executor, conversationId, callback) {
|
|
485
|
-
return await executor.withLock(
|
|
486
|
-
`${CONVERSATION_MUTATION_LOCK_PREFIX}:${conversationId}`,
|
|
487
|
-
async () => await executor.transaction(callback)
|
|
488
|
-
);
|
|
489
|
-
}
|
|
490
|
-
function now() {
|
|
491
|
-
return Date.now();
|
|
492
|
-
}
|
|
493
|
-
function dateFromMs2(ms) {
|
|
494
|
-
return new Date(ms);
|
|
495
|
-
}
|
|
496
|
-
function msFromDate(value) {
|
|
497
|
-
if (value === null || value === void 0) {
|
|
498
|
-
return void 0;
|
|
499
|
-
}
|
|
500
|
-
const date = value instanceof Date ? value : new Date(value);
|
|
501
|
-
return date.getTime();
|
|
502
|
-
}
|
|
503
|
-
function requiredMsFromDate(value) {
|
|
504
|
-
const ms = msFromDate(value);
|
|
505
|
-
if (typeof ms !== "number" || Number.isNaN(ms)) {
|
|
506
|
-
throw new Error("Conversation record timestamp is invalid");
|
|
507
|
-
}
|
|
508
|
-
return ms;
|
|
509
|
-
}
|
|
510
|
-
function tenantId2(value) {
|
|
511
|
-
return value ?? "";
|
|
512
|
-
}
|
|
513
|
-
function sourceFromValue(value) {
|
|
514
|
-
if (value === "api" || value === "internal" || value === "local" || value === "plugin" || value === "resource_event" || value === "scheduler" || value === "slack" || value === "web") {
|
|
515
|
-
return value;
|
|
516
|
-
}
|
|
517
|
-
return void 0;
|
|
518
|
-
}
|
|
519
|
-
function originTypeFromSource(source) {
|
|
520
|
-
return source;
|
|
521
|
-
}
|
|
522
|
-
function localWorkspaceFromConversationId(conversationId) {
|
|
523
|
-
const match = /^local:([^:]+):/.exec(conversationId);
|
|
524
|
-
return match?.[1];
|
|
525
|
-
}
|
|
526
|
-
function destinationUpsertFromDestination(args) {
|
|
527
|
-
const { destination } = args;
|
|
528
|
-
if (!destination) {
|
|
529
|
-
return void 0;
|
|
530
|
-
}
|
|
531
|
-
if (destination.platform === "slack") {
|
|
532
|
-
const channelId = destination.channelId;
|
|
533
|
-
const channelKind = channelId.startsWith("D") ? "dm" : channelId.startsWith("G") ? "group" : "channel";
|
|
534
|
-
return {
|
|
535
|
-
kind: channelKind,
|
|
536
|
-
provider: "slack",
|
|
537
|
-
providerTenantId: destination.teamId,
|
|
538
|
-
providerDestinationId: channelId,
|
|
539
|
-
refreshVisibility: args.visibility !== void 0,
|
|
540
|
-
visibility: args.visibility ?? "unknown",
|
|
541
|
-
...args.channelName ? { displayName: args.channelName } : void 0,
|
|
542
|
-
metadata: { platform: "slack" }
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
return {
|
|
546
|
-
kind: "local_conversation",
|
|
547
|
-
provider: "local",
|
|
548
|
-
providerTenantId: localWorkspaceFromConversationId(destination.conversationId) ?? localWorkspaceFromConversationId(args.conversationId ?? ""),
|
|
549
|
-
providerDestinationId: destination.conversationId,
|
|
550
|
-
// Match Slack: only refresh when a live visibility signal is present so
|
|
551
|
-
// execution-metadata writes cannot clobber public dashboard roots.
|
|
552
|
-
refreshVisibility: args.visibility !== void 0,
|
|
553
|
-
visibility: args.visibility ?? "direct",
|
|
554
|
-
metadata: { platform: "local" }
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
function executionStatusFromValue(value) {
|
|
558
|
-
if (value === "awaiting_resume" || value === "paused") return "paused";
|
|
559
|
-
if (value === "failed" || value === "idle" || value === "pending" || value === "running") {
|
|
560
|
-
return value;
|
|
561
|
-
}
|
|
562
|
-
throw new Error("Conversation record execution status is invalid");
|
|
563
|
-
}
|
|
564
|
-
function executionStatusToSql(status) {
|
|
565
|
-
return status === "paused" ? "awaiting_resume" : status;
|
|
566
|
-
}
|
|
567
|
-
function destinationFromRow(destination) {
|
|
568
|
-
const value = destination?.provider === "slack" ? {
|
|
569
|
-
platform: "slack",
|
|
570
|
-
teamId: destination.providerTenantId,
|
|
571
|
-
channelId: destination.providerDestinationId
|
|
572
|
-
} : destination?.provider === "local" ? {
|
|
573
|
-
platform: "local",
|
|
574
|
-
conversationId: destination.providerDestinationId
|
|
575
|
-
} : void 0;
|
|
576
|
-
return parseDestination(value);
|
|
577
|
-
}
|
|
578
|
-
function conversationFromRow(readRow) {
|
|
579
|
-
const row = readRow.conversation;
|
|
580
|
-
const visibility = visibilityFromLocationRow(readRow.destination);
|
|
581
|
-
if (row.schemaVersion !== 1) {
|
|
582
|
-
throw new Error("Conversation record schema version is invalid");
|
|
583
|
-
}
|
|
584
|
-
if (row.destination !== null && readRow.destination === null) {
|
|
585
|
-
throw new Error("Conversation legacy destination is not migrated");
|
|
586
|
-
}
|
|
587
|
-
if (row.actor !== null && readRow.actorIdentity === null) {
|
|
588
|
-
throw new Error("Conversation legacy actor is not migrated");
|
|
589
|
-
}
|
|
590
|
-
const destination = destinationFromRow(readRow.destination);
|
|
591
|
-
const actor = actorFromIdentityRow(
|
|
592
|
-
readRow.actorIdentity,
|
|
593
|
-
readRow.actorUserDisplayName
|
|
594
|
-
);
|
|
595
|
-
if (readRow.destination !== null && !destination) {
|
|
596
|
-
throw new Error("Conversation record destination is invalid");
|
|
597
|
-
}
|
|
598
|
-
const source = row.source === void 0 || row.source === null ? void 0 : sourceFromValue(row.source);
|
|
599
|
-
if (row.source !== void 0 && row.source !== null && !source) {
|
|
600
|
-
throw new Error("Conversation record source is invalid");
|
|
601
|
-
}
|
|
602
|
-
const sessionSource = row.sessionSource === void 0 || row.sessionSource === null ? void 0 : parseSessionSource(row.sessionSource);
|
|
603
|
-
if (row.sessionSource !== void 0 && row.sessionSource !== null && !sessionSource) {
|
|
604
|
-
throw new Error("Conversation record session source is invalid");
|
|
605
|
-
}
|
|
606
|
-
const execution = {
|
|
607
|
-
status: executionStatusFromValue(row.executionStatus),
|
|
608
|
-
lastCheckpointAtMs: msFromDate(row.lastCheckpointAt),
|
|
609
|
-
lastEnqueuedAtMs: msFromDate(row.lastEnqueuedAt),
|
|
610
|
-
...row.runId ? { runId: row.runId } : void 0,
|
|
611
|
-
updatedAtMs: msFromDate(row.executionUpdatedAt) ?? requiredMsFromDate(row.updatedAt)
|
|
612
|
-
};
|
|
613
|
-
const location = locationFromRow(
|
|
614
|
-
row.location,
|
|
615
|
-
readRow.destination,
|
|
616
|
-
sessionSource
|
|
617
|
-
);
|
|
618
|
-
return {
|
|
619
|
-
schemaVersion: 1,
|
|
620
|
-
conversationId: row.conversationId,
|
|
621
|
-
createdAtMs: requiredMsFromDate(row.createdAt),
|
|
622
|
-
lastActivityAtMs: requiredMsFromDate(row.lastActivityAt),
|
|
623
|
-
updatedAtMs: requiredMsFromDate(row.updatedAt),
|
|
624
|
-
execution,
|
|
625
|
-
executionMetrics: {
|
|
626
|
-
durationMs: row.executionDurationMs,
|
|
627
|
-
...row.metricRunId ? { runId: row.metricRunId } : void 0,
|
|
628
|
-
...row.executionUsage ? { usage: row.executionUsage } : void 0
|
|
629
|
-
},
|
|
630
|
-
...row.parentConversationId ? { parentConversationId: row.parentConversationId } : void 0,
|
|
631
|
-
...destination ? { destination } : void 0,
|
|
632
|
-
...location ? { location } : void 0,
|
|
633
|
-
...actor ? { actor } : void 0,
|
|
634
|
-
...row.channelName ? { channelName: row.channelName } : void 0,
|
|
635
|
-
...source ? { source } : void 0,
|
|
636
|
-
...sessionSource ? { sessionSource } : void 0,
|
|
637
|
-
...row.title ? { title: row.title } : void 0,
|
|
638
|
-
...msFromDate(row.transcriptPurgedAt) !== void 0 ? { transcriptPurgedAtMs: msFromDate(row.transcriptPurgedAt) } : void 0,
|
|
639
|
-
...visibility ? { visibility } : void 0
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
function emptyConversation(args) {
|
|
643
|
-
return {
|
|
644
|
-
schemaVersion: 1,
|
|
645
|
-
conversationId: args.conversationId,
|
|
646
|
-
createdAtMs: args.nowMs,
|
|
647
|
-
lastActivityAtMs: args.nowMs,
|
|
648
|
-
updatedAtMs: args.nowMs,
|
|
649
|
-
...args.destination ? { destination: args.destination } : void 0,
|
|
650
|
-
...args.source ? { source: args.source } : void 0,
|
|
651
|
-
...args.sessionSource ? { sessionSource: args.sessionSource } : void 0,
|
|
652
|
-
execution: {
|
|
653
|
-
status: "idle",
|
|
654
|
-
updatedAtMs: args.nowMs
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
function assertSameConversationDestination(args) {
|
|
659
|
-
if (!args.current || sameDestination(args.current, args.next)) {
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
throw new Error(
|
|
663
|
-
`Conversation destination changed for ${args.conversationId}`
|
|
664
|
-
);
|
|
665
|
-
}
|
|
666
|
-
function tokenTotal(usage) {
|
|
667
|
-
if (!usage) return 0;
|
|
668
|
-
if (usage.totalTokens !== void 0) return usage.totalTokens;
|
|
669
|
-
return (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0) + (usage.cachedInputTokens ?? 0) + (usage.cacheCreationTokens ?? 0);
|
|
670
|
-
}
|
|
671
|
-
function updateConversationUsage(args) {
|
|
672
|
-
const usage = {
|
|
673
|
-
totalTokens: tokenTotal(args.current) - tokenTotal(args.previousExecution) + tokenTotal(args.nextExecution)
|
|
674
|
-
};
|
|
675
|
-
if (args.current?.reasoningTokens !== void 0 || args.previousExecution?.reasoningTokens !== void 0 || args.nextExecution.reasoningTokens !== void 0) {
|
|
676
|
-
usage.reasoningTokens = (args.current?.reasoningTokens ?? 0) - (args.previousExecution?.reasoningTokens ?? 0) + (args.nextExecution.reasoningTokens ?? 0);
|
|
677
|
-
}
|
|
678
|
-
const costFields = [
|
|
679
|
-
"input",
|
|
680
|
-
"output",
|
|
681
|
-
"cacheRead",
|
|
682
|
-
"cacheWrite",
|
|
683
|
-
"total"
|
|
684
|
-
];
|
|
685
|
-
const cost = {};
|
|
686
|
-
for (const field of costFields) {
|
|
687
|
-
if (args.current?.cost?.[field] === void 0 && args.previousExecution?.cost?.[field] === void 0 && args.nextExecution.cost?.[field] === void 0) {
|
|
688
|
-
continue;
|
|
689
|
-
}
|
|
690
|
-
cost[field] = Math.round(
|
|
691
|
-
((args.current?.cost?.[field] ?? 0) - (args.previousExecution?.cost?.[field] ?? 0) + (args.nextExecution.cost?.[field] ?? 0)) * 1e12
|
|
692
|
-
) / 1e12;
|
|
693
|
-
}
|
|
694
|
-
if (Object.keys(cost).length > 0) usage.cost = cost;
|
|
695
|
-
return usage;
|
|
696
|
-
}
|
|
697
|
-
var SqlStore = class {
|
|
698
|
-
constructor(executor) {
|
|
699
|
-
this.executor = executor;
|
|
700
|
-
}
|
|
701
|
-
executor;
|
|
702
|
-
async getConversationIdByProviderConversation(args) {
|
|
703
|
-
return await getConversationIdByProviderConversation(this.executor, args);
|
|
704
|
-
}
|
|
705
|
-
async bindProviderConversation(args) {
|
|
706
|
-
await bindProviderConversation(this.executor, args);
|
|
707
|
-
}
|
|
708
|
-
async createChild(args) {
|
|
709
|
-
const nowMs = args.nowMs ?? now();
|
|
710
|
-
await this.withConversationMutation(args.parentConversationId, async () => {
|
|
711
|
-
await this.withConversationMutation(
|
|
712
|
-
args.childConversationId,
|
|
713
|
-
async () => {
|
|
714
|
-
const existing = await this.get({
|
|
715
|
-
conversationId: args.childConversationId
|
|
716
|
-
});
|
|
717
|
-
if (existing) {
|
|
718
|
-
if (existing.parentConversationId !== args.parentConversationId) {
|
|
719
|
-
throw new Error(
|
|
720
|
-
`Conversation parent changed for ${args.childConversationId}`
|
|
721
|
-
);
|
|
722
|
-
}
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
const parent = await this.get({
|
|
726
|
-
conversationId: args.parentConversationId
|
|
727
|
-
});
|
|
728
|
-
if (!parent) {
|
|
729
|
-
throw new Error(
|
|
730
|
-
`Conversation parent is missing for ${args.childConversationId}`
|
|
731
|
-
);
|
|
732
|
-
}
|
|
733
|
-
if (parent.parentConversationId) {
|
|
734
|
-
throw new Error("Recursive agent delegation is not enabled");
|
|
735
|
-
}
|
|
736
|
-
const child = {
|
|
737
|
-
...emptyConversation({
|
|
738
|
-
conversationId: args.childConversationId,
|
|
739
|
-
nowMs,
|
|
740
|
-
source: args.source
|
|
741
|
-
}),
|
|
742
|
-
parentConversationId: args.parentConversationId
|
|
743
|
-
};
|
|
744
|
-
await this.upsertConversation({ conversation: child });
|
|
745
|
-
}
|
|
746
|
-
);
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
async get(args) {
|
|
750
|
-
const row = await this.readConversationRow(args.conversationId);
|
|
751
|
-
if (!row) {
|
|
752
|
-
return void 0;
|
|
753
|
-
}
|
|
754
|
-
return conversationFromRow(row);
|
|
755
|
-
}
|
|
756
|
-
async recordActivity(args) {
|
|
757
|
-
const nowMs = args.nowMs ?? now();
|
|
758
|
-
const activityAtMs = args.activityAtMs ?? nowMs;
|
|
759
|
-
const sessionSource = normalizeSessionSource(args.sessionSource);
|
|
760
|
-
await this.withConversationMutation(args.conversationId, async () => {
|
|
761
|
-
const existing = await this.get({
|
|
762
|
-
conversationId: args.conversationId
|
|
763
|
-
});
|
|
764
|
-
if (existing && args.destination) {
|
|
765
|
-
assertSameConversationDestination({
|
|
766
|
-
conversationId: args.conversationId,
|
|
767
|
-
current: existing.destination,
|
|
768
|
-
next: args.destination
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
const current2 = existing ?? emptyConversation({
|
|
772
|
-
conversationId: args.conversationId,
|
|
773
|
-
destination: args.destination,
|
|
774
|
-
nowMs,
|
|
775
|
-
source: args.source,
|
|
776
|
-
...sessionSource ? { sessionSource } : void 0
|
|
777
|
-
});
|
|
778
|
-
const {
|
|
779
|
-
sessionSource: _persistedSessionSource,
|
|
780
|
-
visibility: _persistedVisibility,
|
|
781
|
-
...currentWithoutPersistedSignals
|
|
782
|
-
} = current2;
|
|
783
|
-
await this.upsertConversation({
|
|
784
|
-
conversation: {
|
|
785
|
-
...currentWithoutPersistedSignals,
|
|
786
|
-
destination: current2.destination ?? args.destination,
|
|
787
|
-
source: current2.source ?? args.source,
|
|
788
|
-
...sessionSource ? { sessionSource } : void 0,
|
|
789
|
-
channelName: current2.channelName ?? args.channelName,
|
|
790
|
-
actor: mergeActor(current2.actor, args.actor),
|
|
791
|
-
title: current2.title ?? args.title,
|
|
792
|
-
lastActivityAtMs: Math.max(current2.lastActivityAtMs, activityAtMs),
|
|
793
|
-
updatedAtMs: nowMs,
|
|
794
|
-
execution: {
|
|
795
|
-
...current2.execution,
|
|
796
|
-
updatedAtMs: current2.execution.updatedAtMs ?? nowMs
|
|
797
|
-
},
|
|
798
|
-
...args.visibility ? { visibility: args.visibility } : void 0
|
|
799
|
-
}
|
|
800
|
-
});
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
|
-
async recordExecution(args) {
|
|
804
|
-
await this.withConversationMutation(args.conversationId, async () => {
|
|
805
|
-
const existingRow = await this.readConversationRow(args.conversationId);
|
|
806
|
-
const existing = existingRow ? conversationFromRow(existingRow) : void 0;
|
|
807
|
-
if (!existing && !args.destination) {
|
|
808
|
-
return;
|
|
809
|
-
}
|
|
810
|
-
const incomingExecutionAt = args.execution.updatedAtMs ?? args.updatedAtMs;
|
|
811
|
-
const existingExecutionAt = existing?.execution.updatedAtMs ?? existing?.updatedAtMs ?? 0;
|
|
812
|
-
const incomingIsFresh = incomingExecutionAt >= existingExecutionAt;
|
|
813
|
-
const metricRunId = existingRow?.conversation.metricRunId;
|
|
814
|
-
const sameRun = Boolean(metricRunId) && metricRunId === args.execution.runId;
|
|
815
|
-
const execution = incomingIsFresh ? args.execution : existing?.execution ?? args.execution;
|
|
816
|
-
await this.upsertConversation({
|
|
817
|
-
conversation: {
|
|
818
|
-
schemaVersion: 1,
|
|
819
|
-
conversationId: args.conversationId,
|
|
820
|
-
createdAtMs: args.createdAtMs,
|
|
821
|
-
lastActivityAtMs: args.lastActivityAtMs,
|
|
822
|
-
updatedAtMs: args.updatedAtMs,
|
|
823
|
-
...existing?.parentConversationId ? { parentConversationId: existing.parentConversationId } : void 0,
|
|
824
|
-
...existing?.location ? { location: existing.location } : void 0,
|
|
825
|
-
...args.channelName ? { channelName: args.channelName } : void 0,
|
|
826
|
-
...args.destination ? { destination: args.destination } : void 0,
|
|
827
|
-
...args.actor ? { actor: args.actor } : void 0,
|
|
828
|
-
...args.source ? { source: args.source } : void 0,
|
|
829
|
-
...args.title ? { title: args.title } : void 0,
|
|
830
|
-
...args.visibility ? { visibility: args.visibility } : void 0,
|
|
831
|
-
execution
|
|
832
|
-
}
|
|
833
|
-
});
|
|
834
|
-
if (incomingIsFresh && args.metrics) {
|
|
835
|
-
const row = existingRow?.conversation;
|
|
836
|
-
const usage = args.metrics.usage ? updateConversationUsage({
|
|
837
|
-
current: row?.usage ?? void 0,
|
|
838
|
-
previousExecution: sameRun ? row?.executionUsage ?? void 0 : void 0,
|
|
839
|
-
nextExecution: args.metrics.usage
|
|
840
|
-
}) : row?.usage ?? void 0;
|
|
841
|
-
await this.executor.db().update(juniorConversations).set({
|
|
842
|
-
durationMs: (row?.durationMs ?? 0) - (sameRun ? row?.executionDurationMs ?? 0 : 0) + args.metrics.durationMs,
|
|
843
|
-
usage: usage ?? null,
|
|
844
|
-
metricRunId: args.execution.runId ?? null,
|
|
845
|
-
executionDurationMs: args.metrics.durationMs,
|
|
846
|
-
executionUsage: args.metrics.usage ?? (sameRun ? row?.executionUsage ?? null : null)
|
|
847
|
-
}).where(eq4(juniorConversations.conversationId, args.conversationId));
|
|
848
|
-
}
|
|
849
|
-
});
|
|
850
|
-
}
|
|
851
|
-
async listByActivity(args = {}) {
|
|
852
|
-
const rows = await this.executor.db().select({
|
|
853
|
-
conversation: conversationReadColumns(),
|
|
854
|
-
destination: juniorDestinations,
|
|
855
|
-
actorIdentity: juniorIdentities,
|
|
856
|
-
actorUserDisplayName: juniorUsers.displayName
|
|
857
|
-
}).from(juniorConversations).leftJoin(
|
|
858
|
-
juniorDestinations,
|
|
859
|
-
eq4(juniorDestinations.id, juniorConversations.destinationId)
|
|
860
|
-
).leftJoin(
|
|
861
|
-
juniorIdentities,
|
|
862
|
-
eq4(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
863
|
-
).leftJoin(juniorUsers, eq4(juniorUsers.id, juniorIdentities.userId)).where(isNull(juniorConversations.parentConversationId)).orderBy(
|
|
864
|
-
desc(juniorConversations.lastActivityAt),
|
|
865
|
-
asc(juniorConversations.conversationId)
|
|
866
|
-
).limit(Math.max(0, args.limit ?? 1e4)).offset(Math.max(0, args.offset ?? 0));
|
|
867
|
-
const conversations = [];
|
|
868
|
-
for (const row of rows) {
|
|
869
|
-
conversations.push(conversationFromRow(row));
|
|
870
|
-
}
|
|
871
|
-
return conversations;
|
|
872
|
-
}
|
|
873
|
-
async getDestinationVisibility(args) {
|
|
874
|
-
const rows = await this.executor.db().select({
|
|
875
|
-
visibility: juniorDestinations.visibility
|
|
876
|
-
}).from(juniorDestinations).where(
|
|
877
|
-
and4(
|
|
878
|
-
eq4(juniorDestinations.provider, args.provider),
|
|
879
|
-
eq4(
|
|
880
|
-
juniorDestinations.providerTenantId,
|
|
881
|
-
tenantId2(args.providerTenantId)
|
|
882
|
-
),
|
|
883
|
-
eq4(
|
|
884
|
-
juniorDestinations.providerDestinationId,
|
|
885
|
-
args.providerDestinationId
|
|
886
|
-
)
|
|
887
|
-
)
|
|
888
|
-
);
|
|
889
|
-
const row = rows[0];
|
|
890
|
-
if (!row) {
|
|
891
|
-
return void 0;
|
|
892
|
-
}
|
|
893
|
-
if (row.visibility === "public" || row.visibility === "private") {
|
|
894
|
-
return row.visibility;
|
|
895
|
-
}
|
|
896
|
-
return void 0;
|
|
897
|
-
}
|
|
898
|
-
async findSlackDestinationByName(args) {
|
|
899
|
-
const normalized = args.channelName.trim().replace(/^#/, "").toLowerCase();
|
|
900
|
-
if (!normalized) {
|
|
901
|
-
return void 0;
|
|
902
|
-
}
|
|
903
|
-
const rows = await this.executor.db().select({
|
|
904
|
-
channelId: juniorDestinations.providerDestinationId,
|
|
905
|
-
channelName: juniorDestinations.displayName
|
|
906
|
-
}).from(juniorDestinations).where(
|
|
907
|
-
and4(
|
|
908
|
-
eq4(juniorDestinations.provider, "slack"),
|
|
909
|
-
eq4(juniorDestinations.providerTenantId, tenantId2(args.teamId)),
|
|
910
|
-
eq4(juniorDestinations.kind, "channel"),
|
|
911
|
-
sql3`lower(ltrim(${juniorDestinations.displayName}, '#')) = ${normalized}`
|
|
912
|
-
)
|
|
913
|
-
).limit(2);
|
|
914
|
-
if (rows.length !== 1) {
|
|
915
|
-
return void 0;
|
|
916
|
-
}
|
|
917
|
-
const row = rows[0];
|
|
918
|
-
if (!row?.channelId) {
|
|
919
|
-
return void 0;
|
|
920
|
-
}
|
|
921
|
-
return {
|
|
922
|
-
channelId: row.channelId,
|
|
923
|
-
...row.channelName ? { channelName: row.channelName } : void 0
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
/** Serialize all durable mutations for one conversation inside a SQL transaction. */
|
|
927
|
-
async withConversationMutation(conversationId, callback) {
|
|
928
|
-
return await withConversationMutationLock(
|
|
929
|
-
this.executor,
|
|
930
|
-
conversationId,
|
|
931
|
-
callback
|
|
932
|
-
);
|
|
933
|
-
}
|
|
934
|
-
async readConversationRow(conversationId) {
|
|
935
|
-
const rows = await this.executor.db().select({
|
|
936
|
-
conversation: conversationReadColumns(),
|
|
937
|
-
destination: juniorDestinations,
|
|
938
|
-
actorIdentity: juniorIdentities,
|
|
939
|
-
actorUserDisplayName: juniorUsers.displayName
|
|
940
|
-
}).from(juniorConversations).leftJoin(
|
|
941
|
-
juniorDestinations,
|
|
942
|
-
eq4(juniorDestinations.id, juniorConversations.destinationId)
|
|
943
|
-
).leftJoin(
|
|
944
|
-
juniorIdentities,
|
|
945
|
-
eq4(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
946
|
-
).leftJoin(juniorUsers, eq4(juniorUsers.id, juniorIdentities.userId)).where(eq4(juniorConversations.conversationId, conversationId));
|
|
947
|
-
return rows[0];
|
|
948
|
-
}
|
|
949
|
-
/** Upsert the conversation row while preserving previously discovered nullable metadata fields. */
|
|
950
|
-
async upsertConversation(args) {
|
|
951
|
-
const { conversation } = args;
|
|
952
|
-
if (!conversation.parentConversationId && !conversation.destination) {
|
|
953
|
-
const existing = await this.get({
|
|
954
|
-
conversationId: conversation.conversationId
|
|
955
|
-
});
|
|
956
|
-
if (!existing) {
|
|
957
|
-
throw new Error(
|
|
958
|
-
`Conversation ${conversation.conversationId} requires a destination at create`
|
|
959
|
-
);
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
const incomingExecutionVersion = sql3`coalesce(excluded.execution_updated_at, excluded.updated_at)`;
|
|
963
|
-
const currentExecutionVersion = sql3`coalesce(${juniorConversations.executionUpdatedAt}, ${juniorConversations.updatedAt})`;
|
|
964
|
-
const incomingExecutionIsFresh = sql3`${incomingExecutionVersion} >= ${currentExecutionVersion}`;
|
|
965
|
-
const destinationId = await this.upsertDestination(
|
|
966
|
-
destinationUpsertFromDestination({
|
|
967
|
-
channelName: conversation.channelName,
|
|
968
|
-
conversationId: conversation.conversationId,
|
|
969
|
-
destination: conversation.destination,
|
|
970
|
-
...conversation.visibility ? { visibility: conversation.visibility } : void 0
|
|
971
|
-
}),
|
|
972
|
-
conversation.updatedAtMs
|
|
973
|
-
);
|
|
974
|
-
const location = locationForWrite({
|
|
975
|
-
destination: conversation.destination,
|
|
976
|
-
destinationId,
|
|
977
|
-
location: conversation.location,
|
|
978
|
-
sessionSource: conversation.sessionSource
|
|
979
|
-
});
|
|
980
|
-
const actorIdentityObservation = actorIdentityForConversation(conversation);
|
|
981
|
-
const actorIdentity = actorIdentityObservation ? await upsertIdentity(
|
|
982
|
-
this.executor,
|
|
983
|
-
actorIdentityObservation,
|
|
984
|
-
conversation.updatedAtMs
|
|
985
|
-
) : void 0;
|
|
986
|
-
const rootConversationId = conversation.parentConversationId ? sql3`(
|
|
987
|
-
select parent.root_conversation_id
|
|
988
|
-
from junior_conversations parent
|
|
989
|
-
where parent.conversation_id = ${conversation.parentConversationId}
|
|
990
|
-
)` : conversation.conversationId;
|
|
991
|
-
const rows = await this.executor.db().insert(juniorConversations).values({
|
|
992
|
-
conversationId: conversation.conversationId,
|
|
993
|
-
schemaVersion: 1,
|
|
994
|
-
source: conversation.source ?? null,
|
|
995
|
-
sessionSource: conversation.sessionSource ?? null,
|
|
996
|
-
originType: originTypeFromSource(conversation.source) ?? null,
|
|
997
|
-
originId: null,
|
|
998
|
-
originRunId: null,
|
|
999
|
-
location: location ?? null,
|
|
1000
|
-
destinationId: destinationId ?? null,
|
|
1001
|
-
destination: null,
|
|
1002
|
-
actorIdentityId: actorIdentity?.id ?? null,
|
|
1003
|
-
creatorIdentityId: null,
|
|
1004
|
-
credentialSubjectIdentityId: null,
|
|
1005
|
-
actor: null,
|
|
1006
|
-
channelName: conversation.channelName ?? null,
|
|
1007
|
-
title: conversation.title ?? null,
|
|
1008
|
-
createdAt: dateFromMs2(conversation.createdAtMs),
|
|
1009
|
-
lastActivityAt: dateFromMs2(conversation.lastActivityAtMs),
|
|
1010
|
-
updatedAt: dateFromMs2(conversation.updatedAtMs),
|
|
1011
|
-
executionUpdatedAt: conversation.execution.updatedAtMs === void 0 ? null : dateFromMs2(conversation.execution.updatedAtMs),
|
|
1012
|
-
executionStatus: executionStatusToSql(conversation.execution.status),
|
|
1013
|
-
runId: conversation.execution.runId ?? null,
|
|
1014
|
-
lastCheckpointAt: conversation.execution.lastCheckpointAtMs === void 0 ? null : dateFromMs2(conversation.execution.lastCheckpointAtMs),
|
|
1015
|
-
lastEnqueuedAt: conversation.execution.lastEnqueuedAtMs === void 0 ? null : dateFromMs2(conversation.execution.lastEnqueuedAtMs),
|
|
1016
|
-
parentConversationId: conversation.parentConversationId ?? null,
|
|
1017
|
-
rootConversationId
|
|
1018
|
-
}).onConflictDoUpdate({
|
|
1019
|
-
target: juniorConversations.conversationId,
|
|
1020
|
-
set: {
|
|
1021
|
-
// Origin source is set-once so dashboard continues cannot rewrite a Slack root.
|
|
1022
|
-
source: sql3`coalesce(${juniorConversations.source}, excluded.source)`,
|
|
1023
|
-
sessionSource: sql3`coalesce(${juniorConversations.sessionSource}, excluded.source_json)`,
|
|
1024
|
-
originType: sql3`coalesce(excluded.origin_type, ${juniorConversations.originType})`,
|
|
1025
|
-
originId: sql3`coalesce(excluded.origin_id, ${juniorConversations.originId})`,
|
|
1026
|
-
originRunId: sql3`coalesce(excluded.origin_run_id, ${juniorConversations.originRunId})`,
|
|
1027
|
-
location: sql3`coalesce(excluded.location_json, ${juniorConversations.location})`,
|
|
1028
|
-
destinationId: sql3`coalesce(excluded.destination_id, ${juniorConversations.destinationId})`,
|
|
1029
|
-
actorIdentityId: sql3`coalesce(excluded.actor_identity_id, ${juniorConversations.actorIdentityId})`,
|
|
1030
|
-
creatorIdentityId: sql3`coalesce(excluded.creator_identity_id, ${juniorConversations.creatorIdentityId})`,
|
|
1031
|
-
credentialSubjectIdentityId: sql3`coalesce(excluded.credential_subject_identity_id, ${juniorConversations.credentialSubjectIdentityId})`,
|
|
1032
|
-
channelName: sql3`coalesce(excluded.channel_name, ${juniorConversations.channelName})`,
|
|
1033
|
-
title: sql3`coalesce(excluded.title, ${juniorConversations.title})`,
|
|
1034
|
-
createdAt: sql3`least(${juniorConversations.createdAt}, excluded.created_at)`,
|
|
1035
|
-
lastActivityAt: sql3`greatest(${juniorConversations.lastActivityAt}, excluded.last_activity_at)`,
|
|
1036
|
-
updatedAt: sql3`greatest(${juniorConversations.updatedAt}, excluded.updated_at)`,
|
|
1037
|
-
executionUpdatedAt: sql3`case when ${incomingExecutionIsFresh} then excluded.execution_updated_at else ${juniorConversations.executionUpdatedAt} end`,
|
|
1038
|
-
executionStatus: sql3`case when ${incomingExecutionIsFresh} then excluded.execution_status else ${juniorConversations.executionStatus} end`,
|
|
1039
|
-
runId: sql3`case when ${incomingExecutionIsFresh} then excluded.run_id else ${juniorConversations.runId} end`,
|
|
1040
|
-
lastCheckpointAt: sql3`case when ${incomingExecutionIsFresh} then coalesce(excluded.last_checkpoint_at, ${juniorConversations.lastCheckpointAt}) else ${juniorConversations.lastCheckpointAt} end`,
|
|
1041
|
-
lastEnqueuedAt: sql3`case when ${incomingExecutionIsFresh} then coalesce(excluded.last_enqueued_at, ${juniorConversations.lastEnqueuedAt}) else ${juniorConversations.lastEnqueuedAt} end`,
|
|
1042
|
-
rootConversationId: sql3`coalesce(${juniorConversations.rootConversationId}, excluded.root_conversation_id)`
|
|
1043
|
-
}
|
|
1044
|
-
}).returning({
|
|
1045
|
-
actorIdentityId: juniorConversations.actorIdentityId,
|
|
1046
|
-
parentConversationId: juniorConversations.parentConversationId,
|
|
1047
|
-
rootConversationId: juniorConversations.rootConversationId
|
|
1048
|
-
});
|
|
1049
|
-
const row = rows[0];
|
|
1050
|
-
if (!row?.rootConversationId) {
|
|
1051
|
-
throw new Error("Conversation parent is missing its persisted root");
|
|
1052
|
-
}
|
|
1053
|
-
if (row.actorIdentityId && row.parentConversationId === null) {
|
|
1054
|
-
await recordConversationParticipant(this.executor, {
|
|
1055
|
-
actorIdentityId: row.actorIdentityId,
|
|
1056
|
-
conversationId: conversation.conversationId,
|
|
1057
|
-
atMs: conversation.lastActivityAtMs
|
|
1058
|
-
});
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
async upsertDestination(destination, nowMs) {
|
|
1062
|
-
if (!destination) {
|
|
1063
|
-
return void 0;
|
|
1064
|
-
}
|
|
1065
|
-
const visibilityUpdate = destination.refreshVisibility ? sql3`excluded.visibility` : juniorDestinations.visibility;
|
|
1066
|
-
const rows = await this.executor.db().insert(juniorDestinations).values({
|
|
1067
|
-
id: randomUUID2(),
|
|
1068
|
-
provider: destination.provider,
|
|
1069
|
-
providerTenantId: tenantId2(destination.providerTenantId),
|
|
1070
|
-
providerDestinationId: destination.providerDestinationId,
|
|
1071
|
-
kind: destination.kind,
|
|
1072
|
-
parentDestinationId: null,
|
|
1073
|
-
displayName: destination.displayName ?? null,
|
|
1074
|
-
visibility: destination.visibility,
|
|
1075
|
-
metadata: destination.metadata ?? null,
|
|
1076
|
-
createdAt: dateFromMs2(nowMs),
|
|
1077
|
-
updatedAt: dateFromMs2(nowMs)
|
|
1078
|
-
}).onConflictDoUpdate({
|
|
1079
|
-
target: [
|
|
1080
|
-
juniorDestinations.provider,
|
|
1081
|
-
juniorDestinations.providerTenantId,
|
|
1082
|
-
juniorDestinations.providerDestinationId
|
|
1083
|
-
],
|
|
1084
|
-
set: {
|
|
1085
|
-
kind: sql3`excluded.kind`,
|
|
1086
|
-
displayName: sql3`coalesce(excluded.display_name, ${juniorDestinations.displayName})`,
|
|
1087
|
-
// Signal-less writes remain unknown and must not clobber an existing
|
|
1088
|
-
// public/private value. Live source signals refresh this field so
|
|
1089
|
-
// converted channels converge on the next message.
|
|
1090
|
-
visibility: visibilityUpdate,
|
|
1091
|
-
metadata: sql3`coalesce(excluded.metadata_json, ${juniorDestinations.metadata})`,
|
|
1092
|
-
updatedAt: sql3`excluded.updated_at`
|
|
1093
|
-
}
|
|
1094
|
-
}).returning({ id: juniorDestinations.id });
|
|
1095
|
-
return rows[0]?.id;
|
|
1096
|
-
}
|
|
1097
|
-
};
|
|
1098
|
-
function createSqlStore(executor) {
|
|
1099
|
-
return new SqlStore(executor);
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
// src/chat/conversations/sql/history.ts
|
|
1103
|
-
import {
|
|
1104
|
-
and as and6,
|
|
1105
|
-
asc as asc2,
|
|
1106
|
-
desc as desc2,
|
|
1107
|
-
eq as eq6,
|
|
1108
|
-
gt,
|
|
1109
|
-
gte,
|
|
1110
|
-
inArray as inArray2,
|
|
1111
|
-
lt,
|
|
1112
|
-
lte,
|
|
1113
|
-
sql as sql6
|
|
1114
|
-
} from "drizzle-orm";
|
|
1115
|
-
|
|
1116
|
-
// src/chat/conversations/sql/conversation-row.ts
|
|
1117
|
-
import { sql as sql4 } from "drizzle-orm";
|
|
1118
|
-
async function ensureConversationRow(executor, conversationId, atMs, options = {}) {
|
|
1119
|
-
const at = new Date(atMs);
|
|
1120
|
-
const insert = executor.db().insert(juniorConversations).values({
|
|
1121
|
-
conversationId,
|
|
1122
|
-
createdAt: at,
|
|
1123
|
-
lastActivityAt: at,
|
|
1124
|
-
updatedAt: at,
|
|
1125
|
-
executionStatus: "idle"
|
|
1126
|
-
});
|
|
1127
|
-
if (options.activity === "preserve") {
|
|
1128
|
-
await insert.onConflictDoNothing({
|
|
1129
|
-
target: juniorConversations.conversationId
|
|
1130
|
-
});
|
|
1131
|
-
return;
|
|
1132
|
-
}
|
|
1133
|
-
await insert.onConflictDoUpdate({
|
|
1134
|
-
target: juniorConversations.conversationId,
|
|
1135
|
-
set: {
|
|
1136
|
-
lastActivityAt: sql4`greatest(${juniorConversations.lastActivityAt}, excluded.last_activity_at)`,
|
|
1137
|
-
updatedAt: sql4`greatest(${juniorConversations.updatedAt}, excluded.updated_at)`,
|
|
1138
|
-
transcriptPurgedAt: null
|
|
1139
|
-
}
|
|
1140
|
-
});
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
// src/chat/conversations/sql/event-actor.ts
|
|
1144
|
-
import { and as and5, eq as eq5, or, sql as sql5 } from "drizzle-orm";
|
|
1145
|
-
var SLACK_USER_ID_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
1146
|
-
function isRecord(value) {
|
|
1147
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1148
|
-
}
|
|
1149
|
-
function readAuthor(meta) {
|
|
1150
|
-
if (!isRecord(meta) || !isRecord(meta.author)) {
|
|
1151
|
-
return {};
|
|
1152
|
-
}
|
|
1153
|
-
const author = meta.author;
|
|
1154
|
-
return {
|
|
1155
|
-
...typeof author.email === "string" ? { email: author.email } : void 0,
|
|
1156
|
-
...typeof author.fullName === "string" ? { fullName: author.fullName } : void 0,
|
|
1157
|
-
...typeof author.isBot === "boolean" ? { isBot: author.isBot } : void 0,
|
|
1158
|
-
...typeof author.userId === "string" ? { userId: author.userId } : void 0,
|
|
1159
|
-
...typeof author.userName === "string" ? { userName: author.userName } : void 0
|
|
1160
|
-
};
|
|
1161
|
-
}
|
|
1162
|
-
async function loadConversationSlackTenantId(executor, conversationId) {
|
|
1163
|
-
const [row] = await executor.db().select({
|
|
1164
|
-
providerTenantId: juniorDestinations.providerTenantId,
|
|
1165
|
-
sessionSource: juniorConversations.sessionSource
|
|
1166
|
-
}).from(juniorConversations).leftJoin(
|
|
1167
|
-
juniorDestinations,
|
|
1168
|
-
eq5(juniorDestinations.id, juniorConversations.destinationId)
|
|
1169
|
-
).where(eq5(juniorConversations.conversationId, conversationId)).limit(1);
|
|
1170
|
-
const destinationTenant = row?.providerTenantId?.trim();
|
|
1171
|
-
if (destinationTenant) {
|
|
1172
|
-
return destinationTenant;
|
|
1173
|
-
}
|
|
1174
|
-
const sessionSource = parseSessionSource(row?.sessionSource);
|
|
1175
|
-
if (sessionSource?.kind === "slack") {
|
|
1176
|
-
return sessionSource.teamId;
|
|
1177
|
-
}
|
|
1178
|
-
return void 0;
|
|
1179
|
-
}
|
|
1180
|
-
async function findIdentityIdByProviderSubject(executor, args) {
|
|
1181
|
-
const rows = await executor.db().select({ id: juniorIdentities.id }).from(juniorIdentities).where(
|
|
1182
|
-
and5(
|
|
1183
|
-
eq5(juniorIdentities.provider, args.provider),
|
|
1184
|
-
eq5(juniorIdentities.providerSubjectId, args.providerSubjectId),
|
|
1185
|
-
args.providerTenantId === void 0 ? void 0 : eq5(juniorIdentities.providerTenantId, args.providerTenantId)
|
|
1186
|
-
)
|
|
1187
|
-
).limit(1);
|
|
1188
|
-
return rows[0]?.id;
|
|
1189
|
-
}
|
|
1190
|
-
async function findJuniorIdentityIdByEmail(executor, email) {
|
|
1191
|
-
const normalized = email.trim().toLowerCase();
|
|
1192
|
-
if (!normalized) return void 0;
|
|
1193
|
-
const rows = await executor.db().select({ id: juniorIdentities.id }).from(juniorIdentities).where(
|
|
1194
|
-
and5(
|
|
1195
|
-
eq5(juniorIdentities.provider, "junior"),
|
|
1196
|
-
eq5(juniorIdentities.kind, "user"),
|
|
1197
|
-
or(
|
|
1198
|
-
eq5(juniorIdentities.providerSubjectId, normalized),
|
|
1199
|
-
and5(
|
|
1200
|
-
eq5(juniorIdentities.emailNormalized, normalized),
|
|
1201
|
-
eq5(juniorIdentities.emailVerified, true)
|
|
1202
|
-
)
|
|
1203
|
-
)
|
|
1204
|
-
)
|
|
1205
|
-
).limit(1);
|
|
1206
|
-
return rows[0]?.id;
|
|
1207
|
-
}
|
|
1208
|
-
async function findJuniorIdentityIdByDashboardAuthorId(executor, dashboardAuthorId) {
|
|
1209
|
-
if (!dashboardAuthorId.startsWith("dashboard:")) {
|
|
1210
|
-
return void 0;
|
|
1211
|
-
}
|
|
1212
|
-
const rows = await executor.db().select({ id: juniorIdentities.id }).from(juniorIdentities).where(
|
|
1213
|
-
and5(
|
|
1214
|
-
eq5(juniorIdentities.provider, "junior"),
|
|
1215
|
-
eq5(juniorIdentities.kind, "user"),
|
|
1216
|
-
eq5(juniorIdentities.emailVerified, true),
|
|
1217
|
-
sql5`${juniorIdentities.emailNormalized} is not null`,
|
|
1218
|
-
// Match webActorFromEmail(): dashboard:${sha256(email).slice(0,24)}
|
|
1219
|
-
sql5`concat(
|
|
1220
|
-
'dashboard:',
|
|
1221
|
-
left(encode(digest(${juniorIdentities.emailNormalized}, 'sha256'), 'hex'), 24)
|
|
1222
|
-
) = ${dashboardAuthorId}`
|
|
1223
|
-
)
|
|
1224
|
-
).limit(1);
|
|
1225
|
-
return rows[0]?.id;
|
|
1226
|
-
}
|
|
1227
|
-
async function resolveEventActorIdentityId(executor, args) {
|
|
1228
|
-
const data = args.data;
|
|
1229
|
-
if (data.type !== "message" && data.type !== "message_updated") {
|
|
1230
|
-
return void 0;
|
|
1231
|
-
}
|
|
1232
|
-
if (typeof data.authorIdentityId === "string" && data.authorIdentityId) {
|
|
1233
|
-
return data.authorIdentityId;
|
|
1234
|
-
}
|
|
1235
|
-
if (data.role !== "user") {
|
|
1236
|
-
return void 0;
|
|
1237
|
-
}
|
|
1238
|
-
const author = readAuthor(data.meta);
|
|
1239
|
-
if (author.isBot === true) {
|
|
1240
|
-
return void 0;
|
|
1241
|
-
}
|
|
1242
|
-
const userId = parseActorUserId(author.userId);
|
|
1243
|
-
if (!userId) {
|
|
1244
|
-
return void 0;
|
|
1245
|
-
}
|
|
1246
|
-
if (SLACK_USER_ID_PATTERN.test(userId)) {
|
|
1247
|
-
const tenantId3 = await loadConversationSlackTenantId(
|
|
1248
|
-
executor,
|
|
1249
|
-
args.conversationId
|
|
1250
|
-
);
|
|
1251
|
-
const observation = {
|
|
1252
|
-
kind: "user",
|
|
1253
|
-
provider: "slack",
|
|
1254
|
-
providerSubjectId: userId,
|
|
1255
|
-
...tenantId3 ? { providerTenantId: tenantId3 } : void 0,
|
|
1256
|
-
...author.fullName ? { displayName: author.fullName } : void 0,
|
|
1257
|
-
...author.userName ? { handle: author.userName } : void 0,
|
|
1258
|
-
...author.email ? { email: author.email, emailVerified: true } : void 0
|
|
1259
|
-
};
|
|
1260
|
-
if (tenantId3) {
|
|
1261
|
-
const stored = await upsertIdentity(executor, observation, args.nowMs);
|
|
1262
|
-
return stored.id;
|
|
1263
|
-
}
|
|
1264
|
-
return await findIdentityIdByProviderSubject(executor, {
|
|
1265
|
-
provider: "slack",
|
|
1266
|
-
providerSubjectId: userId
|
|
1267
|
-
}) ?? void 0;
|
|
1268
|
-
}
|
|
1269
|
-
const email = typeof author.email === "string" && author.email.includes("@") ? author.email.trim().toLowerCase() : userId.includes("@") ? userId.trim().toLowerCase() : void 0;
|
|
1270
|
-
if (email) {
|
|
1271
|
-
const stored = await upsertIdentity(
|
|
1272
|
-
executor,
|
|
1273
|
-
{
|
|
1274
|
-
kind: "user",
|
|
1275
|
-
provider: "junior",
|
|
1276
|
-
providerSubjectId: email,
|
|
1277
|
-
email,
|
|
1278
|
-
emailVerified: true,
|
|
1279
|
-
...author.fullName ? { displayName: author.fullName } : void 0,
|
|
1280
|
-
metadata: { platform: "web" }
|
|
1281
|
-
},
|
|
1282
|
-
args.nowMs
|
|
1283
|
-
);
|
|
1284
|
-
return stored.id;
|
|
1285
|
-
}
|
|
1286
|
-
if (userId.startsWith("dashboard:")) {
|
|
1287
|
-
return findJuniorIdentityIdByDashboardAuthorId(executor, userId);
|
|
1288
|
-
}
|
|
1289
|
-
return findJuniorIdentityIdByEmail(executor, userId);
|
|
1290
|
-
}
|
|
1291
|
-
function stripPayloadAuthorIdentityId(data) {
|
|
1292
|
-
if (data.type !== "message" && data.type !== "message_updated" || data.authorIdentityId === void 0) {
|
|
1293
|
-
return data;
|
|
1294
|
-
}
|
|
1295
|
-
const { authorIdentityId: _authorIdentityId, ...rest } = data;
|
|
1296
|
-
return rest;
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
// src/db/postgres-json.ts
|
|
1300
|
-
function sanitizePostgresJson(value) {
|
|
1301
|
-
if (typeof value === "string") {
|
|
1302
|
-
return value.replaceAll("\0", " ");
|
|
1303
|
-
}
|
|
1304
|
-
if (Array.isArray(value)) {
|
|
1305
|
-
return value.map((item) => sanitizePostgresJson(item));
|
|
1306
|
-
}
|
|
1307
|
-
if (value === null || typeof value !== "object") {
|
|
1308
|
-
return value;
|
|
1309
|
-
}
|
|
1310
|
-
const prototype = Object.getPrototypeOf(value);
|
|
1311
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
1312
|
-
return value;
|
|
1313
|
-
}
|
|
1314
|
-
return Object.fromEntries(
|
|
1315
|
-
Object.entries(value).map(([key, item]) => [
|
|
1316
|
-
key,
|
|
1317
|
-
sanitizePostgresJson(item)
|
|
1318
|
-
])
|
|
1319
|
-
);
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
// src/chat/conversations/sql/event-lock.ts
|
|
1323
|
-
async function withConversationEventLock(executor, conversationId, callback) {
|
|
1324
|
-
return executor.withLock(`junior_conversation:${conversationId}`, callback);
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
// src/chat/conversations/sql/history.ts
|
|
1328
|
-
var messageHistoryEventTypes = [
|
|
1329
|
-
"message",
|
|
1330
|
-
"message_updated",
|
|
1331
|
-
"message_handled"
|
|
1332
|
-
];
|
|
1333
|
-
var HUMAN_INSTRUCTION_PLATFORMS = /* @__PURE__ */ new Set(["slack", "local", "web"]);
|
|
1334
|
-
function eventUnarchivesConversation(data) {
|
|
1335
|
-
if (data.type === "user_message") {
|
|
1336
|
-
const provenance = data.provenance;
|
|
1337
|
-
if (provenance.authority !== "instruction") return false;
|
|
1338
|
-
const platform = provenance.actor?.platform;
|
|
1339
|
-
return platform === void 0 || HUMAN_INSTRUCTION_PLATFORMS.has(platform);
|
|
1340
|
-
}
|
|
1341
|
-
if (data.type !== "message") {
|
|
1342
|
-
return false;
|
|
1343
|
-
}
|
|
1344
|
-
if (data.role !== "user") return false;
|
|
1345
|
-
const meta = data.meta;
|
|
1346
|
-
if (!meta) return true;
|
|
1347
|
-
if (typeof meta.eventType === "string" && meta.eventType.length > 0) {
|
|
1348
|
-
return false;
|
|
1349
|
-
}
|
|
1350
|
-
const author = meta.author;
|
|
1351
|
-
if (author && typeof author === "object" && !Array.isArray(author) && author.isBot === true) {
|
|
1352
|
-
return false;
|
|
1353
|
-
}
|
|
1354
|
-
return true;
|
|
1355
|
-
}
|
|
1356
|
-
function insertFromEvent(conversationId, seq, historyVersion, event, actorIdentityId) {
|
|
1357
|
-
const stripped = stripPayloadAuthorIdentityId(event.data);
|
|
1358
|
-
const { type, ...payload } = conversationEventDataSchema.parse(stripped);
|
|
1359
|
-
return {
|
|
1360
|
-
conversationId,
|
|
1361
|
-
seq,
|
|
1362
|
-
historyVersion,
|
|
1363
|
-
schemaVersion: 1,
|
|
1364
|
-
idempotencyKey: event.idempotencyKey ?? null,
|
|
1365
|
-
type,
|
|
1366
|
-
payload: sanitizePostgresJson(payload),
|
|
1367
|
-
actorIdentityId: actorIdentityId ?? null,
|
|
1368
|
-
createdAt: new Date(event.createdAtMs)
|
|
1369
|
-
};
|
|
1370
|
-
}
|
|
1371
|
-
function eventFromRow(row) {
|
|
1372
|
-
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;
|
|
1373
|
-
return decodeStoredConversationEvent({
|
|
1374
|
-
schemaVersion: row.schemaVersion,
|
|
1375
|
-
seq: row.seq,
|
|
1376
|
-
historyVersion: row.historyVersion,
|
|
1377
|
-
...row.idempotencyKey ? { idempotencyKey: row.idempotencyKey } : void 0,
|
|
1378
|
-
createdAtMs: row.createdAt.getTime(),
|
|
1379
|
-
type: row.type,
|
|
1380
|
-
payload
|
|
1381
|
-
});
|
|
1382
|
-
}
|
|
1383
|
-
function messagesSummarizedEventFromRow(row) {
|
|
1384
|
-
const event = eventFromRow(row);
|
|
1385
|
-
if (event.schemaVersion !== 1 || event.data.type !== "messages_summarized") {
|
|
1386
|
-
throw new Error(
|
|
1387
|
-
"Message compaction row did not decode as messages_summarized"
|
|
1388
|
-
);
|
|
1389
|
-
}
|
|
1390
|
-
return { ...event, schemaVersion: 1, data: event.data };
|
|
1391
|
-
}
|
|
1392
|
-
var SqlConversationEventStore = class {
|
|
1393
|
-
constructor(executor) {
|
|
1394
|
-
this.executor = executor;
|
|
1395
|
-
}
|
|
1396
|
-
executor;
|
|
1397
|
-
async append(conversationId, events, options = {}) {
|
|
1398
|
-
const parsed = events.map(
|
|
1399
|
-
(event) => newConversationEventSchema.parse(event)
|
|
1400
|
-
);
|
|
1401
|
-
if (parsed.length === 0) {
|
|
1402
|
-
return [];
|
|
1403
|
-
}
|
|
1404
|
-
return withConversationEventLock(
|
|
1405
|
-
this.executor,
|
|
1406
|
-
conversationId,
|
|
1407
|
-
async () => {
|
|
1408
|
-
const existingKeys = parsed.map((event) => event.idempotencyKey).filter((key) => key !== void 0);
|
|
1409
|
-
const persistedKeys = existingKeys.length === 0 ? /* @__PURE__ */ new Set() : new Set(
|
|
1410
|
-
(await this.executor.db().select({ key: juniorConversationEvents.idempotencyKey }).from(juniorConversationEvents).where(
|
|
1411
|
-
and6(
|
|
1412
|
-
eq6(
|
|
1413
|
-
juniorConversationEvents.conversationId,
|
|
1414
|
-
conversationId
|
|
1415
|
-
),
|
|
1416
|
-
inArray2(
|
|
1417
|
-
juniorConversationEvents.idempotencyKey,
|
|
1418
|
-
existingKeys
|
|
1419
|
-
)
|
|
1420
|
-
)
|
|
1421
|
-
)).flatMap((row) => row.key ? [row.key] : [])
|
|
1422
|
-
);
|
|
1423
|
-
const acceptedKeys = new Set(persistedKeys);
|
|
1424
|
-
const pending = parsed.filter((event) => {
|
|
1425
|
-
if (event.idempotencyKey === void 0) return true;
|
|
1426
|
-
if (acceptedKeys.has(event.idempotencyKey)) return false;
|
|
1427
|
-
acceptedKeys.add(event.idempotencyKey);
|
|
1428
|
-
return true;
|
|
1429
|
-
});
|
|
1430
|
-
if (pending.length === 0) {
|
|
1431
|
-
return [];
|
|
1432
|
-
}
|
|
1433
|
-
const newestCreatedAtMs = Math.max(
|
|
1434
|
-
...pending.map((event) => event.createdAtMs)
|
|
1435
|
-
);
|
|
1436
|
-
await ensureConversationRow(
|
|
1437
|
-
this.executor,
|
|
1438
|
-
conversationId,
|
|
1439
|
-
newestCreatedAtMs,
|
|
1440
|
-
options
|
|
1441
|
-
);
|
|
1442
|
-
const cursor = await this.readCursor(conversationId);
|
|
1443
|
-
const historyVersion = cursor.maxHistoryVersion ?? 0;
|
|
1444
|
-
let seq = cursor.nextSeq;
|
|
1445
|
-
const rows = [];
|
|
1446
|
-
for (const event of pending) {
|
|
1447
|
-
const actorIdentityId = await resolveEventActorIdentityId(
|
|
1448
|
-
this.executor,
|
|
1449
|
-
{
|
|
1450
|
-
conversationId,
|
|
1451
|
-
data: event.data,
|
|
1452
|
-
nowMs: event.createdAtMs
|
|
1453
|
-
}
|
|
1454
|
-
);
|
|
1455
|
-
rows.push(
|
|
1456
|
-
insertFromEvent(
|
|
1457
|
-
conversationId,
|
|
1458
|
-
seq++,
|
|
1459
|
-
historyVersion,
|
|
1460
|
-
event,
|
|
1461
|
-
actorIdentityId
|
|
1462
|
-
)
|
|
1463
|
-
);
|
|
1464
|
-
if (actorIdentityId) {
|
|
1465
|
-
await recordConversationParticipant(this.executor, {
|
|
1466
|
-
actorIdentityId,
|
|
1467
|
-
conversationId,
|
|
1468
|
-
atMs: event.createdAtMs,
|
|
1469
|
-
restoreArchive: eventUnarchivesConversation(event.data)
|
|
1470
|
-
});
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
await this.executor.db().insert(juniorConversationEvents).values(rows);
|
|
1474
|
-
return rows.map((row) => ({
|
|
1475
|
-
seq: row.seq,
|
|
1476
|
-
historyVersion: row.historyVersion
|
|
1477
|
-
}));
|
|
1478
|
-
}
|
|
1479
|
-
);
|
|
1480
|
-
}
|
|
1481
|
-
async replaceHistory(conversationId, replacement) {
|
|
1482
|
-
const parsed = historyReplacementSchema.parse(replacement);
|
|
1483
|
-
await withConversationEventLock(this.executor, conversationId, async () => {
|
|
1484
|
-
await ensureConversationRow(this.executor, conversationId, Date.now());
|
|
1485
|
-
const cursor = await this.readCursor(conversationId);
|
|
1486
|
-
const historyVersion = (cursor.maxHistoryVersion ?? 0) + 1;
|
|
1487
|
-
await this.executor.db().insert(juniorConversationEvents).values(
|
|
1488
|
-
insertFromEvent(
|
|
1489
|
-
conversationId,
|
|
1490
|
-
cursor.nextSeq,
|
|
1491
|
-
historyVersion,
|
|
1492
|
-
parsed
|
|
1493
|
-
)
|
|
1494
|
-
);
|
|
1495
|
-
});
|
|
1496
|
-
}
|
|
1497
|
-
async loadCurrentHistoryVersion(conversationId) {
|
|
1498
|
-
return (await this.readCursor(conversationId)).maxHistoryVersion ?? 0;
|
|
1499
|
-
}
|
|
1500
|
-
async loadCurrentHistory(conversationId) {
|
|
1501
|
-
const cursor = await this.readCursor(conversationId);
|
|
1502
|
-
if (cursor.maxHistoryVersion === null) {
|
|
1503
|
-
return [];
|
|
1504
|
-
}
|
|
1505
|
-
const rows = await this.executor.db().select().from(juniorConversationEvents).where(
|
|
1506
|
-
and6(
|
|
1507
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1508
|
-
eq6(juniorConversationEvents.historyVersion, cursor.maxHistoryVersion)
|
|
1509
|
-
)
|
|
1510
|
-
).orderBy(asc2(juniorConversationEvents.seq));
|
|
1511
|
-
return rows.map(eventFromRow);
|
|
1512
|
-
}
|
|
1513
|
-
async loadByIdempotencyKey(conversationId, idempotencyKey) {
|
|
1514
|
-
const [row] = await this.executor.db().select().from(juniorConversationEvents).where(
|
|
1515
|
-
and6(
|
|
1516
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1517
|
-
eq6(juniorConversationEvents.idempotencyKey, idempotencyKey)
|
|
1518
|
-
)
|
|
1519
|
-
).limit(1);
|
|
1520
|
-
return row ? eventFromRow(row) : void 0;
|
|
1521
|
-
}
|
|
1522
|
-
async loadHistoryContaining(conversationId, seq, throughSeq) {
|
|
1523
|
-
const [boundary] = await this.executor.db().select({ historyVersion: juniorConversationEvents.historyVersion }).from(juniorConversationEvents).where(
|
|
1524
|
-
and6(
|
|
1525
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1526
|
-
eq6(juniorConversationEvents.seq, seq)
|
|
1527
|
-
)
|
|
1528
|
-
).limit(1);
|
|
1529
|
-
if (!boundary) return void 0;
|
|
1530
|
-
const rows = await this.executor.db().select().from(juniorConversationEvents).where(
|
|
1531
|
-
and6(
|
|
1532
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1533
|
-
eq6(juniorConversationEvents.historyVersion, boundary.historyVersion),
|
|
1534
|
-
throughSeq === void 0 ? void 0 : lte(juniorConversationEvents.seq, throughSeq)
|
|
1535
|
-
)
|
|
1536
|
-
).orderBy(asc2(juniorConversationEvents.seq));
|
|
1537
|
-
return rows.map(eventFromRow);
|
|
1538
|
-
}
|
|
1539
|
-
async loadLatestStructuredEvent(conversationId, namespace, name) {
|
|
1540
|
-
const [row] = await this.executor.db().select().from(juniorConversationEvents).where(
|
|
1541
|
-
and6(
|
|
1542
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1543
|
-
eq6(juniorConversationEvents.type, "structured_event"),
|
|
1544
|
-
sql6`${juniorConversationEvents.payload}->>'namespace' = ${namespace}`,
|
|
1545
|
-
sql6`${juniorConversationEvents.payload}->>'name' = ${name}`
|
|
1546
|
-
)
|
|
1547
|
-
).orderBy(desc2(juniorConversationEvents.seq)).limit(1);
|
|
1548
|
-
return row ? eventFromRow(row) : void 0;
|
|
1549
|
-
}
|
|
1550
|
-
async loadLatestInstruction(conversationId) {
|
|
1551
|
-
const [row] = await this.executor.db().select().from(juniorConversationEvents).where(
|
|
1552
|
-
and6(
|
|
1553
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1554
|
-
eq6(juniorConversationEvents.type, "user_message"),
|
|
1555
|
-
sql6`${juniorConversationEvents.payload}->'provenance'->>'authority' = 'instruction'`
|
|
1556
|
-
)
|
|
1557
|
-
).orderBy(desc2(juniorConversationEvents.seq)).limit(1);
|
|
1558
|
-
return row ? eventFromRow(row) : void 0;
|
|
1559
|
-
}
|
|
1560
|
-
async loadMessageHistory(conversationId) {
|
|
1561
|
-
const [compactionRow] = await this.executor.db().select().from(juniorConversationEvents).where(
|
|
1562
|
-
and6(
|
|
1563
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1564
|
-
eq6(juniorConversationEvents.type, "messages_summarized")
|
|
1565
|
-
)
|
|
1566
|
-
).orderBy(desc2(juniorConversationEvents.seq)).limit(1);
|
|
1567
|
-
const compaction = compactionRow ? messagesSummarizedEventFromRow(compactionRow) : void 0;
|
|
1568
|
-
const historyFromSeq = compaction?.data.historyFromSeq ?? 0;
|
|
1569
|
-
const rows = await this.executor.db().select().from(juniorConversationEvents).where(
|
|
1570
|
-
and6(
|
|
1571
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1572
|
-
inArray2(juniorConversationEvents.type, messageHistoryEventTypes),
|
|
1573
|
-
gte(juniorConversationEvents.seq, historyFromSeq)
|
|
1574
|
-
)
|
|
1575
|
-
).orderBy(asc2(juniorConversationEvents.seq));
|
|
1576
|
-
return { events: rows.map(eventFromRow), compaction, historyFromSeq };
|
|
1577
|
-
}
|
|
1578
|
-
async loadHistory(conversationId) {
|
|
1579
|
-
const rows = await this.executor.db().select().from(juniorConversationEvents).where(eq6(juniorConversationEvents.conversationId, conversationId)).orderBy(asc2(juniorConversationEvents.seq));
|
|
1580
|
-
return rows.map(eventFromRow);
|
|
1581
|
-
}
|
|
1582
|
-
async query(conversationId, query) {
|
|
1583
|
-
if (query.limit < 1) {
|
|
1584
|
-
throw new Error("Conversation event query limit must be at least 1");
|
|
1585
|
-
}
|
|
1586
|
-
if (query.afterSeq !== void 0 && query.beforeSeq !== void 0 && query.afterSeq >= query.beforeSeq) {
|
|
1587
|
-
return { events: [], hasOlder: false, hasNewer: false };
|
|
1588
|
-
}
|
|
1589
|
-
const typeFilter = query.types && query.types.length > 0 ? inArray2(juniorConversationEvents.type, [...query.types]) : void 0;
|
|
1590
|
-
const bounds = and6(
|
|
1591
|
-
eq6(juniorConversationEvents.conversationId, conversationId),
|
|
1592
|
-
query.afterSeq === void 0 ? void 0 : gt(juniorConversationEvents.seq, query.afterSeq),
|
|
1593
|
-
query.beforeSeq === void 0 ? void 0 : lt(juniorConversationEvents.seq, query.beforeSeq),
|
|
1594
|
-
typeFilter
|
|
1595
|
-
);
|
|
1596
|
-
const newestFirst = query.afterSeq === void 0;
|
|
1597
|
-
const rows = await this.executor.db().select().from(juniorConversationEvents).where(bounds).orderBy(
|
|
1598
|
-
newestFirst ? desc2(juniorConversationEvents.seq) : asc2(juniorConversationEvents.seq)
|
|
1599
|
-
).limit(query.limit + 1);
|
|
1600
|
-
const overflow = rows.length > query.limit;
|
|
1601
|
-
const pageRows = overflow ? rows.slice(0, query.limit) : rows;
|
|
1602
|
-
const events = (newestFirst ? [...pageRows].reverse() : pageRows).map(
|
|
1603
|
-
eventFromRow
|
|
1604
|
-
);
|
|
1605
|
-
if (events.length === 0) {
|
|
1606
|
-
return { events, hasOlder: false, hasNewer: false };
|
|
1607
|
-
}
|
|
1608
|
-
const firstSeq = events[0].seq;
|
|
1609
|
-
const lastSeq = events[events.length - 1].seq;
|
|
1610
|
-
const hasOlder = newestFirst && overflow ? true : await this.hasMatchingEvent({
|
|
1611
|
-
conversationId,
|
|
1612
|
-
beforeSeq: firstSeq,
|
|
1613
|
-
typeFilter
|
|
1614
|
-
});
|
|
1615
|
-
const hasNewer = !newestFirst && overflow ? true : await this.hasMatchingEvent({
|
|
1616
|
-
conversationId,
|
|
1617
|
-
afterSeq: lastSeq,
|
|
1618
|
-
typeFilter
|
|
1619
|
-
});
|
|
1620
|
-
return { events, hasOlder, hasNewer };
|
|
1621
|
-
}
|
|
1622
|
-
/** Return whether any matching event exists inside the exclusive seq window. */
|
|
1623
|
-
async hasMatchingEvent(args) {
|
|
1624
|
-
if (args.afterSeq !== void 0 && args.beforeSeq !== void 0 && args.afterSeq >= args.beforeSeq) {
|
|
1625
|
-
return false;
|
|
1626
|
-
}
|
|
1627
|
-
const [row] = await this.executor.db().select({ seq: juniorConversationEvents.seq }).from(juniorConversationEvents).where(
|
|
1628
|
-
and6(
|
|
1629
|
-
eq6(juniorConversationEvents.conversationId, args.conversationId),
|
|
1630
|
-
args.afterSeq === void 0 ? void 0 : gt(juniorConversationEvents.seq, args.afterSeq),
|
|
1631
|
-
args.beforeSeq === void 0 ? void 0 : lt(juniorConversationEvents.seq, args.beforeSeq),
|
|
1632
|
-
args.typeFilter
|
|
1633
|
-
)
|
|
1634
|
-
).limit(1);
|
|
1635
|
-
return row !== void 0;
|
|
1636
|
-
}
|
|
1637
|
-
/** Read the next sequence and active model-history version. */
|
|
1638
|
-
async readCursor(conversationId) {
|
|
1639
|
-
const rows = await this.executor.db().select({
|
|
1640
|
-
maxSeq: sql6`max(${juniorConversationEvents.seq})`,
|
|
1641
|
-
maxHistoryVersion: sql6`max(${juniorConversationEvents.historyVersion})`
|
|
1642
|
-
}).from(juniorConversationEvents).where(eq6(juniorConversationEvents.conversationId, conversationId));
|
|
1643
|
-
const maxSeq = rows[0]?.maxSeq;
|
|
1644
|
-
const maxHistoryVersion = rows[0]?.maxHistoryVersion;
|
|
1645
|
-
return {
|
|
1646
|
-
maxHistoryVersion: maxHistoryVersion === null || maxHistoryVersion === void 0 ? null : Number(maxHistoryVersion),
|
|
1647
|
-
nextSeq: maxSeq === null || maxSeq === void 0 ? 0 : Number(maxSeq) + 1
|
|
1648
|
-
};
|
|
1649
|
-
}
|
|
1650
|
-
};
|
|
1651
|
-
function createSqlConversationEventStore(executor) {
|
|
1652
|
-
return new SqlConversationEventStore(executor);
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
// src/chat/conversations/sql/message-search.ts
|
|
1656
|
-
import {
|
|
1657
|
-
and as and7,
|
|
1658
|
-
desc as desc3,
|
|
1659
|
-
eq as eq7,
|
|
1660
|
-
gte as gte2,
|
|
1661
|
-
isNull as isNull2,
|
|
1662
|
-
lt as lt2,
|
|
1663
|
-
ne,
|
|
1664
|
-
sql as sql7
|
|
1665
|
-
} from "drizzle-orm";
|
|
1666
|
-
var EXCERPT_WITHOUT_QUERY_CHARS = 240;
|
|
1667
|
-
var SqlConversationMessageSearchStore = class {
|
|
1668
|
-
constructor(executor) {
|
|
1669
|
-
this.executor = executor;
|
|
1670
|
-
}
|
|
1671
|
-
executor;
|
|
1672
|
-
async search(args) {
|
|
1673
|
-
const db = this.executor.db();
|
|
1674
|
-
const query = args.filters.query?.trim() || void 0;
|
|
1675
|
-
const text = sql7`${juniorConversationEvents.payload}->>'text'`;
|
|
1676
|
-
const role = sql7`${juniorConversationEvents.payload}->>'role'`;
|
|
1677
|
-
const messageId = sql7`${juniorConversationEvents.payload}->>'messageId'`;
|
|
1678
|
-
const tsquery = query ? sql7`websearch_to_tsquery('english', ${query})` : void 0;
|
|
1679
|
-
const rank = tsquery ? sql7`ts_rank_cd(to_tsvector('english', ${text}), ${tsquery})` : sql7`1`;
|
|
1680
|
-
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})`;
|
|
1681
|
-
const conditions = [
|
|
1682
|
-
eq7(juniorConversations.source, "slack"),
|
|
1683
|
-
isNull2(juniorConversations.parentConversationId),
|
|
1684
|
-
isNull2(juniorConversations.transcriptPurgedAt),
|
|
1685
|
-
ne(juniorConversations.conversationId, args.currentConversationId),
|
|
1686
|
-
eq7(juniorDestinations.provider, args.scope.provider),
|
|
1687
|
-
eq7(juniorDestinations.providerTenantId, args.scope.providerTenantId),
|
|
1688
|
-
eq7(juniorDestinations.visibility, "public"),
|
|
1689
|
-
eq7(juniorConversationEvents.type, "message"),
|
|
1690
|
-
sql7`${role} in ('user', 'assistant')`
|
|
1691
|
-
];
|
|
1692
|
-
if (tsquery) {
|
|
1693
|
-
conditions.push(sql7`to_tsvector('english', ${text}) @@ ${tsquery}`);
|
|
1694
|
-
}
|
|
1695
|
-
if (args.filters.channelId) {
|
|
1696
|
-
conditions.push(
|
|
1697
|
-
eq7(juniorDestinations.providerDestinationId, args.filters.channelId)
|
|
1698
|
-
);
|
|
1699
|
-
}
|
|
1700
|
-
if (args.filters.afterMs !== void 0 && Number.isFinite(args.filters.afterMs)) {
|
|
1701
|
-
conditions.push(
|
|
1702
|
-
gte2(juniorConversations.lastActivityAt, new Date(args.filters.afterMs))
|
|
1703
|
-
);
|
|
1704
|
-
}
|
|
1705
|
-
if (args.filters.beforeMs !== void 0 && Number.isFinite(args.filters.beforeMs)) {
|
|
1706
|
-
conditions.push(
|
|
1707
|
-
lt2(juniorConversations.lastActivityAt, new Date(args.filters.beforeMs))
|
|
1708
|
-
);
|
|
1709
|
-
}
|
|
1710
|
-
if (args.filters.annotation) {
|
|
1711
|
-
const annotation = args.filters.annotation.toLowerCase();
|
|
1712
|
-
const nestedAnnotationPrefix = `${annotation}#`;
|
|
1713
|
-
conditions.push(
|
|
1714
|
-
sql7`exists (
|
|
1715
|
-
select 1
|
|
1716
|
-
from ${juniorConversationAnnotations}
|
|
1717
|
-
where ${and7(
|
|
1718
|
-
eq7(
|
|
1719
|
-
juniorConversationAnnotations.conversationId,
|
|
1720
|
-
juniorConversations.conversationId
|
|
1721
|
-
),
|
|
1722
|
-
// Exact key, or a nested child that continues with "#".
|
|
1723
|
-
// Avoids sibling key collisions and partial nested-id prefixes.
|
|
1724
|
-
sql7`(
|
|
1725
|
-
lower(${juniorConversationAnnotations.key}) = ${annotation}
|
|
1726
|
-
or starts_with(
|
|
1727
|
-
lower(${juniorConversationAnnotations.key}),
|
|
1728
|
-
${nestedAnnotationPrefix}
|
|
1729
|
-
)
|
|
1730
|
-
)`
|
|
1731
|
-
)}
|
|
1732
|
-
)`
|
|
1733
|
-
);
|
|
1734
|
-
}
|
|
1735
|
-
const bestPerConversation = db.selectDistinctOn([juniorConversations.conversationId], {
|
|
1736
|
-
channelName: juniorDestinations.displayName,
|
|
1737
|
-
conversationId: juniorConversations.conversationId,
|
|
1738
|
-
excerpt: excerpt.as("excerpt"),
|
|
1739
|
-
lastActivityAt: juniorConversations.lastActivityAt,
|
|
1740
|
-
messageCreatedAt: juniorConversationEvents.createdAt,
|
|
1741
|
-
messageId: messageId.as("message_id"),
|
|
1742
|
-
providerDestinationId: juniorDestinations.providerDestinationId,
|
|
1743
|
-
rank: rank.as("rank"),
|
|
1744
|
-
role: role.as("role")
|
|
1745
|
-
}).from(juniorConversationEvents).innerJoin(
|
|
1746
|
-
juniorConversations,
|
|
1747
|
-
eq7(
|
|
1748
|
-
juniorConversations.conversationId,
|
|
1749
|
-
juniorConversationEvents.conversationId
|
|
1750
|
-
)
|
|
1751
|
-
).innerJoin(
|
|
1752
|
-
juniorDestinations,
|
|
1753
|
-
eq7(juniorDestinations.id, juniorConversations.destinationId)
|
|
1754
|
-
).where(and7(...conditions)).orderBy(
|
|
1755
|
-
juniorConversations.conversationId,
|
|
1756
|
-
desc3(rank),
|
|
1757
|
-
desc3(juniorConversationEvents.createdAt)
|
|
1758
|
-
).as("best_conversation_matches");
|
|
1759
|
-
const rows = await db.select().from(bestPerConversation).orderBy(
|
|
1760
|
-
desc3(bestPerConversation.rank),
|
|
1761
|
-
desc3(bestPerConversation.lastActivityAt),
|
|
1762
|
-
desc3(bestPerConversation.messageCreatedAt)
|
|
1763
|
-
).limit(args.limit);
|
|
1764
|
-
return rows.map((row) => ({
|
|
1765
|
-
conversationId: row.conversationId,
|
|
1766
|
-
excerpt: row.excerpt,
|
|
1767
|
-
messageCreatedAtMs: row.messageCreatedAt.getTime(),
|
|
1768
|
-
messageId: row.messageId,
|
|
1769
|
-
providerDestinationId: row.providerDestinationId,
|
|
1770
|
-
role: row.role,
|
|
1771
|
-
...row.channelName ? { channelName: row.channelName } : void 0
|
|
1772
|
-
}));
|
|
1773
|
-
}
|
|
1774
|
-
};
|
|
1775
|
-
function createSqlConversationMessageSearchStore(executor) {
|
|
1776
|
-
return new SqlConversationMessageSearchStore(executor);
|
|
1777
|
-
}
|
|
1778
|
-
|
|
1779
|
-
// src/chat/db.ts
|
|
1780
|
-
var current;
|
|
1781
|
-
function createDb(args) {
|
|
1782
|
-
return createJuniorSqlExecutor({
|
|
1783
|
-
connectionString: args.databaseUrl,
|
|
1784
|
-
driver: args.driver,
|
|
1785
|
-
statementTimeoutMs: args.statementTimeoutMs
|
|
1786
|
-
});
|
|
1787
|
-
}
|
|
1788
|
-
function getSqlExecutor() {
|
|
1789
|
-
const { sql: sql8 } = getChatConfig();
|
|
1790
|
-
if (current?.databaseUrl !== sql8.databaseUrl || current.driver !== sql8.driver || current.statementTimeoutMs !== sql8.statementTimeoutMs) {
|
|
1791
|
-
if (current) {
|
|
1792
|
-
const previous = current;
|
|
1793
|
-
current = void 0;
|
|
1794
|
-
void previous.db.close().catch(() => void 0);
|
|
1795
|
-
}
|
|
1796
|
-
const db = createDb({
|
|
1797
|
-
databaseUrl: sql8.databaseUrl,
|
|
1798
|
-
driver: sql8.driver,
|
|
1799
|
-
statementTimeoutMs: sql8.statementTimeoutMs
|
|
1800
|
-
});
|
|
1801
|
-
current = {
|
|
1802
|
-
databaseUrl: sql8.databaseUrl,
|
|
1803
|
-
driver: sql8.driver,
|
|
1804
|
-
statementTimeoutMs: sql8.statementTimeoutMs,
|
|
1805
|
-
db,
|
|
1806
|
-
store: createSqlStore(db),
|
|
1807
|
-
eventStore: createSqlConversationEventStore(db),
|
|
1808
|
-
searchStore: createSqlConversationMessageSearchStore(db)
|
|
1809
|
-
};
|
|
1810
|
-
}
|
|
1811
|
-
return current.db;
|
|
1812
|
-
}
|
|
1813
|
-
function getDb() {
|
|
1814
|
-
return getSqlExecutor().db();
|
|
1815
|
-
}
|
|
1816
|
-
function getConversationStore() {
|
|
1817
|
-
getSqlExecutor();
|
|
1818
|
-
return current.store;
|
|
1819
|
-
}
|
|
1820
|
-
function getConversationEventStore() {
|
|
1821
|
-
getSqlExecutor();
|
|
1822
|
-
return current.eventStore;
|
|
1823
|
-
}
|
|
1824
|
-
function getConversationMessageSearchStore() {
|
|
1825
|
-
getSqlExecutor();
|
|
1826
|
-
return current.searchStore;
|
|
1827
|
-
}
|
|
1828
|
-
async function closeDb() {
|
|
1829
|
-
const previous = current;
|
|
1830
|
-
current = void 0;
|
|
1831
|
-
await previous?.db.close();
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
export {
|
|
1835
|
-
createSlackDestination,
|
|
1836
|
-
parseDestination,
|
|
1837
|
-
requireSlackDestination,
|
|
1838
|
-
sameDestination,
|
|
1839
|
-
upsertIdentity,
|
|
1840
|
-
upsertLinkedIdentity,
|
|
1841
|
-
deleteProviderIdentityForSlackUser,
|
|
1842
|
-
resolveRootConversationId,
|
|
1843
|
-
parseSessionSource,
|
|
1844
|
-
bindProviderConversation,
|
|
1845
|
-
locationFromRow,
|
|
1846
|
-
withConversationMutationLock,
|
|
1847
|
-
sanitizePostgresJson,
|
|
1848
|
-
withConversationEventLock,
|
|
1849
|
-
createSqlConversationEventStore,
|
|
1850
|
-
getSqlExecutor,
|
|
1851
|
-
getDb,
|
|
1852
|
-
getConversationStore,
|
|
1853
|
-
getConversationEventStore,
|
|
1854
|
-
getConversationMessageSearchStore,
|
|
1855
|
-
closeDb
|
|
1856
|
-
};
|