@sentry/junior 0.185.0 → 0.187.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-hooks-NGZQLL5O.js → agent-hooks-XVAE2554.js} +11 -11
- package/dist/api/schema/conversation.d.ts +8 -0
- package/dist/api/schema.js +1 -1
- package/dist/api.js +44 -36
- package/dist/app.js +1079 -264
- package/dist/{catalog-runtime-AAEAO2RL.js → catalog-runtime-DWFAC562.js} +4 -4
- package/dist/chat/agent/types.d.ts +16 -13
- package/dist/chat/api-turns/{accepted-reply.d.ts → assistant-message.d.ts} +3 -2
- package/dist/chat/api-turns/cancellation.d.ts +0 -1
- package/dist/chat/api-turns/mailbox-input.d.ts +4 -0
- package/dist/chat/api-turns/routing.d.ts +23 -7
- package/dist/chat/api-turns/work.d.ts +2 -2
- package/dist/chat/conversations/location.d.ts +2 -2
- package/dist/chat/conversations/store.d.ts +13 -0
- package/dist/chat/conversations/turn-lifecycle.d.ts +2 -0
- package/dist/chat/providers/slack/runtime.d.ts +0 -2
- package/dist/chat/providers/slack/turn.d.ts +0 -2
- package/dist/chat/resource-events/actor.d.ts +14 -2
- package/dist/chat/resource-events/app-publisher.d.ts +18 -0
- package/dist/chat/resource-events/catalog.d.ts +19 -0
- package/dist/chat/resource-events/ingest.d.ts +0 -1
- package/dist/chat/resource-events/notification.d.ts +28 -3
- package/dist/chat/resource-events/runtime-catalog.d.ts +7 -2
- package/dist/chat/resource-events/store.d.ts +1 -13
- package/dist/chat/resource-events/workspace.d.ts +7 -3
- package/dist/chat/sandbox/egress/credentials.d.ts +5 -4
- package/dist/chat/sandbox/egress/session.d.ts +9 -9
- package/dist/chat/sandbox/errors.d.ts +1 -1
- package/dist/chat/sandbox/ref.d.ts +1 -1
- package/dist/chat/sandbox/snapshot/events.d.ts +8 -1
- package/dist/chat/sandbox/snapshot/not-ready-error.d.ts +6 -1
- package/dist/chat/sentry-links.d.ts +2 -0
- package/dist/chat/services/turn-session-routing.d.ts +23 -7
- package/dist/chat/task-execution/slack-resource-event.d.ts +47 -0
- package/dist/chat/task-execution/slack-work.d.ts +0 -21
- package/dist/chat/task-input.d.ts +22 -0
- package/dist/chat/tools/event-tasks.d.ts +1 -1
- package/dist/chat/tools/resource-events.d.ts +1 -1
- package/dist/{chunk-Y5G23T2D.js → chunk-27T5HZHO.js} +91 -7
- package/dist/{chunk-TVVAMOLS.js → chunk-2VUDJGB6.js} +2 -2
- package/dist/{chunk-X7NCJQAA.js → chunk-4A2R3AQB.js} +1 -1
- package/dist/{chunk-MWOH6CIK.js → chunk-4YD3DET6.js} +278 -116
- package/dist/{chunk-INQHUE72.js → chunk-6FGN7ZEG.js} +6 -2
- package/dist/{chunk-ZKKGFUWM.js → chunk-6FKNNUSN.js} +6 -6
- package/dist/{chunk-OMQ2J6F6.js → chunk-6YCIYOVA.js} +1 -1
- package/dist/{chunk-7GAP2XG4.js → chunk-7LRRVMPH.js} +1 -1
- package/dist/{chunk-4HA36IWS.js → chunk-BITZUBPJ.js} +8 -8
- package/dist/{chunk-QCT4226Q.js → chunk-D3GDGREI.js} +3 -3
- package/dist/{chunk-WLKWN4CD.js → chunk-D5BWM37G.js} +8 -5
- package/dist/{chunk-VH4IU3UC.js → chunk-DUE4EUNL.js} +19 -45
- package/dist/{chunk-DAPC2HTM.js → chunk-EIWYZXSM.js} +5 -5
- package/dist/{chunk-LVK4WJKM.js → chunk-HXR3FHTE.js} +13 -3
- package/dist/{chunk-UUULGCKK.js → chunk-ITLYUKGZ.js} +14 -4
- package/dist/{chunk-FTVMXDNN.js → chunk-JCRXXEMC.js} +1 -1
- package/dist/{chunk-EJYP3NQ4.js → chunk-JZPDYKRG.js} +37 -3
- package/dist/{chunk-HJPC32TQ.js → chunk-KRYJ5VOD.js} +20 -14
- package/dist/{chunk-QZKHHG3B.js → chunk-MUPPP7A7.js} +436 -283
- package/dist/{chunk-D63IUQQE.js → chunk-NIKLTFBP.js} +12 -9
- package/dist/{chunk-U4CTAVWN.js → chunk-NU775DLU.js} +2 -2
- package/dist/{chunk-W7GCLNIV.js → chunk-OM4SFFJK.js} +3 -3
- package/dist/{chunk-X2SS6BF7.js → chunk-P2VU5JNH.js} +32 -36
- package/dist/{chunk-4K25ODAO.js → chunk-PFAZSRGR.js} +3 -1
- package/dist/{chunk-EIJCPJOY.js → chunk-Q6OCUQ7W.js} +1 -1
- package/dist/{chunk-GJTIZQGJ.js → chunk-QH3I7ZOK.js} +1 -1
- package/dist/{chunk-4S47VHJR.js → chunk-STF4GSK4.js} +3 -3
- package/dist/{chunk-C6TS47CQ.js → chunk-TQHCZXN7.js} +11 -5
- package/dist/{chunk-ZIF2S464.js → chunk-U3KMII5Y.js} +1 -1
- package/dist/{chunk-6DOAUXLD.js → chunk-U5POFCKM.js} +753 -1718
- package/dist/{chunk-PNYJOEVV.js → chunk-U6ZQHRIP.js} +1 -1
- package/dist/{chunk-LRI5IRGY.js → chunk-URZ7UD4P.js} +2 -2
- package/dist/{chunk-6Q7YZLCL.js → chunk-VC343WHM.js} +9 -1
- package/dist/{chunk-ABAX75GG.js → chunk-WKIS4VRK.js} +17 -3
- package/dist/{chunk-FFHXG2FX.js → chunk-WL3R2KTS.js} +11 -29
- package/dist/{chunk-EWEH2PJW.js → chunk-WRDW3A3D.js} +5 -5
- package/dist/{chunk-7MHNIGHP.js → chunk-X5SXFVZT.js} +1 -1
- package/dist/{chunk-ATUWN6Z3.js → chunk-Z6OHCDXP.js} +2 -2
- package/dist/cli/chat.js +33 -33
- package/dist/cli/check.js +5 -5
- package/dist/cli/plugins.js +12 -12
- package/dist/cli/snapshot-create.js +9 -9
- package/dist/cli/upgrade.js +6 -6
- package/dist/{db-TRJ77FAU.js → db-FBHAWVXU.js} +6 -6
- package/dist/instrumentation.js +3 -3
- package/dist/nitro.js +6 -6
- package/dist/{oauth-callback-server-XD5SV3MS.js → oauth-callback-server-5HS5ULC6.js} +28 -28
- package/dist/{runner-KFX7NG6D.js → runner-46W6NV6B.js} +19 -19
- package/dist/{skills-J2AH26CW.js → skills-TG3QC4B6.js} +5 -5
- package/dist/spawn-Y6YWBIJS.js +41 -0
- package/dist/task-runner-YSGBPN4U.js +34 -0
- package/dist/{validation-O5J4VOPF.js → validation-GMRIDBC5.js} +5 -5
- package/dist/version.js +1 -1
- package/dist/{work-ECPQTG3U.js → work-W4ULBJTU.js} +21 -21
- package/dist/{worker-RS3DXUDO.js → worker-M6NVACS2.js} +10 -10
- package/package.json +4 -4
- package/dist/spawn-VU3CSRI6.js +0 -41
- package/dist/task-runner-5JG3VIIY.js +0 -34
|
@@ -1,40 +1,46 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createWebAuthorization,
|
|
3
3
|
deleteWebAuthorization
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ITLYUKGZ.js";
|
|
5
5
|
import {
|
|
6
6
|
AgentRunError,
|
|
7
7
|
executeTurn
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OM4SFFJK.js";
|
|
9
9
|
import {
|
|
10
10
|
buildDeliveredTurnStatePatch,
|
|
11
11
|
completeAuthPauseTurn,
|
|
12
12
|
finalizeFailedTurnReplyWithEvent,
|
|
13
13
|
getTurnUserMessage
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-EIWYZXSM.js";
|
|
15
15
|
import {
|
|
16
16
|
processPluginTask,
|
|
17
17
|
scheduleSessionCompletedPluginTasks
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-WL3R2KTS.js";
|
|
19
19
|
import {
|
|
20
20
|
ConversationTurnLifecycleService
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-VC343WHM.js";
|
|
22
22
|
import {
|
|
23
23
|
coerceThreadConversationState,
|
|
24
24
|
getPersistedSandboxState,
|
|
25
25
|
getPersistedThreadState,
|
|
26
26
|
persistThreadStateById
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-27T5HZHO.js";
|
|
28
28
|
import {
|
|
29
29
|
healthReportSchema
|
|
30
30
|
} from "./chunk-UTL3MHPC.js";
|
|
31
|
+
import {
|
|
32
|
+
RESOURCE_EVENT_MESSAGE_AUTHOR,
|
|
33
|
+
RESOURCE_EVENT_SYSTEM_ACTOR,
|
|
34
|
+
isResourceEventConversationMessage,
|
|
35
|
+
isResourceEventMailboxMetadata
|
|
36
|
+
} from "./chunk-MUPPP7A7.js";
|
|
31
37
|
import {
|
|
32
38
|
parseSlackThreadId
|
|
33
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-4A2R3AQB.js";
|
|
34
40
|
import {
|
|
35
41
|
appendAndEnqueueExclusiveInboundMessage,
|
|
36
42
|
appendAndEnqueueInboundMessage
|
|
37
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-NIKLTFBP.js";
|
|
38
44
|
import {
|
|
39
45
|
TurnInputCommitLostError,
|
|
40
46
|
buildDeterministicTurnId,
|
|
@@ -45,7 +51,7 @@ import {
|
|
|
45
51
|
markTurnClosed,
|
|
46
52
|
markTurnFailed,
|
|
47
53
|
startActiveTurn
|
|
48
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-NU775DLU.js";
|
|
49
55
|
import {
|
|
50
56
|
abandonTurnRecord,
|
|
51
57
|
buildConversationContext,
|
|
@@ -61,35 +67,42 @@ import {
|
|
|
61
67
|
recordDeliveredAssistantMessage,
|
|
62
68
|
saveTurnCheckpoint,
|
|
63
69
|
upsertConversationMessage
|
|
64
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-D5BWM37G.js";
|
|
65
71
|
import {
|
|
66
72
|
normalizeSlackConversationId
|
|
67
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-DUE4EUNL.js";
|
|
68
74
|
import {
|
|
69
75
|
getConversationEventStore,
|
|
70
76
|
getConversationStore,
|
|
71
77
|
getDb
|
|
72
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-WKIS4VRK.js";
|
|
73
79
|
import {
|
|
74
80
|
juniorConversationParticipants,
|
|
75
81
|
juniorConversations,
|
|
76
82
|
juniorIdentities,
|
|
77
83
|
juniorUsers
|
|
78
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-HXR3FHTE.js";
|
|
79
85
|
import {
|
|
80
86
|
juniorDestinations
|
|
81
87
|
} from "./chunk-VFUK3X5B.js";
|
|
88
|
+
import {
|
|
89
|
+
getSlackBotToken
|
|
90
|
+
} from "./chunk-URZ7UD4P.js";
|
|
82
91
|
import {
|
|
83
92
|
canExposeConversationPayload
|
|
84
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-Q6OCUQ7W.js";
|
|
85
94
|
import {
|
|
86
95
|
credentialContextForActor
|
|
87
96
|
} from "./chunk-CEMMLV5L.js";
|
|
97
|
+
import {
|
|
98
|
+
createActor
|
|
99
|
+
} from "./chunk-N7TMSOZH.js";
|
|
88
100
|
import {
|
|
89
101
|
logException,
|
|
102
|
+
logWarn,
|
|
90
103
|
setTags,
|
|
91
104
|
withLogContext
|
|
92
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-6YCIYOVA.js";
|
|
93
106
|
|
|
94
107
|
// src/handlers/health.ts
|
|
95
108
|
function readHealthReport() {
|
|
@@ -129,6 +142,10 @@ function createVercelAttachmentStorage() {
|
|
|
129
142
|
|
|
130
143
|
// src/chat/api-turns/routing.ts
|
|
131
144
|
import { z } from "zod";
|
|
145
|
+
import {
|
|
146
|
+
createLocalSource,
|
|
147
|
+
createWebSource
|
|
148
|
+
} from "@sentry/junior-plugin-api";
|
|
132
149
|
var apiTurnMailboxMetadataSchema = z.object({
|
|
133
150
|
authorEmail: z.string().email(),
|
|
134
151
|
authorFullName: z.string().min(1).optional(),
|
|
@@ -137,6 +154,38 @@ var apiTurnMailboxMetadataSchema = z.object({
|
|
|
137
154
|
kind: z.literal("api_turn"),
|
|
138
155
|
messageId: z.string().min(1)
|
|
139
156
|
}).strict();
|
|
157
|
+
function turnIdentityFromConversationMessage(message) {
|
|
158
|
+
if (isResourceEventConversationMessage(message)) {
|
|
159
|
+
return {
|
|
160
|
+
actor: RESOURCE_EVENT_SYSTEM_ACTOR,
|
|
161
|
+
author: message.author ?? RESOURCE_EVENT_MESSAGE_AUTHOR,
|
|
162
|
+
source: "resource_event"
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
const actor = createActor(message.author, {
|
|
166
|
+
platform: "web",
|
|
167
|
+
userId: message.author?.userId
|
|
168
|
+
});
|
|
169
|
+
if (actor?.platform !== "web") {
|
|
170
|
+
return void 0;
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
actor,
|
|
174
|
+
author: message.author ?? { userId: actor.userId },
|
|
175
|
+
source: "web"
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function sourceFromTurnInput(args) {
|
|
179
|
+
switch (args.source) {
|
|
180
|
+
case "resource_event":
|
|
181
|
+
return createLocalSource(args.conversationId);
|
|
182
|
+
case "web":
|
|
183
|
+
return createWebSource(
|
|
184
|
+
args.conversationId,
|
|
185
|
+
args.visibility === "private" ? "private" : "public"
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
140
189
|
async function getActiveApiTurnId(conversationId) {
|
|
141
190
|
const summaries = await listTurnSummaries(conversationId);
|
|
142
191
|
const active = summaries.filter(
|
|
@@ -170,13 +219,52 @@ function parseApiTurnMessages(messages) {
|
|
|
170
219
|
return [];
|
|
171
220
|
}
|
|
172
221
|
if (parsed.some((entry) => !entry.metadata.success)) {
|
|
173
|
-
throw new Error("
|
|
222
|
+
throw new Error("A Turn cannot combine different kinds of input");
|
|
174
223
|
}
|
|
175
224
|
return parsed.map((entry) => {
|
|
176
225
|
if (!entry.metadata.success) {
|
|
177
|
-
throw new Error("
|
|
226
|
+
throw new Error("User message has invalid metadata");
|
|
178
227
|
}
|
|
179
|
-
|
|
228
|
+
const metadata = entry.metadata.data;
|
|
229
|
+
const actor = {
|
|
230
|
+
platform: "web",
|
|
231
|
+
userId: metadata.authorUserId,
|
|
232
|
+
email: metadata.authorEmail.trim().toLowerCase(),
|
|
233
|
+
...metadata.authorFullName ? { fullName: metadata.authorFullName } : void 0,
|
|
234
|
+
...metadata.authorUserName ? { userName: metadata.authorUserName } : void 0
|
|
235
|
+
};
|
|
236
|
+
return {
|
|
237
|
+
actor,
|
|
238
|
+
author: {
|
|
239
|
+
email: actor.email,
|
|
240
|
+
...actor.fullName ? { fullName: actor.fullName } : void 0,
|
|
241
|
+
userId: actor.userId,
|
|
242
|
+
...actor.userName ? { userName: actor.userName } : void 0
|
|
243
|
+
},
|
|
244
|
+
message: entry.message,
|
|
245
|
+
source: "web"
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
function parseResourceEventMessages(messages) {
|
|
250
|
+
if (messages.length === 0) {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
if (!messages.every(
|
|
254
|
+
(message) => message.source === "resource_event" && isResourceEventMailboxMetadata(message.input.metadata)
|
|
255
|
+
)) {
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
return messages.map((message) => {
|
|
259
|
+
if (!isResourceEventMailboxMetadata(message.input.metadata)) {
|
|
260
|
+
throw new Error("Resource event has invalid metadata");
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
actor: RESOURCE_EVENT_SYSTEM_ACTOR,
|
|
264
|
+
author: RESOURCE_EVENT_MESSAGE_AUTHOR,
|
|
265
|
+
message,
|
|
266
|
+
source: "resource_event"
|
|
267
|
+
};
|
|
180
268
|
});
|
|
181
269
|
}
|
|
182
270
|
async function resolveApiTurnWork(context) {
|
|
@@ -184,6 +272,12 @@ async function resolveApiTurnWork(context) {
|
|
|
184
272
|
if (batch.length > 0) {
|
|
185
273
|
return { kind: "mailbox", batch };
|
|
186
274
|
}
|
|
275
|
+
if (context.destination?.platform === "local") {
|
|
276
|
+
const resourceBatch = parseResourceEventMessages(context.attempt.messages);
|
|
277
|
+
if (resourceBatch.length > 0) {
|
|
278
|
+
return { kind: "mailbox", batch: resourceBatch };
|
|
279
|
+
}
|
|
280
|
+
}
|
|
187
281
|
if (context.attempt.messages.length > 0) {
|
|
188
282
|
return void 0;
|
|
189
283
|
}
|
|
@@ -197,16 +291,15 @@ async function isApiTurnWork(context) {
|
|
|
197
291
|
// src/chat/api-turns/work.ts
|
|
198
292
|
import { createHash } from "crypto";
|
|
199
293
|
import {
|
|
200
|
-
createWebSource,
|
|
201
294
|
localDestinationSchema
|
|
202
295
|
} from "@sentry/junior-plugin-api";
|
|
203
296
|
|
|
204
|
-
// src/chat/api-turns/
|
|
205
|
-
async function
|
|
297
|
+
// src/chat/api-turns/assistant-message.ts
|
|
298
|
+
async function commitAssistantMessage(args) {
|
|
206
299
|
const conversationMessageId = recordDeliveredAssistantMessage({
|
|
207
300
|
conversation: args.conversation,
|
|
208
301
|
sessionId: args.sessionId,
|
|
209
|
-
source:
|
|
302
|
+
source: args.source,
|
|
210
303
|
text: args.text,
|
|
211
304
|
userMessageId: args.userMessageId
|
|
212
305
|
});
|
|
@@ -221,8 +314,8 @@ async function commitWebAcceptedReply(args) {
|
|
|
221
314
|
);
|
|
222
315
|
} catch (error) {
|
|
223
316
|
logException(
|
|
224
|
-
new Error("
|
|
225
|
-
"
|
|
317
|
+
new Error("Assistant message persistence failed"),
|
|
318
|
+
"conversation.assistant.message_persist.failed",
|
|
226
319
|
{
|
|
227
320
|
"error.type": error instanceof Error ? error.name : typeof error
|
|
228
321
|
}
|
|
@@ -287,7 +380,7 @@ function createApiTurnCancellation() {
|
|
|
287
380
|
}
|
|
288
381
|
async function completeCancelledApiTurn(args) {
|
|
289
382
|
try {
|
|
290
|
-
const
|
|
383
|
+
const pendingAuthorization = args.conversation.processing.pendingAuth?.sessionId === args.turnId ? args.conversation.processing.pendingAuth : void 0;
|
|
291
384
|
await abandonTurnRecord({
|
|
292
385
|
conversationId: args.conversationId,
|
|
293
386
|
turnId: args.turnId,
|
|
@@ -303,9 +396,9 @@ async function completeCancelledApiTurn(args) {
|
|
|
303
396
|
nowMs: Date.now(),
|
|
304
397
|
sessionId: args.turnId
|
|
305
398
|
});
|
|
306
|
-
if (
|
|
399
|
+
if (pendingAuthorization) {
|
|
307
400
|
await deleteWebAuthorization({
|
|
308
|
-
actorId:
|
|
401
|
+
actorId: pendingAuthorization.actorId,
|
|
309
402
|
conversationId: args.conversationId
|
|
310
403
|
});
|
|
311
404
|
}
|
|
@@ -329,6 +422,11 @@ async function completeCancelledApiTurn(args) {
|
|
|
329
422
|
await args.acknowledge();
|
|
330
423
|
}
|
|
331
424
|
|
|
425
|
+
// src/chat/api-turns/mailbox-input.ts
|
|
426
|
+
function joinMailboxText(messages) {
|
|
427
|
+
return messages.map((message) => message.input.text.trim()).filter(Boolean).join("\n\n");
|
|
428
|
+
}
|
|
429
|
+
|
|
332
430
|
// src/chat/api-turns/work.ts
|
|
333
431
|
function normalizeEmail(email) {
|
|
334
432
|
return email.trim().toLowerCase();
|
|
@@ -364,21 +462,6 @@ function resolveApiTurnDestination(args) {
|
|
|
364
462
|
}
|
|
365
463
|
return requireLocalDestination(args.conversationId);
|
|
366
464
|
}
|
|
367
|
-
function webSourceForConversation(args) {
|
|
368
|
-
return createWebSource(
|
|
369
|
-
args.conversationId,
|
|
370
|
-
args.visibility === "private" ? "private" : "public"
|
|
371
|
-
);
|
|
372
|
-
}
|
|
373
|
-
function actorFromMetadata(metadata) {
|
|
374
|
-
return {
|
|
375
|
-
platform: "web",
|
|
376
|
-
userId: metadata.authorUserId,
|
|
377
|
-
email: normalizeEmail(metadata.authorEmail),
|
|
378
|
-
...metadata.authorFullName ? { fullName: metadata.authorFullName } : void 0,
|
|
379
|
-
...metadata.authorUserName ? { userName: metadata.authorUserName } : void 0
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
465
|
function storedActorFromApi(actor) {
|
|
383
466
|
return {
|
|
384
467
|
...actor.email ? { email: normalizeEmail(actor.email) } : void 0,
|
|
@@ -395,16 +478,6 @@ function webActorFromEmail(email, profile) {
|
|
|
395
478
|
...profile?.userName ? { userName: profile.userName } : void 0
|
|
396
479
|
};
|
|
397
480
|
}
|
|
398
|
-
function actorFromStoredConversation(stored) {
|
|
399
|
-
const email = stored?.email?.trim().toLowerCase();
|
|
400
|
-
if (!email) {
|
|
401
|
-
return void 0;
|
|
402
|
-
}
|
|
403
|
-
return webActorFromEmail(
|
|
404
|
-
email,
|
|
405
|
-
stored?.fullName ? { fullName: stored.fullName } : void 0
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
481
|
function buildApiTurnInboundMessage(args) {
|
|
409
482
|
const text = args.message.trim();
|
|
410
483
|
if (!text) {
|
|
@@ -450,8 +523,9 @@ async function recordApiConversationActivity(args) {
|
|
|
450
523
|
});
|
|
451
524
|
const isNewRoot = !existing;
|
|
452
525
|
const visibility = args.rootVisibility === "private" ? "private" : "public";
|
|
453
|
-
const source = isNewRoot ?
|
|
526
|
+
const source = isNewRoot ? sourceFromTurnInput({
|
|
454
527
|
conversationId: args.conversationId,
|
|
528
|
+
source: "web",
|
|
455
529
|
visibility
|
|
456
530
|
}) : void 0;
|
|
457
531
|
await store.recordActivity({
|
|
@@ -545,65 +619,84 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
545
619
|
const resolved = await resolveApiTurnWork(context);
|
|
546
620
|
if (!resolved) {
|
|
547
621
|
throw new Error(
|
|
548
|
-
`
|
|
622
|
+
`Unsupported input for Conversation ${context.conversationId}`
|
|
549
623
|
);
|
|
550
624
|
}
|
|
551
625
|
if (context.publishExternally) {
|
|
552
626
|
throw new Error(
|
|
553
|
-
`
|
|
627
|
+
`publishExternally must be false for Conversation ${context.conversationId}`
|
|
554
628
|
);
|
|
555
629
|
}
|
|
556
630
|
const lifecycle = new ConversationTurnLifecycleService(
|
|
557
631
|
getConversationEventStore()
|
|
558
632
|
);
|
|
559
633
|
const isResume = resolved.kind === "resume";
|
|
560
|
-
let
|
|
561
|
-
let text;
|
|
562
|
-
let turnId;
|
|
563
|
-
let userMessageId;
|
|
564
|
-
let startedAtMs;
|
|
565
|
-
let inputMessageIds;
|
|
634
|
+
let turnIdentity;
|
|
635
|
+
let text = "";
|
|
636
|
+
let turnId = "";
|
|
637
|
+
let userMessageId = "";
|
|
638
|
+
let startedAtMs = Date.now();
|
|
639
|
+
let inputMessageIds = [];
|
|
566
640
|
const storedConversation = await getConversationStore().get({
|
|
567
641
|
conversationId: context.conversationId
|
|
568
642
|
});
|
|
643
|
+
const mailboxDestination = resolved.kind === "mailbox" ? resolved.batch[0]?.message.destination : void 0;
|
|
644
|
+
const destination = resolveApiTurnDestination({
|
|
645
|
+
conversationId: context.conversationId,
|
|
646
|
+
existing: context.destination ?? mailboxDestination ?? storedConversation?.destination
|
|
647
|
+
});
|
|
569
648
|
if (resolved.kind === "mailbox") {
|
|
570
649
|
const first = resolved.batch[0];
|
|
571
|
-
text = resolved.batch.map((entry) => entry.message
|
|
572
|
-
actor = actorFromMetadata(first.metadata);
|
|
573
|
-
turnId = apiTurnIdForMessage(first.metadata.messageId);
|
|
574
|
-
userMessageId = first.metadata.messageId;
|
|
650
|
+
text = joinMailboxText(resolved.batch.map((entry) => entry.message));
|
|
575
651
|
startedAtMs = first.message.createdAtMs;
|
|
576
|
-
|
|
652
|
+
userMessageId = first.message.inboundMessageId;
|
|
653
|
+
turnId = apiTurnIdForMessage(userMessageId);
|
|
654
|
+
inputMessageIds = resolved.batch.map(
|
|
655
|
+
(entry) => entry.message.inboundMessageId
|
|
656
|
+
);
|
|
657
|
+
turnIdentity = first;
|
|
577
658
|
} else {
|
|
578
659
|
turnId = resolved.turnId;
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
660
|
+
}
|
|
661
|
+
const persisted = await getPersistedThreadState(context.conversationId);
|
|
662
|
+
const conversation = coerceThreadConversationState(persisted);
|
|
663
|
+
await hydrateConversationMessages({
|
|
664
|
+
conversation,
|
|
665
|
+
conversationId: context.conversationId
|
|
666
|
+
});
|
|
667
|
+
if (isResume) {
|
|
668
|
+
const userMessage = getTurnUserMessage(conversation, turnId);
|
|
669
|
+
if (!userMessage) {
|
|
583
670
|
throw new Error(
|
|
584
|
-
`
|
|
671
|
+
`Unable to locate the persisted user message for Turn "${turnId}"`
|
|
585
672
|
);
|
|
586
673
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
startedAtMs =
|
|
591
|
-
inputMessageIds = [];
|
|
674
|
+
turnIdentity = turnIdentityFromConversationMessage(userMessage);
|
|
675
|
+
userMessageId = userMessage.id;
|
|
676
|
+
text = userMessage.text;
|
|
677
|
+
startedAtMs = userMessage.createdAtMs;
|
|
678
|
+
inputMessageIds = [userMessageId];
|
|
592
679
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
680
|
+
if (!turnIdentity) {
|
|
681
|
+
throw new Error(
|
|
682
|
+
`Resumed Turn is missing an Actor for Conversation ${context.conversationId}`
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
const { actor, author } = turnIdentity;
|
|
686
|
+
const source = sourceFromTurnInput({
|
|
598
687
|
conversationId: context.conversationId,
|
|
688
|
+
source: turnIdentity.source,
|
|
599
689
|
visibility: storedConversation?.visibility
|
|
600
690
|
});
|
|
691
|
+
const webActor = actor.platform === "web" ? actor : void 0;
|
|
601
692
|
return await withLogContext(
|
|
602
693
|
{
|
|
603
694
|
conversationId: context.conversationId,
|
|
604
|
-
platform:
|
|
605
|
-
|
|
606
|
-
|
|
695
|
+
platform: actor.platform,
|
|
696
|
+
...webActor ? {
|
|
697
|
+
userId: webActor.userId,
|
|
698
|
+
...webActor.userName ? { userName: webActor.userName } : void 0
|
|
699
|
+
} : void 0
|
|
607
700
|
},
|
|
608
701
|
async () => {
|
|
609
702
|
let acknowledged = isResume || context.attempt.messages.length === 0;
|
|
@@ -620,12 +713,6 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
620
713
|
}
|
|
621
714
|
acknowledged = true;
|
|
622
715
|
};
|
|
623
|
-
const persisted = await getPersistedThreadState(context.conversationId);
|
|
624
|
-
const conversation = coerceThreadConversationState(persisted);
|
|
625
|
-
await hydrateConversationMessages({
|
|
626
|
-
conversation,
|
|
627
|
-
conversationId: context.conversationId
|
|
628
|
-
});
|
|
629
716
|
let sandboxRef = getPersistedSandboxState(persisted);
|
|
630
717
|
const initialSandboxRef = sandboxRef;
|
|
631
718
|
const appSignal = cancellation?.signal(context.conversationId);
|
|
@@ -640,7 +727,6 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
640
727
|
try {
|
|
641
728
|
await completeCancelledApiTurn({
|
|
642
729
|
acknowledge,
|
|
643
|
-
actorId: actor.userId,
|
|
644
730
|
cancellation,
|
|
645
731
|
conversation,
|
|
646
732
|
conversationId: context.conversationId,
|
|
@@ -658,16 +744,6 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
658
744
|
return { status: "completed" };
|
|
659
745
|
};
|
|
660
746
|
if (isResume) {
|
|
661
|
-
const userMessage = getTurnUserMessage(conversation, turnId);
|
|
662
|
-
if (!userMessage) {
|
|
663
|
-
throw new Error(
|
|
664
|
-
`Unable to locate the persisted user message for Turn "${turnId}"`
|
|
665
|
-
);
|
|
666
|
-
}
|
|
667
|
-
userMessageId = userMessage.id;
|
|
668
|
-
text = userMessage.text;
|
|
669
|
-
startedAtMs = userMessage.createdAtMs;
|
|
670
|
-
inputMessageIds = [userMessageId];
|
|
671
747
|
if (cancellationSignal?.aborted) {
|
|
672
748
|
return await completeCancelledTurn();
|
|
673
749
|
}
|
|
@@ -677,16 +753,11 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
677
753
|
role: "user",
|
|
678
754
|
text: normalizeConversationText(text),
|
|
679
755
|
createdAtMs: startedAtMs,
|
|
680
|
-
author
|
|
681
|
-
...actor.email ? { email: actor.email } : void 0,
|
|
682
|
-
...actor.fullName ? { fullName: actor.fullName } : void 0,
|
|
683
|
-
userId: actor.userId,
|
|
684
|
-
...actor.userName ? { userName: actor.userName } : void 0
|
|
685
|
-
},
|
|
756
|
+
author,
|
|
686
757
|
meta: {
|
|
687
758
|
explicitMention: true,
|
|
688
759
|
replied: false,
|
|
689
|
-
source: "web"
|
|
760
|
+
...turnIdentity.source === "web" ? { source: "web" } : void 0
|
|
690
761
|
}
|
|
691
762
|
});
|
|
692
763
|
await persistConversationMessages({
|
|
@@ -722,11 +793,12 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
722
793
|
}
|
|
723
794
|
failureCode = "delivery_failed";
|
|
724
795
|
assistantMessageDelivered = true;
|
|
725
|
-
await
|
|
796
|
+
await commitAssistantMessage({
|
|
726
797
|
...agentMessage ? { agentMessage } : void 0,
|
|
727
798
|
conversation,
|
|
728
799
|
conversationId: context.conversationId,
|
|
729
800
|
sessionId: turnId,
|
|
801
|
+
...turnIdentity.source === "web" ? { source: "web" } : void 0,
|
|
730
802
|
text: replyText,
|
|
731
803
|
userMessageId
|
|
732
804
|
});
|
|
@@ -737,6 +809,7 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
737
809
|
return await completeCancelledTurn();
|
|
738
810
|
}
|
|
739
811
|
if (!isResume) {
|
|
812
|
+
const pendingAuthorizationActorId = conversation.processing.pendingAuth?.actorId;
|
|
740
813
|
const authParked = (await listTurnSummaries(context.conversationId)).filter(
|
|
741
814
|
(summary) => summary.surface === "api" && !summary.dispatchId && summary.state === "paused" && summary.resumeReason === "auth"
|
|
742
815
|
);
|
|
@@ -747,7 +820,7 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
747
820
|
await abandonTurnRecord({
|
|
748
821
|
conversationId: context.conversationId,
|
|
749
822
|
turnId: parked.turnId,
|
|
750
|
-
errorMessage: "Auth-
|
|
823
|
+
errorMessage: "Auth-paused Turn superseded by new input"
|
|
751
824
|
});
|
|
752
825
|
markTurnClosed({
|
|
753
826
|
conversation,
|
|
@@ -755,9 +828,9 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
755
828
|
sessionId: parked.turnId
|
|
756
829
|
});
|
|
757
830
|
}
|
|
758
|
-
if (authParked.length > 0) {
|
|
831
|
+
if (authParked.length > 0 && pendingAuthorizationActorId) {
|
|
759
832
|
await deleteWebAuthorization({
|
|
760
|
-
actorId:
|
|
833
|
+
actorId: pendingAuthorizationActorId,
|
|
761
834
|
conversationId: context.conversationId
|
|
762
835
|
});
|
|
763
836
|
}
|
|
@@ -790,14 +863,17 @@ function createApiTurnWorker(agentRunner, cancellation) {
|
|
|
790
863
|
actor,
|
|
791
864
|
credentialContext: credentialContextForActor(actor),
|
|
792
865
|
destination,
|
|
866
|
+
...storedConversation?.location ? { location: storedConversation.location } : void 0,
|
|
793
867
|
publishExternally: false,
|
|
794
868
|
source,
|
|
795
869
|
surface: "api",
|
|
796
870
|
...cancellationSignal ? { signal: cancellationSignal } : void 0,
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
871
|
+
...webActor ? {
|
|
872
|
+
authorization: createWebAuthorization({
|
|
873
|
+
actorId: webActor.userId,
|
|
874
|
+
conversationId: context.conversationId
|
|
875
|
+
})
|
|
876
|
+
} : { disabledFeatures: ["interactive-auth"] },
|
|
801
877
|
state: {
|
|
802
878
|
pendingAuth: conversation.processing.pendingAuth,
|
|
803
879
|
sandboxRef
|
|
@@ -1227,6 +1303,91 @@ async function readConversationAccessFromSql(db, conversationIds, viewer) {
|
|
|
1227
1303
|
);
|
|
1228
1304
|
}
|
|
1229
1305
|
|
|
1306
|
+
// src/chat/slack/user.ts
|
|
1307
|
+
import { z as z2 } from "zod";
|
|
1308
|
+
var slackUserInfoSchema = z2.object({
|
|
1309
|
+
ok: z2.literal(true),
|
|
1310
|
+
user: z2.object({
|
|
1311
|
+
name: z2.string().nullish(),
|
|
1312
|
+
profile: z2.object({
|
|
1313
|
+
email: z2.string().nullish(),
|
|
1314
|
+
real_name: z2.string().nullish()
|
|
1315
|
+
}).optional()
|
|
1316
|
+
})
|
|
1317
|
+
});
|
|
1318
|
+
var USER_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1319
|
+
var userCache = /* @__PURE__ */ new Map();
|
|
1320
|
+
function userCacheKey(teamId, userId) {
|
|
1321
|
+
return `${teamId}:${userId}`;
|
|
1322
|
+
}
|
|
1323
|
+
function readFromCache(teamId, userId) {
|
|
1324
|
+
const hit = userCache.get(userCacheKey(teamId, userId));
|
|
1325
|
+
if (!hit) return null;
|
|
1326
|
+
if (hit.expiresAt < Date.now()) {
|
|
1327
|
+
userCache.delete(userCacheKey(teamId, userId));
|
|
1328
|
+
return null;
|
|
1329
|
+
}
|
|
1330
|
+
return hit.value;
|
|
1331
|
+
}
|
|
1332
|
+
function writeToCache(teamId, userId, value) {
|
|
1333
|
+
userCache.set(userCacheKey(teamId, userId), {
|
|
1334
|
+
value,
|
|
1335
|
+
expiresAt: Date.now() + USER_CACHE_TTL_MS
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
async function lookupSlackUser(teamId, userId) {
|
|
1339
|
+
if (!teamId || !userId) {
|
|
1340
|
+
return null;
|
|
1341
|
+
}
|
|
1342
|
+
const cached = readFromCache(teamId, userId);
|
|
1343
|
+
if (cached) {
|
|
1344
|
+
return cached;
|
|
1345
|
+
}
|
|
1346
|
+
const token = getSlackBotToken();
|
|
1347
|
+
if (!token) {
|
|
1348
|
+
return null;
|
|
1349
|
+
}
|
|
1350
|
+
try {
|
|
1351
|
+
const response = await fetch(
|
|
1352
|
+
`https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`,
|
|
1353
|
+
{
|
|
1354
|
+
headers: {
|
|
1355
|
+
authorization: `Bearer ${token}`
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
);
|
|
1359
|
+
if (!response.ok) {
|
|
1360
|
+
logWarn("slack.user.lookup.failed", {
|
|
1361
|
+
"enduser.id": userId,
|
|
1362
|
+
"app.slack.team_id": teamId,
|
|
1363
|
+
"http.response.status_code": response.status
|
|
1364
|
+
});
|
|
1365
|
+
return null;
|
|
1366
|
+
}
|
|
1367
|
+
const parsed = slackUserInfoSchema.safeParse(await response.json());
|
|
1368
|
+
if (!parsed.success) {
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
const payload = parsed.data;
|
|
1372
|
+
const userName = payload.user.name?.trim() || void 0;
|
|
1373
|
+
const fullName = payload.user.profile?.real_name?.trim() || void 0;
|
|
1374
|
+
const result = {
|
|
1375
|
+
userName,
|
|
1376
|
+
fullName,
|
|
1377
|
+
email: payload.user.profile?.email?.trim() || void 0
|
|
1378
|
+
};
|
|
1379
|
+
writeToCache(teamId, userId, result);
|
|
1380
|
+
return result;
|
|
1381
|
+
} catch (error) {
|
|
1382
|
+
logWarn("slack.user.lookup.failed", {
|
|
1383
|
+
"enduser.id": userId,
|
|
1384
|
+
"app.slack.team_id": teamId,
|
|
1385
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
1386
|
+
});
|
|
1387
|
+
return null;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1230
1391
|
// src/chat/slack/conversation-context.ts
|
|
1231
1392
|
function normalizeConversationName(type, channelName) {
|
|
1232
1393
|
const trimmed = channelName?.trim();
|
|
@@ -1315,6 +1476,7 @@ export {
|
|
|
1315
1476
|
readHealthReport,
|
|
1316
1477
|
GET,
|
|
1317
1478
|
createVercelAttachmentStorage,
|
|
1479
|
+
lookupSlackUser,
|
|
1318
1480
|
conversationVisibilityFromSlackChannelType,
|
|
1319
1481
|
resolveSlackChannelTypeFromMessage,
|
|
1320
1482
|
resolveSlackConversationContext,
|
|
@@ -29,7 +29,9 @@ function assertRunConsistency(run) {
|
|
|
29
29
|
switch (source.platform) {
|
|
30
30
|
case "slack": {
|
|
31
31
|
if (destination.platform !== "slack") {
|
|
32
|
-
throw new TypeError(
|
|
32
|
+
throw new TypeError(
|
|
33
|
+
"Run source and destination platforms do not match"
|
|
34
|
+
);
|
|
33
35
|
}
|
|
34
36
|
if (source.teamId !== destination.teamId) {
|
|
35
37
|
throw new TypeError("Slack source and destination teams do not match");
|
|
@@ -38,7 +40,9 @@ function assertRunConsistency(run) {
|
|
|
38
40
|
}
|
|
39
41
|
case "local": {
|
|
40
42
|
if (destination.platform !== "local") {
|
|
41
|
-
throw new TypeError(
|
|
43
|
+
throw new TypeError(
|
|
44
|
+
"Run source and destination platforms do not match"
|
|
45
|
+
);
|
|
42
46
|
}
|
|
43
47
|
if (source.conversationId !== destination.conversationId) {
|
|
44
48
|
throw new TypeError(
|