@sentry/junior 0.138.0 → 0.140.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-SCR74Q3E.js → agent-hooks-BFTDRFUO.js} +10 -10
- package/dist/api/schema/task.d.ts +104 -1
- package/dist/api/schema.d.ts +2 -2
- package/dist/api/schema.js +9 -1
- package/dist/api.js +198 -54
- package/dist/app.js +374 -607
- package/dist/{catalog-runtime-IU3QF4GG.js → catalog-runtime-RK664S5T.js} +6 -6
- package/dist/chat/agent/request.d.ts +12 -2
- package/dist/chat/credentials/context.d.ts +14 -0
- package/dist/chat/resource-events/actor.d.ts +23 -0
- package/dist/chat/scheduled-tasks/telemetry.d.ts +7 -0
- package/dist/chat/scheduled-tasks/tool-support.d.ts +10 -2
- package/dist/chat/scheduled-tasks/tools/create.d.ts +4 -2
- package/dist/chat/scheduled-tasks/tools/delete.d.ts +4 -2
- package/dist/chat/scheduled-tasks/tools/list.d.ts +4 -2
- package/dist/chat/scheduled-tasks/tools/run-now.d.ts +4 -2
- package/dist/chat/scheduled-tasks/tools/update.d.ts +4 -2
- package/dist/chat/scheduled-tasks/types.d.ts +1 -1
- package/dist/chat/slack/dashboard-link.d.ts +2 -0
- package/dist/chat/state/turn-session-keys.d.ts +2 -2
- package/dist/chat/state/turn-session.d.ts +16 -12
- package/dist/chat/tasks/execution-stats.d.ts +34 -3
- package/dist/chat/tasks/read.d.ts +3 -1
- package/dist/chunk-3B7O3GNU.js +207 -0
- package/dist/{chunk-N7WARMC6.js → chunk-3CUBAGA3.js} +7 -7
- package/dist/{chunk-5MXWHTCK.js → chunk-4PIT6O7A.js} +17 -8
- package/dist/{chunk-DCLLQGS6.js → chunk-557HLSNH.js} +8 -3
- package/dist/{chunk-SD3OFRWY.js → chunk-5KAZMR5U.js} +6 -6
- package/dist/{chunk-ZBSMCXKV.js → chunk-5YAWB2AX.js} +7 -6
- package/dist/{chunk-FEUNPTGV.js → chunk-A6BI25J3.js} +434 -12
- package/dist/{chunk-5LTJ4ITU.js → chunk-AA2EPMUF.js} +4 -4
- package/dist/{chunk-TUUDXEXU.js → chunk-BMFRFSTM.js} +68 -79
- package/dist/{chunk-C7ZVPO4Z.js → chunk-CPPTBHQN.js} +1 -1
- package/dist/{chunk-ZXNTJJIE.js → chunk-D3X2PI3D.js} +2 -2
- package/dist/{chunk-LPVUNO2W.js → chunk-DMDOKRPC.js} +7 -7
- package/dist/{chunk-TCS76X5D.js → chunk-HEFBGCCU.js} +2 -2
- package/dist/{chunk-EPBBYMNE.js → chunk-HUO3UTAQ.js} +1 -1
- package/dist/{chunk-KFRHRSCJ.js → chunk-I3OZR3HG.js} +2 -2
- package/dist/{chunk-BOLJOV5T.js → chunk-J5H65GY2.js} +1 -1
- package/dist/{chunk-RZIBSCYC.js → chunk-MYVCHWDG.js} +39 -23
- package/dist/{chunk-QS527AV5.js → chunk-N2I7W2VS.js} +1 -1
- package/dist/{chunk-JNNJZURV.js → chunk-NPL66ZWL.js} +1 -1
- package/dist/{chunk-A7WCHXZV.js → chunk-OGNL2QY7.js} +4 -4
- package/dist/{chunk-77VDLF3Z.js → chunk-RUIXF3YQ.js} +10 -0
- package/dist/{chunk-BYW4B4PR.js → chunk-S3FAOKQU.js} +2 -2
- package/dist/chunk-TGIKZJ3Y.js +115 -0
- package/dist/{chunk-YU5QUF67.js → chunk-TKTZ4L4Z.js} +1 -1
- package/dist/{chunk-VPZFVJND.js → chunk-UXMRN2ZX.js} +1 -1
- package/dist/{chunk-HIWJWWMT.js → chunk-VRDHAITB.js} +3 -3
- package/dist/{chunk-SIPKWSXK.js → chunk-WSWM6A3R.js} +3 -3
- package/dist/{chunk-FNLBTB4K.js → chunk-WTGLUX4K.js} +1 -1
- package/dist/{chunk-PB3CXNVL.js → chunk-XROWZSOY.js} +1 -1
- package/dist/{chunk-TDJCLNDH.js → chunk-XX2QNQN4.js} +147 -86
- package/dist/{chunk-KDCHVT25.js → chunk-YB363QGA.js} +9 -2
- package/dist/{chunk-HCIVH3JS.js → chunk-YWM6MJT4.js} +29 -1
- package/dist/{chunk-E5UYAIKJ.js → chunk-Z2A7BDHT.js} +17 -19
- package/dist/cli/chat.js +33 -33
- package/dist/cli/check.js +7 -7
- package/dist/cli/plugins.js +14 -14
- package/dist/cli/snapshot-create.js +10 -10
- package/dist/cli/upgrade.js +8 -8
- package/dist/db/schema/task-executions.d.ts +23 -2
- package/dist/db/schema.d.ts +20 -1
- package/dist/{db-UO2IWXGA.js → db-QOGYDDQM.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-MAQI43LX.js → oauth-callback-server-CT4RMGCP.js} +22 -21
- package/dist/{runner-PIUQEXKE.js → runner-PHMLHNLX.js} +18 -16
- package/dist/{sandbox-egress-signals-A5HWIQH4.js → sandbox-egress-signals-EKPAVWQL.js} +2 -2
- package/dist/{skills-4ARJADHQ.js → skills-AYRM4QGF.js} +7 -7
- package/dist/spawn-OGRQFUNK.js +38 -0
- package/dist/{validation-S3EE3HWL.js → validation-M5JNGRGL.js} +7 -7
- package/dist/version.js +1 -1
- package/dist/{work-UARRUAW3.js → work-LZWE6HK4.js} +18 -18
- package/dist/{worker-DOCIRVD3.js → worker-KOGPXFYK.js} +10 -10
- package/migrations/0022_task_execution_status.sql +3 -0
- package/migrations/meta/0022_snapshot.json +2186 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +5 -5
- package/dist/chunk-ELKW5FIB.js +0 -233
- package/dist/spawn-G2AWPMCT.js +0 -38
package/dist/app.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
processConversationWork
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VRDHAITB.js";
|
|
4
4
|
import {
|
|
5
5
|
bindSpawnAgent
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XROWZSOY.js";
|
|
7
7
|
import {
|
|
8
8
|
createAgentInvocationWorker,
|
|
9
9
|
enqueueAgentInvocation,
|
|
10
10
|
listPendingAgentInvocationMailboxAppends,
|
|
11
11
|
routeAgentInvocationWork
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-5YAWB2AX.js";
|
|
13
13
|
import {
|
|
14
14
|
GET as GET2,
|
|
15
15
|
GET2 as GET3,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
splitSlackReplyText,
|
|
40
40
|
startSlackProcessingReaction,
|
|
41
41
|
stripLeadingBotMention
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-Z2A7BDHT.js";
|
|
43
43
|
import "./chunk-FA6POGLH.js";
|
|
44
44
|
import {
|
|
45
45
|
CONVERSATION_WORK_STALE_ENQUEUE_MS,
|
|
@@ -51,32 +51,50 @@ import {
|
|
|
51
51
|
isInvalidConversationRecordError,
|
|
52
52
|
listActiveConversationIds,
|
|
53
53
|
removeActiveConversation
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-AA2EPMUF.js";
|
|
55
55
|
import {
|
|
56
56
|
buildDeliveredTurnStatePatch,
|
|
57
|
+
claimDispatchMailboxAppend,
|
|
57
58
|
completeAuthPauseTurn,
|
|
59
|
+
confirmDispatchMailboxAppend,
|
|
60
|
+
createOrGetDispatch,
|
|
58
61
|
finalizeFailedTurnReplyWithEvent,
|
|
59
62
|
getAgentTurnDiagnosticsAttributes,
|
|
63
|
+
getDispatchConversationId,
|
|
64
|
+
getDispatchInputMessageId,
|
|
65
|
+
getDispatchInputMessageIds,
|
|
66
|
+
getDispatchRecord,
|
|
67
|
+
getDispatchTurnId,
|
|
68
|
+
getPluginDispatchProjection,
|
|
60
69
|
getTurnUserMessage,
|
|
61
70
|
getTurnUserReplyAttachmentContext,
|
|
62
71
|
getTurnUserSlackMessageTs,
|
|
72
|
+
isTerminalDispatchStatus,
|
|
73
|
+
listPendingDispatchMailboxAppends,
|
|
74
|
+
markDispatchAwaitingResume,
|
|
75
|
+
markDispatchBlocked,
|
|
76
|
+
markDispatchCompleted,
|
|
77
|
+
markDispatchFailed,
|
|
78
|
+
markDispatchRunning,
|
|
63
79
|
persistAuthPauseTurnState,
|
|
64
80
|
processPluginTask,
|
|
65
81
|
requireTurnFailureEventId,
|
|
66
82
|
resolveTurnSessionRouting,
|
|
67
83
|
scheduleSessionCompletedPluginTasks
|
|
68
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-A6BI25J3.js";
|
|
69
85
|
import {
|
|
70
86
|
ConversationTurnLifecycleService
|
|
71
87
|
} from "./chunk-Q6QZTTLS.js";
|
|
72
88
|
import {
|
|
73
89
|
GET,
|
|
74
90
|
conversationVisibilityFromSlackChannelType,
|
|
75
|
-
recordTaskExecution,
|
|
76
91
|
resolveSlackChannelTypeFromMessage,
|
|
77
92
|
resolveSlackConversationContext
|
|
78
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-TGIKZJ3Y.js";
|
|
79
94
|
import "./chunk-4CODA7P5.js";
|
|
95
|
+
import {
|
|
96
|
+
recordTaskExecution
|
|
97
|
+
} from "./chunk-3B7O3GNU.js";
|
|
80
98
|
import "./chunk-UTL3MHPC.js";
|
|
81
99
|
import {
|
|
82
100
|
getVercelConversationWorkQueue,
|
|
@@ -95,7 +113,7 @@ import {
|
|
|
95
113
|
import {
|
|
96
114
|
validatePluginEgressCredentialHooks,
|
|
97
115
|
validatePluginRegistrations
|
|
98
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-TKTZ4L4Z.js";
|
|
99
117
|
import {
|
|
100
118
|
defineJuniorPlugins,
|
|
101
119
|
pluginCatalogConfigFromEnv,
|
|
@@ -128,18 +146,18 @@ import {
|
|
|
128
146
|
setConfigDefaults,
|
|
129
147
|
shouldEmitDevAgentTrace,
|
|
130
148
|
shouldPropagateSandboxEgressTrace
|
|
131
|
-
} from "./chunk-
|
|
149
|
+
} from "./chunk-MYVCHWDG.js";
|
|
132
150
|
import {
|
|
133
151
|
AuthorizationFlowDisabledError,
|
|
134
152
|
PluginCredentialFailureError
|
|
135
|
-
} from "./chunk-
|
|
153
|
+
} from "./chunk-DMDOKRPC.js";
|
|
136
154
|
import "./chunk-DIB4GX3G.js";
|
|
137
155
|
import {
|
|
138
156
|
createUserTokenStore,
|
|
139
157
|
deleteMcpAuthSessionsForUserProvider,
|
|
140
158
|
deleteMcpServerSessionId,
|
|
141
159
|
deleteMcpStoredOAuthCredentials
|
|
142
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-3CUBAGA3.js";
|
|
143
161
|
import {
|
|
144
162
|
RetryableDeliveryError
|
|
145
163
|
} from "./chunk-R776HKPK.js";
|
|
@@ -147,7 +165,7 @@ import {
|
|
|
147
165
|
formatProviderLabel,
|
|
148
166
|
postSlackMessage,
|
|
149
167
|
startOAuthFlow
|
|
150
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-5KAZMR5U.js";
|
|
151
169
|
import {
|
|
152
170
|
ConversationTurnBoundaryError,
|
|
153
171
|
CooperativeTurnYieldError,
|
|
@@ -203,11 +221,9 @@ import {
|
|
|
203
221
|
trimTrailingAssistantMessages,
|
|
204
222
|
updateConversationStats,
|
|
205
223
|
upsertConversationMessage
|
|
206
|
-
} from "./chunk-
|
|
207
|
-
import
|
|
208
|
-
|
|
209
|
-
} from "./chunk-3Y47VMHV.js";
|
|
210
|
-
import "./chunk-EPBBYMNE.js";
|
|
224
|
+
} from "./chunk-BMFRFSTM.js";
|
|
225
|
+
import "./chunk-3Y47VMHV.js";
|
|
226
|
+
import "./chunk-HUO3UTAQ.js";
|
|
211
227
|
import {
|
|
212
228
|
getExperimentalFeatures,
|
|
213
229
|
setExperimentalFeatures
|
|
@@ -215,14 +231,16 @@ import {
|
|
|
215
231
|
import {
|
|
216
232
|
getSandboxResourceConfig,
|
|
217
233
|
setSandboxResourceConfig
|
|
218
|
-
} from "./chunk-
|
|
234
|
+
} from "./chunk-OGNL2QY7.js";
|
|
219
235
|
import {
|
|
220
236
|
createSchedulerSqlStore,
|
|
221
|
-
findMatchingEventTasks
|
|
222
|
-
|
|
237
|
+
findMatchingEventTasks,
|
|
238
|
+
logScheduledTaskRunSkipped,
|
|
239
|
+
scheduledTaskRunAttributes
|
|
240
|
+
} from "./chunk-XX2QNQN4.js";
|
|
223
241
|
import {
|
|
224
242
|
parseSlackThreadId
|
|
225
|
-
} from "./chunk-
|
|
243
|
+
} from "./chunk-WTGLUX4K.js";
|
|
226
244
|
import "./chunk-CDQ4YIZM.js";
|
|
227
245
|
import "./chunk-PDO5BLNM.js";
|
|
228
246
|
import "./chunk-UIE3R5XU.js";
|
|
@@ -242,7 +260,7 @@ import {
|
|
|
242
260
|
verifyEventTaskCredentialSubject,
|
|
243
261
|
verifyScheduledTaskCredentialSubject,
|
|
244
262
|
verifySlackDirectCredentialSubject
|
|
245
|
-
} from "./chunk-
|
|
263
|
+
} from "./chunk-4PIT6O7A.js";
|
|
246
264
|
import {
|
|
247
265
|
SlackActionError,
|
|
248
266
|
downloadPrivateSlackFile,
|
|
@@ -252,7 +270,7 @@ import {
|
|
|
252
270
|
normalizeSlackConversationId,
|
|
253
271
|
runWithSlackInstallationToken,
|
|
254
272
|
runWithWorkspaceTeamId
|
|
255
|
-
} from "./chunk-
|
|
273
|
+
} from "./chunk-HEFBGCCU.js";
|
|
256
274
|
import {
|
|
257
275
|
contextProvenance,
|
|
258
276
|
createSlackDestination,
|
|
@@ -264,20 +282,20 @@ import {
|
|
|
264
282
|
requireSlackDestination,
|
|
265
283
|
withConversationEventLock,
|
|
266
284
|
withConversationMutationLock
|
|
267
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-WSWM6A3R.js";
|
|
268
286
|
import {
|
|
269
287
|
juniorAgentBindings,
|
|
270
288
|
juniorAgentInvocations,
|
|
271
289
|
juniorConversationEvents,
|
|
272
290
|
juniorConversations
|
|
273
|
-
} from "./chunk-
|
|
291
|
+
} from "./chunk-557HLSNH.js";
|
|
274
292
|
import {
|
|
275
293
|
sleep
|
|
276
294
|
} from "./chunk-EM225ITJ.js";
|
|
277
295
|
import {
|
|
278
296
|
acquireActiveLock,
|
|
279
297
|
getStateAdapter
|
|
280
|
-
} from "./chunk-
|
|
298
|
+
} from "./chunk-J5H65GY2.js";
|
|
281
299
|
import {
|
|
282
300
|
STANDARD_MODEL_PROFILE,
|
|
283
301
|
botConfig,
|
|
@@ -295,19 +313,19 @@ import {
|
|
|
295
313
|
modelIdForProfile,
|
|
296
314
|
setSlackReactionConfig,
|
|
297
315
|
standardModelId
|
|
298
|
-
} from "./chunk-
|
|
316
|
+
} from "./chunk-S3FAOKQU.js";
|
|
299
317
|
import {
|
|
300
318
|
juniorDestinations
|
|
301
319
|
} from "./chunk-VFUK3X5B.js";
|
|
302
|
-
import "./chunk-
|
|
303
|
-
import "./chunk-
|
|
320
|
+
import "./chunk-UXMRN2ZX.js";
|
|
321
|
+
import "./chunk-D3X2PI3D.js";
|
|
304
322
|
import {
|
|
305
323
|
pluginCatalogRuntime
|
|
306
|
-
} from "./chunk-
|
|
307
|
-
import "./chunk-
|
|
324
|
+
} from "./chunk-N2I7W2VS.js";
|
|
325
|
+
import "./chunk-I3OZR3HG.js";
|
|
308
326
|
import {
|
|
309
|
-
|
|
310
|
-
} from "./chunk-
|
|
327
|
+
credentialContextForActor
|
|
328
|
+
} from "./chunk-RUIXF3YQ.js";
|
|
311
329
|
import {
|
|
312
330
|
createActor,
|
|
313
331
|
createSlackActor,
|
|
@@ -336,7 +354,7 @@ import {
|
|
|
336
354
|
withContext,
|
|
337
355
|
withLogContext,
|
|
338
356
|
withSpan
|
|
339
|
-
} from "./chunk-
|
|
357
|
+
} from "./chunk-NPL66ZWL.js";
|
|
340
358
|
import {
|
|
341
359
|
continueTrace
|
|
342
360
|
} from "./chunk-6GWA276C.js";
|
|
@@ -344,10 +362,10 @@ import "./chunk-OOUNJNMR.js";
|
|
|
344
362
|
import "./chunk-H4HBKISO.js";
|
|
345
363
|
import {
|
|
346
364
|
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
|
|
347
|
-
} from "./chunk-
|
|
365
|
+
} from "./chunk-YB363QGA.js";
|
|
348
366
|
import {
|
|
349
367
|
JUNIOR_VERSION
|
|
350
|
-
} from "./chunk-
|
|
368
|
+
} from "./chunk-CPPTBHQN.js";
|
|
351
369
|
import "./chunk-MLKGABMK.js";
|
|
352
370
|
|
|
353
371
|
// src/app.ts
|
|
@@ -409,400 +427,20 @@ async function verifyDispatchCallbackRequest(request) {
|
|
|
409
427
|
}
|
|
410
428
|
}
|
|
411
429
|
|
|
412
|
-
// src/chat/agent-dispatch/store.ts
|
|
413
|
-
import { createHash } from "crypto";
|
|
414
|
-
import {
|
|
415
|
-
destinationSchema,
|
|
416
|
-
destinationVisibilitySchema,
|
|
417
|
-
isSlackDestination,
|
|
418
|
-
replyAttributionSchema,
|
|
419
|
-
sourceSchema
|
|
420
|
-
} from "@sentry/junior-plugin-api";
|
|
421
|
-
import { z as z2 } from "zod";
|
|
422
|
-
var DISPATCH_PREFIX = "junior:agent_dispatch";
|
|
423
|
-
var DISPATCH_LOCK_TTL_MS = 10 * 60 * 1e3;
|
|
424
|
-
var DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS = 1e4;
|
|
425
|
-
var DISPATCH_MAILBOX_APPEND_INDEX_MAX_LENGTH = 1e4;
|
|
426
|
-
var nonEmptyExactStringSchema = z2.string().min(1).refine(
|
|
427
|
-
(value) => value === value.trim() && value.toLowerCase() !== "unknown"
|
|
428
|
-
);
|
|
429
|
-
var pendingDispatchMailboxAppendIndexSchema = z2.array(
|
|
430
|
-
nonEmptyExactStringSchema
|
|
431
|
-
);
|
|
432
|
-
var dispatchStatusSchema = z2.enum([
|
|
433
|
-
"pending",
|
|
434
|
-
"running",
|
|
435
|
-
"awaiting_resume",
|
|
436
|
-
"completed",
|
|
437
|
-
"failed",
|
|
438
|
-
"blocked"
|
|
439
|
-
]);
|
|
440
|
-
var dispatchActorSchema = z2.object({
|
|
441
|
-
platform: z2.literal("system"),
|
|
442
|
-
name: nonEmptyExactStringSchema
|
|
443
|
-
}).strict();
|
|
444
|
-
var dispatchRecordSchema = z2.object({
|
|
445
|
-
actor: dispatchActorSchema,
|
|
446
|
-
createdAtMs: z2.number().finite(),
|
|
447
|
-
credentialSubject: credentialSubjectSchema.optional(),
|
|
448
|
-
destination: destinationSchema,
|
|
449
|
-
destinationVisibility: destinationVisibilitySchema,
|
|
450
|
-
errorMessage: z2.string().optional(),
|
|
451
|
-
id: nonEmptyExactStringSchema,
|
|
452
|
-
idempotencyKey: z2.string().min(1),
|
|
453
|
-
input: z2.string().min(1),
|
|
454
|
-
metadata: z2.record(z2.string(), z2.string()).optional(),
|
|
455
|
-
plugin: nonEmptyExactStringSchema,
|
|
456
|
-
replyAttribution: replyAttributionSchema.optional(),
|
|
457
|
-
resultMessageTs: z2.string().optional(),
|
|
458
|
-
source: sourceSchema,
|
|
459
|
-
status: dispatchStatusSchema,
|
|
460
|
-
updatedAtMs: z2.number().finite()
|
|
461
|
-
}).strict().superRefine((record, ctx) => {
|
|
462
|
-
if (!isSlackDestination(record.destination)) {
|
|
463
|
-
ctx.addIssue({
|
|
464
|
-
code: z2.ZodIssueCode.custom,
|
|
465
|
-
message: "Dispatch destination platform must be slack",
|
|
466
|
-
path: ["destination"]
|
|
467
|
-
});
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
const subject = record.credentialSubject;
|
|
471
|
-
if (!subject) {
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
if (subject.allowedWhen === "private-direct-conversation") {
|
|
475
|
-
if (!record.destination.channelId.startsWith("D")) {
|
|
476
|
-
ctx.addIssue({
|
|
477
|
-
code: z2.ZodIssueCode.custom,
|
|
478
|
-
message: "Dispatch credentialSubject requires a private direct Slack destination",
|
|
479
|
-
path: ["credentialSubject"]
|
|
480
|
-
});
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
if (subject.binding.type !== "slack-direct-conversation" || subject.binding.teamId !== record.destination.teamId || subject.binding.channelId !== record.destination.channelId) {
|
|
484
|
-
ctx.addIssue({
|
|
485
|
-
code: z2.ZodIssueCode.custom,
|
|
486
|
-
message: "Dispatch credentialSubject binding must match destination",
|
|
487
|
-
path: ["credentialSubject", "binding"]
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
if (subject.binding.type !== subject.allowedWhen || subject.binding.plugin !== record.plugin || subject.binding.taskId !== subject.taskId) {
|
|
493
|
-
ctx.addIssue({
|
|
494
|
-
code: z2.ZodIssueCode.custom,
|
|
495
|
-
message: "Dispatch credentialSubject binding must match task",
|
|
496
|
-
path: ["credentialSubject", "binding"]
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
});
|
|
500
|
-
var storedDispatchRecordSchema = dispatchRecordSchema.extend({
|
|
501
|
-
attempt: z2.number().int().nonnegative().optional(),
|
|
502
|
-
lastCallbackAtMs: z2.number().finite().optional(),
|
|
503
|
-
leaseExpiresAtMs: z2.number().finite().optional(),
|
|
504
|
-
maxAttempts: z2.number().int().positive().optional(),
|
|
505
|
-
version: z2.number().int().positive().optional()
|
|
506
|
-
});
|
|
507
|
-
function getDispatchStorageKey(id) {
|
|
508
|
-
return `${DISPATCH_PREFIX}:record:${id}`;
|
|
509
|
-
}
|
|
510
|
-
function dispatchLockKey(id) {
|
|
511
|
-
return `${DISPATCH_PREFIX}:lock:${id}`;
|
|
512
|
-
}
|
|
513
|
-
function pendingDispatchMailboxAppendIndexKey() {
|
|
514
|
-
return `${DISPATCH_PREFIX}:incomplete`;
|
|
515
|
-
}
|
|
516
|
-
function pendingDispatchMailboxAppendIndexLockKey() {
|
|
517
|
-
return `${DISPATCH_PREFIX}:incomplete:lock`;
|
|
518
|
-
}
|
|
519
|
-
function normalizeMetadata(metadata) {
|
|
520
|
-
if (!metadata) {
|
|
521
|
-
return void 0;
|
|
522
|
-
}
|
|
523
|
-
const entries = Object.entries(metadata).filter(
|
|
524
|
-
(entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
|
|
525
|
-
);
|
|
526
|
-
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
527
|
-
}
|
|
528
|
-
function buildDispatchId(plugin, idempotencyKey) {
|
|
529
|
-
const digest = createHash("sha256").update(plugin).update("\0").update(idempotencyKey).digest("hex").slice(0, 32);
|
|
530
|
-
return `dispatch_${digest}`;
|
|
531
|
-
}
|
|
532
|
-
function parseDispatchRecord(value) {
|
|
533
|
-
const parsed = parseStoredDispatchRecord(value);
|
|
534
|
-
return parsed?.record;
|
|
535
|
-
}
|
|
536
|
-
function parseStoredDispatchRecord(value) {
|
|
537
|
-
const parsed = storedDispatchRecordSchema.safeParse(value);
|
|
538
|
-
if (!parsed.success) {
|
|
539
|
-
return void 0;
|
|
540
|
-
}
|
|
541
|
-
const {
|
|
542
|
-
attempt: _attempt,
|
|
543
|
-
lastCallbackAtMs: _lastCallbackAtMs,
|
|
544
|
-
leaseExpiresAtMs: _leaseExpiresAtMs,
|
|
545
|
-
maxAttempts: _maxAttempts,
|
|
546
|
-
version: _version,
|
|
547
|
-
...record
|
|
548
|
-
} = parsed.data;
|
|
549
|
-
return {
|
|
550
|
-
...typeof parsed.data.leaseExpiresAtMs === "number" ? { legacyLeaseExpiresAtMs: parsed.data.leaseExpiresAtMs } : {},
|
|
551
|
-
record
|
|
552
|
-
};
|
|
553
|
-
}
|
|
554
|
-
function getDispatchConversationId(dispatch2) {
|
|
555
|
-
return `agent-dispatch:${dispatch2.id}`;
|
|
556
|
-
}
|
|
557
|
-
function getDispatchInputMessageId(dispatchId) {
|
|
558
|
-
return `agent-dispatch:${dispatchId}`;
|
|
559
|
-
}
|
|
560
|
-
function getLegacyDispatchInputMessageId(dispatchId) {
|
|
561
|
-
return `dispatch:${dispatchId}:user`;
|
|
562
|
-
}
|
|
563
|
-
function getDispatchInputMessageIds(dispatchId) {
|
|
564
|
-
return [
|
|
565
|
-
getDispatchInputMessageId(dispatchId),
|
|
566
|
-
getLegacyDispatchInputMessageId(dispatchId)
|
|
567
|
-
];
|
|
568
|
-
}
|
|
569
|
-
function getDispatchTurnId(dispatchId) {
|
|
570
|
-
return `dispatch:${dispatchId}`;
|
|
571
|
-
}
|
|
572
|
-
function toDispatchProjection(record) {
|
|
573
|
-
return {
|
|
574
|
-
id: record.id,
|
|
575
|
-
status: record.status,
|
|
576
|
-
...record.resultMessageTs ? { resultMessageTs: record.resultMessageTs } : {},
|
|
577
|
-
...record.errorMessage ? { errorMessage: record.errorMessage } : {}
|
|
578
|
-
};
|
|
579
|
-
}
|
|
580
|
-
function isTerminalDispatchStatus(status) {
|
|
581
|
-
return status === "completed" || status === "failed" || status === "blocked";
|
|
582
|
-
}
|
|
583
|
-
async function withDispatchLock(dispatchId, task) {
|
|
584
|
-
const state = getStateAdapter();
|
|
585
|
-
await state.connect();
|
|
586
|
-
const lock = await state.acquireLock(
|
|
587
|
-
dispatchLockKey(dispatchId),
|
|
588
|
-
DISPATCH_LOCK_TTL_MS
|
|
589
|
-
);
|
|
590
|
-
if (!lock) {
|
|
591
|
-
throw new Error(`Could not acquire dispatch lock for ${dispatchId}`);
|
|
592
|
-
}
|
|
593
|
-
try {
|
|
594
|
-
return await task(state);
|
|
595
|
-
} finally {
|
|
596
|
-
await state.releaseLock(lock);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
async function putRecord(state, record) {
|
|
600
|
-
const parsed = dispatchRecordSchema.safeParse(record);
|
|
601
|
-
if (!parsed.success) {
|
|
602
|
-
throw new Error(
|
|
603
|
-
`Dispatch record is invalid: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"} ${issue.message}`).join("; ")}`
|
|
604
|
-
);
|
|
605
|
-
}
|
|
606
|
-
const next = parsed.data;
|
|
607
|
-
await state.set(
|
|
608
|
-
getDispatchStorageKey(next.id),
|
|
609
|
-
next,
|
|
610
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
611
|
-
);
|
|
612
|
-
}
|
|
613
|
-
async function updatePendingDispatchMailboxAppendIndex(state, update) {
|
|
614
|
-
const lock = await state.acquireLock(
|
|
615
|
-
pendingDispatchMailboxAppendIndexLockKey(),
|
|
616
|
-
DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS
|
|
617
|
-
);
|
|
618
|
-
if (!lock) {
|
|
619
|
-
throw new Error("Could not acquire dispatch mailbox append index lock");
|
|
620
|
-
}
|
|
621
|
-
try {
|
|
622
|
-
const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
|
|
623
|
-
const ids = stored === void 0 || stored === null ? [] : pendingDispatchMailboxAppendIndexSchema.parse(stored);
|
|
624
|
-
const next = [...new Set(update([...new Set(ids)]))].slice(
|
|
625
|
-
-DISPATCH_MAILBOX_APPEND_INDEX_MAX_LENGTH
|
|
626
|
-
);
|
|
627
|
-
if (next.length === ids.length && next.every((id, index) => id === ids[index])) {
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
await state.set(
|
|
631
|
-
pendingDispatchMailboxAppendIndexKey(),
|
|
632
|
-
next,
|
|
633
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
634
|
-
);
|
|
635
|
-
} finally {
|
|
636
|
-
await state.releaseLock(lock);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
async function getDispatchRecord(id) {
|
|
640
|
-
const state = getStateAdapter();
|
|
641
|
-
await state.connect();
|
|
642
|
-
return parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
|
|
643
|
-
}
|
|
644
|
-
async function createOrGetDispatch(args) {
|
|
645
|
-
const id = buildDispatchId(args.plugin, args.options.idempotencyKey);
|
|
646
|
-
return await withDispatchLock(id, async (state) => {
|
|
647
|
-
const existing = parseDispatchRecord(
|
|
648
|
-
await state.get(getDispatchStorageKey(id))
|
|
649
|
-
);
|
|
650
|
-
if (existing) {
|
|
651
|
-
return { record: existing, status: "already_exists" };
|
|
652
|
-
}
|
|
653
|
-
const metadata = normalizeMetadata(args.options.metadata);
|
|
654
|
-
const record = {
|
|
655
|
-
actor: { platform: "system", name: args.plugin },
|
|
656
|
-
createdAtMs: args.nowMs,
|
|
657
|
-
...args.options.credentialSubject ? { credentialSubject: args.options.credentialSubject } : {},
|
|
658
|
-
destination: args.options.destination,
|
|
659
|
-
destinationVisibility: args.options.destinationVisibility,
|
|
660
|
-
id,
|
|
661
|
-
idempotencyKey: args.options.idempotencyKey,
|
|
662
|
-
input: args.options.input,
|
|
663
|
-
...metadata ? { metadata } : {},
|
|
664
|
-
plugin: args.plugin,
|
|
665
|
-
...args.options.replyAttribution ? { replyAttribution: args.options.replyAttribution } : {},
|
|
666
|
-
status: "pending",
|
|
667
|
-
source: args.options.source,
|
|
668
|
-
updatedAtMs: args.nowMs
|
|
669
|
-
};
|
|
670
|
-
await updatePendingDispatchMailboxAppendIndex(
|
|
671
|
-
state,
|
|
672
|
-
(ids) => ids.includes(id) ? ids : [...ids, id]
|
|
673
|
-
);
|
|
674
|
-
await putRecord(state, record);
|
|
675
|
-
return { record, status: "created" };
|
|
676
|
-
});
|
|
677
|
-
}
|
|
678
|
-
async function transitionDispatch(id, transition) {
|
|
679
|
-
return await withDispatchLock(id, async (state) => {
|
|
680
|
-
const current = parseDispatchRecord(
|
|
681
|
-
await state.get(getDispatchStorageKey(id))
|
|
682
|
-
);
|
|
683
|
-
if (!current) {
|
|
684
|
-
return void 0;
|
|
685
|
-
}
|
|
686
|
-
const transitioned = transition(current);
|
|
687
|
-
if (transitioned === current) {
|
|
688
|
-
return current;
|
|
689
|
-
}
|
|
690
|
-
const next = {
|
|
691
|
-
...transitioned,
|
|
692
|
-
updatedAtMs: Date.now()
|
|
693
|
-
};
|
|
694
|
-
await putRecord(state, next);
|
|
695
|
-
return next;
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
async function markDispatchRunning(id) {
|
|
699
|
-
return await transitionDispatch(
|
|
700
|
-
id,
|
|
701
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : { ...record, status: "running", errorMessage: void 0 }
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
async function markDispatchAwaitingResume(id) {
|
|
705
|
-
return await transitionDispatch(
|
|
706
|
-
id,
|
|
707
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
708
|
-
...record,
|
|
709
|
-
status: "awaiting_resume"
|
|
710
|
-
}
|
|
711
|
-
);
|
|
712
|
-
}
|
|
713
|
-
async function markDispatchBlocked(id, errorMessage, resultMessageTs) {
|
|
714
|
-
return await transitionDispatch(
|
|
715
|
-
id,
|
|
716
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
717
|
-
...record,
|
|
718
|
-
errorMessage,
|
|
719
|
-
...resultMessageTs ? { resultMessageTs } : {},
|
|
720
|
-
status: "blocked"
|
|
721
|
-
}
|
|
722
|
-
);
|
|
723
|
-
}
|
|
724
|
-
async function markDispatchCompleted(id, resultMessageTs) {
|
|
725
|
-
const previous = await getDispatchRecord(id);
|
|
726
|
-
const next = await transitionDispatch(
|
|
727
|
-
id,
|
|
728
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
729
|
-
...record,
|
|
730
|
-
errorMessage: void 0,
|
|
731
|
-
...resultMessageTs ? { resultMessageTs } : {},
|
|
732
|
-
status: "completed"
|
|
733
|
-
}
|
|
734
|
-
);
|
|
735
|
-
if (next?.status === "completed" && previous?.status !== "completed" && next.plugin === "junior") {
|
|
736
|
-
const eventTaskId = next.metadata?.eventTaskId;
|
|
737
|
-
if (eventTaskId) {
|
|
738
|
-
await recordTaskExecution("event", eventTaskId, {
|
|
739
|
-
conversationId: getDispatchConversationId(next),
|
|
740
|
-
executionId: next.id,
|
|
741
|
-
nowMs: next.updatedAtMs
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
return next;
|
|
746
|
-
}
|
|
747
|
-
async function markDispatchFailed(id, errorMessage, resultMessageTs) {
|
|
748
|
-
return await transitionDispatch(
|
|
749
|
-
id,
|
|
750
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
751
|
-
...record,
|
|
752
|
-
errorMessage,
|
|
753
|
-
...resultMessageTs ? { resultMessageTs } : {},
|
|
754
|
-
status: "failed"
|
|
755
|
-
}
|
|
756
|
-
);
|
|
757
|
-
}
|
|
758
|
-
async function confirmDispatchMailboxAppend(id) {
|
|
759
|
-
const state = getStateAdapter();
|
|
760
|
-
await state.connect();
|
|
761
|
-
await updatePendingDispatchMailboxAppendIndex(
|
|
762
|
-
state,
|
|
763
|
-
(ids) => ids.filter((candidate) => candidate !== id)
|
|
764
|
-
);
|
|
765
|
-
}
|
|
766
|
-
async function listPendingDispatchMailboxAppends() {
|
|
767
|
-
const state = getStateAdapter();
|
|
768
|
-
await state.connect();
|
|
769
|
-
const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
|
|
770
|
-
return stored === void 0 || stored === null ? [] : [...new Set(pendingDispatchMailboxAppendIndexSchema.parse(stored))];
|
|
771
|
-
}
|
|
772
|
-
async function claimDispatchMailboxAppend(id, nowMs) {
|
|
773
|
-
return await withDispatchLock(id, async (state) => {
|
|
774
|
-
const stored = parseStoredDispatchRecord(
|
|
775
|
-
await state.get(getDispatchStorageKey(id))
|
|
776
|
-
);
|
|
777
|
-
if (!stored || stored.legacyLeaseExpiresAtMs && stored.legacyLeaseExpiresAtMs > nowMs) {
|
|
778
|
-
return void 0;
|
|
779
|
-
}
|
|
780
|
-
await putRecord(state, stored.record);
|
|
781
|
-
return stored.record;
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
async function getPluginDispatchProjection(args) {
|
|
785
|
-
const record = await getDispatchRecord(args.id);
|
|
786
|
-
if (!record || record.plugin !== args.plugin) {
|
|
787
|
-
return void 0;
|
|
788
|
-
}
|
|
789
|
-
return toDispatchProjection(record);
|
|
790
|
-
}
|
|
791
|
-
|
|
792
430
|
// src/chat/agent-dispatch/work.ts
|
|
793
|
-
import { z as
|
|
794
|
-
var agentDispatchMailboxMetadataSchema =
|
|
795
|
-
dispatchId:
|
|
796
|
-
kind:
|
|
431
|
+
import { z as z2 } from "zod";
|
|
432
|
+
var agentDispatchMailboxMetadataSchema = z2.object({
|
|
433
|
+
dispatchId: z2.string().min(1),
|
|
434
|
+
kind: z2.literal("agent_dispatch")
|
|
797
435
|
}).strict();
|
|
798
436
|
var AGENT_DISPATCH_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
799
437
|
function buildDispatchRoutingContext(dispatch2) {
|
|
800
438
|
return {
|
|
801
439
|
actor: dispatch2.actor,
|
|
802
|
-
credentialContext:
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
440
|
+
credentialContext: credentialContextForActor(
|
|
441
|
+
dispatch2.actor,
|
|
442
|
+
dispatch2.credentialSubject
|
|
443
|
+
),
|
|
806
444
|
destinationVisibility: dispatch2.destinationVisibility,
|
|
807
445
|
dispatch: {
|
|
808
446
|
actor: dispatch2.actor,
|
|
@@ -1301,7 +939,7 @@ import {
|
|
|
1301
939
|
// src/chat/agent-dispatch/validation.ts
|
|
1302
940
|
import {
|
|
1303
941
|
dispatchOptionsSchema,
|
|
1304
|
-
isSlackDestination
|
|
942
|
+
isSlackDestination
|
|
1305
943
|
} from "@sentry/junior-plugin-api";
|
|
1306
944
|
function hasIssueAtPath(issues, path) {
|
|
1307
945
|
return issues.some(
|
|
@@ -1398,7 +1036,7 @@ function validateDispatchOptions(options) {
|
|
|
1398
1036
|
}
|
|
1399
1037
|
const candidate = parsed.data;
|
|
1400
1038
|
const { credentialSubject, destination } = candidate;
|
|
1401
|
-
if (!
|
|
1039
|
+
if (!isSlackDestination(destination)) {
|
|
1402
1040
|
throw new Error("Dispatch destination platform must be slack");
|
|
1403
1041
|
}
|
|
1404
1042
|
if (credentialSubject !== void 0) {
|
|
@@ -1623,6 +1261,37 @@ function shouldSkipRun(task, run) {
|
|
|
1623
1261
|
}
|
|
1624
1262
|
return void 0;
|
|
1625
1263
|
}
|
|
1264
|
+
async function recordScheduledExecution(args) {
|
|
1265
|
+
const dispatchId = args.run.dispatchId;
|
|
1266
|
+
await recordTaskExecution("scheduled", args.run.taskId, {
|
|
1267
|
+
...dispatchId ? { conversationId: getDispatchConversationId({ id: dispatchId }) } : {},
|
|
1268
|
+
executionId: args.run.id,
|
|
1269
|
+
nowMs: args.nowMs,
|
|
1270
|
+
status: args.status
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
async function logRunOutcome(args) {
|
|
1274
|
+
const task = args.task ?? await args.store.getTask(args.run.taskId) ?? void 0;
|
|
1275
|
+
if (!task) {
|
|
1276
|
+
logInfo(args.eventName, {
|
|
1277
|
+
"app.task.id": args.run.taskId,
|
|
1278
|
+
"app.task.type": "scheduled",
|
|
1279
|
+
"app.task.run.id": args.run.id,
|
|
1280
|
+
"app.task.run.status": args.run.status,
|
|
1281
|
+
"app.task.run.scheduled_for": new Date(
|
|
1282
|
+
args.run.scheduledForMs
|
|
1283
|
+
).toISOString(),
|
|
1284
|
+
...args.run.dispatchId ? { "app.dispatch.id": args.run.dispatchId } : {},
|
|
1285
|
+
...args.run.resultMessageTs ? { "app.task.result_message_ts": args.run.resultMessageTs } : {},
|
|
1286
|
+
...args.extras
|
|
1287
|
+
});
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
logInfo(
|
|
1291
|
+
args.eventName,
|
|
1292
|
+
scheduledTaskRunAttributes(task, args.run, args.extras)
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1626
1295
|
async function applyDispatchResult(args) {
|
|
1627
1296
|
if (args.dispatch.status === "completed") {
|
|
1628
1297
|
const completed = await args.store.markRunCompleted({
|
|
@@ -1637,14 +1306,16 @@ async function applyDispatchResult(args) {
|
|
|
1637
1306
|
run: args.run,
|
|
1638
1307
|
status: "completed"
|
|
1639
1308
|
});
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1309
|
+
await recordScheduledExecution({
|
|
1310
|
+
nowMs: args.nowMs,
|
|
1311
|
+
run: args.run,
|
|
1312
|
+
status: "completed"
|
|
1313
|
+
});
|
|
1314
|
+
await logRunOutcome({
|
|
1315
|
+
eventName: "scheduled_task.run.completed",
|
|
1316
|
+
run: completed,
|
|
1317
|
+
store: args.store
|
|
1318
|
+
});
|
|
1648
1319
|
return true;
|
|
1649
1320
|
}
|
|
1650
1321
|
if (args.dispatch.status === "blocked") {
|
|
@@ -1661,6 +1332,17 @@ async function applyDispatchResult(args) {
|
|
|
1661
1332
|
run: args.run,
|
|
1662
1333
|
status: "blocked"
|
|
1663
1334
|
});
|
|
1335
|
+
await recordScheduledExecution({
|
|
1336
|
+
nowMs: args.nowMs,
|
|
1337
|
+
run: args.run,
|
|
1338
|
+
status: "blocked"
|
|
1339
|
+
});
|
|
1340
|
+
await logRunOutcome({
|
|
1341
|
+
eventName: "scheduled_task.run.blocked",
|
|
1342
|
+
run: blocked,
|
|
1343
|
+
store: args.store,
|
|
1344
|
+
extras: blocked.errorMessage ? { "app.task.run.error": blocked.errorMessage } : void 0
|
|
1345
|
+
});
|
|
1664
1346
|
return true;
|
|
1665
1347
|
}
|
|
1666
1348
|
if (args.dispatch.status === "failed") {
|
|
@@ -1677,6 +1359,17 @@ async function applyDispatchResult(args) {
|
|
|
1677
1359
|
run: args.run,
|
|
1678
1360
|
status: "failed"
|
|
1679
1361
|
});
|
|
1362
|
+
await recordScheduledExecution({
|
|
1363
|
+
nowMs: args.nowMs,
|
|
1364
|
+
run: args.run,
|
|
1365
|
+
status: "failed"
|
|
1366
|
+
});
|
|
1367
|
+
await logRunOutcome({
|
|
1368
|
+
eventName: "scheduled_task.run.failed",
|
|
1369
|
+
run: failed,
|
|
1370
|
+
store: args.store,
|
|
1371
|
+
extras: failed.errorMessage ? { "app.task.run.error": failed.errorMessage } : void 0
|
|
1372
|
+
});
|
|
1680
1373
|
return true;
|
|
1681
1374
|
}
|
|
1682
1375
|
return false;
|
|
@@ -1699,6 +1392,17 @@ async function finishClaimedRun(args) {
|
|
|
1699
1392
|
run: args.run,
|
|
1700
1393
|
status: args.status
|
|
1701
1394
|
});
|
|
1395
|
+
await recordScheduledExecution({
|
|
1396
|
+
nowMs: args.nowMs,
|
|
1397
|
+
run: args.run,
|
|
1398
|
+
status: args.status
|
|
1399
|
+
});
|
|
1400
|
+
await logRunOutcome({
|
|
1401
|
+
eventName: args.status === "blocked" ? "scheduled_task.run.blocked" : "scheduled_task.run.failed",
|
|
1402
|
+
run: finished,
|
|
1403
|
+
store: args.store,
|
|
1404
|
+
extras: { "app.task.run.error": args.errorMessage }
|
|
1405
|
+
});
|
|
1702
1406
|
}
|
|
1703
1407
|
async function runScheduledTaskHeartbeat(args) {
|
|
1704
1408
|
const store = createSchedulerSqlStore(getDb());
|
|
@@ -1717,7 +1421,12 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1717
1421
|
});
|
|
1718
1422
|
continue;
|
|
1719
1423
|
}
|
|
1720
|
-
if (await applyDispatchResult({
|
|
1424
|
+
if (await applyDispatchResult({
|
|
1425
|
+
dispatch: dispatch2,
|
|
1426
|
+
nowMs: args.nowMs,
|
|
1427
|
+
run,
|
|
1428
|
+
store
|
|
1429
|
+
})) {
|
|
1721
1430
|
processedCount += 1;
|
|
1722
1431
|
}
|
|
1723
1432
|
}
|
|
@@ -1726,20 +1435,39 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1726
1435
|
if (!run) break;
|
|
1727
1436
|
const task = await store.getTask(run.taskId);
|
|
1728
1437
|
if (!task) {
|
|
1729
|
-
await store.markRunFailed({
|
|
1438
|
+
const failed = await store.markRunFailed({
|
|
1730
1439
|
completedAtMs: args.nowMs,
|
|
1731
1440
|
errorMessage: `Scheduled task ${run.taskId} was not found`,
|
|
1732
1441
|
runId: run.id
|
|
1733
1442
|
});
|
|
1443
|
+
if (failed) {
|
|
1444
|
+
await logRunOutcome({
|
|
1445
|
+
eventName: "scheduled_task.run.failed",
|
|
1446
|
+
run: failed,
|
|
1447
|
+
store,
|
|
1448
|
+
extras: {
|
|
1449
|
+
"app.task.run.error": `Scheduled task ${run.taskId} was not found`
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1734
1453
|
continue;
|
|
1735
1454
|
}
|
|
1455
|
+
logInfo(
|
|
1456
|
+
"scheduled_task.run.claimed",
|
|
1457
|
+
scheduledTaskRunAttributes(task, run)
|
|
1458
|
+
);
|
|
1736
1459
|
const skippedReason = shouldSkipRun(task, run);
|
|
1737
1460
|
if (skippedReason) {
|
|
1738
|
-
await store.markRunSkipped({
|
|
1461
|
+
const skipped = await store.markRunSkipped({
|
|
1739
1462
|
completedAtMs: args.nowMs,
|
|
1740
1463
|
errorMessage: skippedReason,
|
|
1741
1464
|
runId: run.id
|
|
1742
1465
|
});
|
|
1466
|
+
if (skipped) {
|
|
1467
|
+
logScheduledTaskRunSkipped(task, skipped, {
|
|
1468
|
+
"app.task.run.error": skippedReason
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1743
1471
|
continue;
|
|
1744
1472
|
}
|
|
1745
1473
|
let metadata;
|
|
@@ -1788,12 +1516,22 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1788
1516
|
});
|
|
1789
1517
|
continue;
|
|
1790
1518
|
}
|
|
1791
|
-
await store.markRunDispatched({
|
|
1519
|
+
const dispatched = await store.markRunDispatched({
|
|
1792
1520
|
claimedAtMs: run.claimedAtMs,
|
|
1793
1521
|
dispatchId: dispatch2.id,
|
|
1794
1522
|
nowMs: args.nowMs,
|
|
1795
1523
|
runId: run.id
|
|
1796
1524
|
});
|
|
1525
|
+
logInfo(
|
|
1526
|
+
"scheduled_task.run.dispatched",
|
|
1527
|
+
scheduledTaskRunAttributes(
|
|
1528
|
+
task,
|
|
1529
|
+
dispatched ?? { ...run, dispatchId: dispatch2.id },
|
|
1530
|
+
{
|
|
1531
|
+
"app.dispatch.id": dispatch2.id
|
|
1532
|
+
}
|
|
1533
|
+
)
|
|
1534
|
+
);
|
|
1797
1535
|
dispatchCount += 1;
|
|
1798
1536
|
}
|
|
1799
1537
|
return dispatchCount;
|
|
@@ -2658,7 +2396,7 @@ import {
|
|
|
2658
2396
|
Message,
|
|
2659
2397
|
ThreadImpl
|
|
2660
2398
|
} from "chat";
|
|
2661
|
-
import { z as
|
|
2399
|
+
import { z as z4 } from "zod";
|
|
2662
2400
|
|
|
2663
2401
|
// src/chat/ingress/message-router.ts
|
|
2664
2402
|
function normalizeIncomingSlackThreadId(threadId, message) {
|
|
@@ -2829,14 +2567,14 @@ async function ensureSlackMessageActorIdentity(message, teamId, lookupSlackUser2
|
|
|
2829
2567
|
}
|
|
2830
2568
|
|
|
2831
2569
|
// src/chat/slack/user.ts
|
|
2832
|
-
import { z as
|
|
2833
|
-
var slackUserInfoSchema =
|
|
2834
|
-
ok:
|
|
2835
|
-
user:
|
|
2836
|
-
name:
|
|
2837
|
-
profile:
|
|
2838
|
-
email:
|
|
2839
|
-
real_name:
|
|
2570
|
+
import { z as z3 } from "zod";
|
|
2571
|
+
var slackUserInfoSchema = z3.object({
|
|
2572
|
+
ok: z3.literal(true),
|
|
2573
|
+
user: z3.object({
|
|
2574
|
+
name: z3.string().nullish(),
|
|
2575
|
+
profile: z3.object({
|
|
2576
|
+
email: z3.string().nullish(),
|
|
2577
|
+
real_name: z3.string().nullish()
|
|
2840
2578
|
}).optional()
|
|
2841
2579
|
})
|
|
2842
2580
|
});
|
|
@@ -2913,6 +2651,20 @@ async function lookupSlackUser(teamId, userId) {
|
|
|
2913
2651
|
}
|
|
2914
2652
|
}
|
|
2915
2653
|
|
|
2654
|
+
// src/chat/resource-events/actor.ts
|
|
2655
|
+
var RESOURCE_EVENT_SLACK_AUTHOR_ID = "UJRNEVENT";
|
|
2656
|
+
var RESOURCE_EVENT_SYSTEM_ACTOR = {
|
|
2657
|
+
platform: "system",
|
|
2658
|
+
name: "resource-event"
|
|
2659
|
+
};
|
|
2660
|
+
function isResourceEventConversationMessage(message) {
|
|
2661
|
+
return Boolean(message.meta?.eventType) || message.author?.userId === RESOURCE_EVENT_SLACK_AUTHOR_ID;
|
|
2662
|
+
}
|
|
2663
|
+
function isResourceEventSlackMessage(message) {
|
|
2664
|
+
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
2665
|
+
return raw?.event_type === "resource_event";
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2916
2668
|
// src/chat/slack/message-control.ts
|
|
2917
2669
|
var LEADING_MENTION_BEFORE_STEERING_RE = /^(\s*(?:<@[^>]+>|@[A-Za-z0-9._-]+\b)[\s,:-]*)!!\s*/;
|
|
2918
2670
|
function stripLeadingSteeringOverride(text) {
|
|
@@ -2920,17 +2672,17 @@ function stripLeadingSteeringOverride(text) {
|
|
|
2920
2672
|
}
|
|
2921
2673
|
|
|
2922
2674
|
// src/chat/task-execution/slack-work.ts
|
|
2923
|
-
var slackConversationRouteSchema =
|
|
2675
|
+
var slackConversationRouteSchema = z4.enum(["mention", "subscribed"]);
|
|
2924
2676
|
function hasSteeringOverride(text) {
|
|
2925
2677
|
return stripLeadingSteeringOverride(text) !== text;
|
|
2926
2678
|
}
|
|
2927
|
-
var serializedDateSchema =
|
|
2928
|
-
var mdastPointSchema =
|
|
2929
|
-
column:
|
|
2930
|
-
line:
|
|
2931
|
-
offset:
|
|
2679
|
+
var serializedDateSchema = z4.iso.datetime();
|
|
2680
|
+
var mdastPointSchema = z4.object({
|
|
2681
|
+
column: z4.number().int().positive(),
|
|
2682
|
+
line: z4.number().int().positive(),
|
|
2683
|
+
offset: z4.number().int().nonnegative().optional()
|
|
2932
2684
|
}).strict();
|
|
2933
|
-
var mdastPositionSchema =
|
|
2685
|
+
var mdastPositionSchema = z4.object({
|
|
2934
2686
|
end: mdastPointSchema,
|
|
2935
2687
|
start: mdastPointSchema
|
|
2936
2688
|
}).strict();
|
|
@@ -3042,7 +2794,7 @@ function isFormattedContentNode(value) {
|
|
|
3042
2794
|
return false;
|
|
3043
2795
|
}
|
|
3044
2796
|
}
|
|
3045
|
-
var formattedContentSchema =
|
|
2797
|
+
var formattedContentSchema = z4.custom(
|
|
3046
2798
|
(value) => {
|
|
3047
2799
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3048
2800
|
return false;
|
|
@@ -3052,79 +2804,79 @@ var formattedContentSchema = z5.custom(
|
|
|
3052
2804
|
},
|
|
3053
2805
|
"must be a valid formatted-content root"
|
|
3054
2806
|
);
|
|
3055
|
-
var serializedMessageSchema =
|
|
3056
|
-
_type:
|
|
3057
|
-
attachments:
|
|
3058
|
-
|
|
3059
|
-
type:
|
|
3060
|
-
url:
|
|
3061
|
-
name:
|
|
3062
|
-
mimeType:
|
|
3063
|
-
size:
|
|
3064
|
-
width:
|
|
3065
|
-
height:
|
|
3066
|
-
fetchMetadata:
|
|
2807
|
+
var serializedMessageSchema = z4.object({
|
|
2808
|
+
_type: z4.literal("chat:Message"),
|
|
2809
|
+
attachments: z4.array(
|
|
2810
|
+
z4.object({
|
|
2811
|
+
type: z4.enum(["image", "file", "video", "audio"]),
|
|
2812
|
+
url: z4.string().optional(),
|
|
2813
|
+
name: z4.string().optional(),
|
|
2814
|
+
mimeType: z4.string().optional(),
|
|
2815
|
+
size: z4.number().finite().optional(),
|
|
2816
|
+
width: z4.number().finite().optional(),
|
|
2817
|
+
height: z4.number().finite().optional(),
|
|
2818
|
+
fetchMetadata: z4.record(z4.string(), z4.string()).optional()
|
|
3067
2819
|
}).strict()
|
|
3068
2820
|
),
|
|
3069
|
-
author:
|
|
3070
|
-
userId:
|
|
3071
|
-
userName:
|
|
3072
|
-
fullName:
|
|
3073
|
-
isBot:
|
|
3074
|
-
isMe:
|
|
2821
|
+
author: z4.object({
|
|
2822
|
+
userId: z4.string(),
|
|
2823
|
+
userName: z4.string(),
|
|
2824
|
+
fullName: z4.string(),
|
|
2825
|
+
isBot: z4.union([z4.boolean(), z4.literal("unknown")]),
|
|
2826
|
+
isMe: z4.boolean()
|
|
3075
2827
|
}).strict(),
|
|
3076
2828
|
formatted: formattedContentSchema,
|
|
3077
|
-
id:
|
|
3078
|
-
isMention:
|
|
3079
|
-
links:
|
|
3080
|
-
|
|
3081
|
-
url:
|
|
3082
|
-
title:
|
|
3083
|
-
description:
|
|
3084
|
-
imageUrl:
|
|
3085
|
-
siteName:
|
|
2829
|
+
id: z4.string().min(1),
|
|
2830
|
+
isMention: z4.boolean().optional(),
|
|
2831
|
+
links: z4.array(
|
|
2832
|
+
z4.object({
|
|
2833
|
+
url: z4.string(),
|
|
2834
|
+
title: z4.string().optional(),
|
|
2835
|
+
description: z4.string().optional(),
|
|
2836
|
+
imageUrl: z4.string().optional(),
|
|
2837
|
+
siteName: z4.string().optional()
|
|
3086
2838
|
}).strict()
|
|
3087
2839
|
).optional(),
|
|
3088
|
-
metadata:
|
|
2840
|
+
metadata: z4.object({
|
|
3089
2841
|
dateSent: serializedDateSchema,
|
|
3090
|
-
edited:
|
|
2842
|
+
edited: z4.boolean(),
|
|
3091
2843
|
editedAt: serializedDateSchema.optional()
|
|
3092
2844
|
}).strict(),
|
|
3093
|
-
raw:
|
|
3094
|
-
text:
|
|
3095
|
-
threadId:
|
|
2845
|
+
raw: z4.unknown(),
|
|
2846
|
+
text: z4.string(),
|
|
2847
|
+
threadId: z4.string().min(1)
|
|
3096
2848
|
}).strict();
|
|
3097
|
-
var serializedThreadSchema =
|
|
3098
|
-
_type:
|
|
3099
|
-
adapterName:
|
|
3100
|
-
channelId:
|
|
3101
|
-
channelVisibility:
|
|
2849
|
+
var serializedThreadSchema = z4.object({
|
|
2850
|
+
_type: z4.literal("chat:Thread"),
|
|
2851
|
+
adapterName: z4.literal("slack"),
|
|
2852
|
+
channelId: z4.string().min(1),
|
|
2853
|
+
channelVisibility: z4.enum(["private", "workspace", "external", "unknown"]).optional(),
|
|
3102
2854
|
currentMessage: serializedMessageSchema.optional(),
|
|
3103
|
-
id:
|
|
3104
|
-
isDM:
|
|
2855
|
+
id: z4.string().min(1),
|
|
2856
|
+
isDM: z4.boolean()
|
|
3105
2857
|
}).strict();
|
|
3106
|
-
var slackInstallationSchema =
|
|
3107
|
-
enterpriseId:
|
|
3108
|
-
isEnterpriseInstall:
|
|
3109
|
-
teamId:
|
|
2858
|
+
var slackInstallationSchema = z4.object({
|
|
2859
|
+
enterpriseId: z4.string().optional(),
|
|
2860
|
+
isEnterpriseInstall: z4.boolean().optional(),
|
|
2861
|
+
teamId: z4.string().optional()
|
|
3110
2862
|
}).strict();
|
|
3111
|
-
var slackConversationMessageMetadataBaseSchema =
|
|
2863
|
+
var slackConversationMessageMetadataBaseSchema = z4.object({
|
|
3112
2864
|
installation: slackInstallationSchema.optional(),
|
|
3113
2865
|
message: serializedMessageSchema,
|
|
3114
|
-
platform:
|
|
2866
|
+
platform: z4.literal("slack"),
|
|
3115
2867
|
route: slackConversationRouteSchema,
|
|
3116
2868
|
thread: serializedThreadSchema
|
|
3117
2869
|
});
|
|
3118
|
-
var slackConversationMessageMetadataSchema =
|
|
2870
|
+
var slackConversationMessageMetadataSchema = z4.union([
|
|
3119
2871
|
slackConversationMessageMetadataBaseSchema.strict(),
|
|
3120
2872
|
slackConversationMessageMetadataBaseSchema.extend({
|
|
3121
|
-
kind:
|
|
3122
|
-
resourceEvent:
|
|
3123
|
-
eventKey:
|
|
3124
|
-
eventType:
|
|
3125
|
-
namespace:
|
|
3126
|
-
identifier:
|
|
3127
|
-
subscriptionId:
|
|
2873
|
+
kind: z4.literal("resource_event"),
|
|
2874
|
+
resourceEvent: z4.object({
|
|
2875
|
+
eventKey: z4.string(),
|
|
2876
|
+
eventType: z4.string(),
|
|
2877
|
+
namespace: z4.string(),
|
|
2878
|
+
identifier: z4.string(),
|
|
2879
|
+
subscriptionId: z4.string()
|
|
3128
2880
|
}).strict()
|
|
3129
2881
|
}).strict()
|
|
3130
2882
|
]);
|
|
@@ -3157,7 +2909,7 @@ function slackSerializedResourceEventMessage(input) {
|
|
|
3157
2909
|
_type: "chat:Message",
|
|
3158
2910
|
attachments: [],
|
|
3159
2911
|
author: {
|
|
3160
|
-
userId:
|
|
2912
|
+
userId: RESOURCE_EVENT_SLACK_AUTHOR_ID,
|
|
3161
2913
|
userName: "junior-event",
|
|
3162
2914
|
fullName: "Junior event",
|
|
3163
2915
|
isBot: true,
|
|
@@ -3175,7 +2927,7 @@ function slackSerializedResourceEventMessage(input) {
|
|
|
3175
2927
|
resource_event_type: input.eventType,
|
|
3176
2928
|
thread_ts: input.threadTs,
|
|
3177
2929
|
type: "message",
|
|
3178
|
-
user:
|
|
2930
|
+
user: RESOURCE_EVENT_SLACK_AUTHOR_ID
|
|
3179
2931
|
},
|
|
3180
2932
|
text: input.text,
|
|
3181
2933
|
threadId: `slack:${input.channelId}:${input.threadTs}`
|
|
@@ -3219,7 +2971,7 @@ function createSlackResourceEventInboundMessage(input) {
|
|
|
3219
2971
|
receivedAtMs: Date.now(),
|
|
3220
2972
|
input: {
|
|
3221
2973
|
text: input.text,
|
|
3222
|
-
authorId:
|
|
2974
|
+
authorId: RESOURCE_EVENT_SLACK_AUTHOR_ID,
|
|
3223
2975
|
metadata: {
|
|
3224
2976
|
kind: "resource_event",
|
|
3225
2977
|
installation: {
|
|
@@ -3259,10 +3011,6 @@ function routeForRecords(records) {
|
|
|
3259
3011
|
return metadata.route === "mention";
|
|
3260
3012
|
}) ? "mention" : "subscribed";
|
|
3261
3013
|
}
|
|
3262
|
-
function isResourceEventNotificationMessage(message) {
|
|
3263
|
-
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
3264
|
-
return raw?.event_type === "resource_event";
|
|
3265
|
-
}
|
|
3266
3014
|
function restoreMessage(args) {
|
|
3267
3015
|
const metadata = parseSlackMetadata(args.record.input.metadata);
|
|
3268
3016
|
if (!metadata) {
|
|
@@ -3278,7 +3026,7 @@ function restoreMessage(args) {
|
|
|
3278
3026
|
async function bindSlackActorIdentities(args) {
|
|
3279
3027
|
const byAuthorId = /* @__PURE__ */ new Map();
|
|
3280
3028
|
for (const message of args.messages) {
|
|
3281
|
-
if (
|
|
3029
|
+
if (isResourceEventSlackMessage(message)) {
|
|
3282
3030
|
continue;
|
|
3283
3031
|
}
|
|
3284
3032
|
const authorId = requireSlackAuthorId(message);
|
|
@@ -4497,7 +4245,7 @@ function registerVercelPluginTaskDevConsumer() {
|
|
|
4497
4245
|
}
|
|
4498
4246
|
|
|
4499
4247
|
// src/chat/services/subscribed-decision.ts
|
|
4500
|
-
import { z as
|
|
4248
|
+
import { z as z5 } from "zod";
|
|
4501
4249
|
|
|
4502
4250
|
// src/chat/services/subscribed-reply-router-policy.ts
|
|
4503
4251
|
function buildSubscribedReplyRouterPolicy(assistantName) {
|
|
@@ -4542,13 +4290,13 @@ Assess conversation floor ownership and whether the latest message continues wor
|
|
|
4542
4290
|
}
|
|
4543
4291
|
|
|
4544
4292
|
// src/chat/services/subscribed-decision.ts
|
|
4545
|
-
var replyDecisionSchema =
|
|
4546
|
-
should_reply:
|
|
4547
|
-
should_unsubscribe:
|
|
4293
|
+
var replyDecisionSchema = z5.object({
|
|
4294
|
+
should_reply: z5.boolean().describe("Whether Junior should respond to this thread message."),
|
|
4295
|
+
should_unsubscribe: z5.boolean().describe(
|
|
4548
4296
|
"Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
|
|
4549
4297
|
),
|
|
4550
|
-
confidence:
|
|
4551
|
-
reason:
|
|
4298
|
+
confidence: z5.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
|
|
4299
|
+
reason: z5.string().describe("Short reason for the decision; use an empty string if none.")
|
|
4552
4300
|
}).strict();
|
|
4553
4301
|
var ROUTER_CONFIDENCE_THRESHOLD = 0.7;
|
|
4554
4302
|
var ROUTER_CLASSIFIER_MAX_TOKENS = 400;
|
|
@@ -5003,10 +4751,6 @@ function buildLogContext(deps, args) {
|
|
|
5003
4751
|
function actorUserName(message) {
|
|
5004
4752
|
return getMessageActorIdentity(message)?.userName;
|
|
5005
4753
|
}
|
|
5006
|
-
function isResourceEventNotificationMessage2(message) {
|
|
5007
|
-
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
5008
|
-
return raw?.event_type === "resource_event";
|
|
5009
|
-
}
|
|
5010
4754
|
function createSlackTurnRuntime(deps) {
|
|
5011
4755
|
const logContext = (args) => buildLogContext(deps, args);
|
|
5012
4756
|
const maybeHandleThreadOptOutDecision = async (args) => {
|
|
@@ -5427,7 +5171,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
5427
5171
|
const threadId = deps.getThreadId(thread, message);
|
|
5428
5172
|
const channelId = deps.getChannelId(thread, message);
|
|
5429
5173
|
const runId = deps.getRunId(thread, message);
|
|
5430
|
-
const isResourceEventNotification =
|
|
5174
|
+
const isResourceEventNotification = isResourceEventSlackMessage(message);
|
|
5431
5175
|
const actorId = isResourceEventNotification ? void 0 : message.author.userId;
|
|
5432
5176
|
const turnContext = logContext({
|
|
5433
5177
|
threadId,
|
|
@@ -6225,11 +5969,11 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
6225
5969
|
import { createSlackSource as createSlackSource2 } from "@sentry/junior-plugin-api";
|
|
6226
5970
|
|
|
6227
5971
|
// src/chat/slack/action-token.ts
|
|
6228
|
-
import { z as
|
|
6229
|
-
var slackActionTokenSchema =
|
|
6230
|
-
var slackMessageEnvelopeSchema =
|
|
6231
|
-
raw:
|
|
6232
|
-
action_token:
|
|
5972
|
+
import { z as z6 } from "zod";
|
|
5973
|
+
var slackActionTokenSchema = z6.string().trim().min(1).brand();
|
|
5974
|
+
var slackMessageEnvelopeSchema = z6.object({
|
|
5975
|
+
raw: z6.object({
|
|
5976
|
+
action_token: z6.unknown().optional()
|
|
6233
5977
|
}).optional()
|
|
6234
5978
|
});
|
|
6235
5979
|
function readSlackActionToken(message) {
|
|
@@ -6393,7 +6137,7 @@ function queuedInstructionActor(queued) {
|
|
|
6393
6137
|
};
|
|
6394
6138
|
}
|
|
6395
6139
|
function queuedInstructionProvenance(queued, teamId) {
|
|
6396
|
-
if (
|
|
6140
|
+
if (isResourceEventSlackMessage(queued.message)) {
|
|
6397
6141
|
return contextProvenance;
|
|
6398
6142
|
}
|
|
6399
6143
|
const identity = getMessageActorIdentity(queued.message);
|
|
@@ -6407,13 +6151,6 @@ function queuedInstructionProvenance(queued, teamId) {
|
|
|
6407
6151
|
);
|
|
6408
6152
|
return instructionProvenanceFor(author);
|
|
6409
6153
|
}
|
|
6410
|
-
function isResourceEventMessage(message) {
|
|
6411
|
-
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
6412
|
-
return raw?.event_type === "resource_event";
|
|
6413
|
-
}
|
|
6414
|
-
function resourceEventCredentialContext(message) {
|
|
6415
|
-
return isResourceEventMessage(message) ? { actor: { platform: "system", name: "resource-event" } } : void 0;
|
|
6416
|
-
}
|
|
6417
6154
|
async function resolveChannelName(thread) {
|
|
6418
6155
|
const existingName = thread.channel.name?.trim();
|
|
6419
6156
|
if (existingName) {
|
|
@@ -6542,7 +6279,7 @@ function createReplyToThread(deps) {
|
|
|
6542
6279
|
)
|
|
6543
6280
|
};
|
|
6544
6281
|
await Promise.all(
|
|
6545
|
-
(options.queuedMessages ?? []).filter((queued) => !
|
|
6282
|
+
(options.queuedMessages ?? []).filter((queued) => !isResourceEventSlackMessage(queued.message)).map(
|
|
6546
6283
|
(queued) => ensureSlackMessageActorIdentity(
|
|
6547
6284
|
queued.message,
|
|
6548
6285
|
teamId,
|
|
@@ -6551,15 +6288,28 @@ function createReplyToThread(deps) {
|
|
|
6551
6288
|
)
|
|
6552
6289
|
);
|
|
6553
6290
|
const effectiveUserText = currentText.userText;
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6291
|
+
let executionActor;
|
|
6292
|
+
let credentialContext;
|
|
6293
|
+
if (options.execution) {
|
|
6294
|
+
executionActor = options.execution.dispatch.actor;
|
|
6295
|
+
credentialContext = options.execution.credentialContext;
|
|
6296
|
+
} else if (isResourceEventSlackMessage(message)) {
|
|
6297
|
+
executionActor = RESOURCE_EVENT_SYSTEM_ACTOR;
|
|
6298
|
+
credentialContext = credentialContextForActor(executionActor);
|
|
6299
|
+
} else {
|
|
6300
|
+
executionActor = await ensureSlackMessageActorIdentity(
|
|
6301
|
+
message,
|
|
6302
|
+
teamId,
|
|
6303
|
+
deps.services.lookupSlackUser
|
|
6304
|
+
);
|
|
6305
|
+
if (executionActor) {
|
|
6306
|
+
credentialContext = credentialContextForActor(executionActor);
|
|
6307
|
+
}
|
|
6308
|
+
}
|
|
6309
|
+
if (!executionActor || !credentialContext) {
|
|
6310
|
+
throw new Error("Slack reply execution requires an actor");
|
|
6311
|
+
}
|
|
6312
|
+
const actor = "userId" in executionActor ? executionActor : void 0;
|
|
6563
6313
|
const slackActorId = actor?.userId;
|
|
6564
6314
|
const preparedState = options.preparedState ?? await deps.prepareTurnState({
|
|
6565
6315
|
thread,
|
|
@@ -6633,7 +6383,7 @@ function createReplyToThread(deps) {
|
|
|
6633
6383
|
attachments,
|
|
6634
6384
|
{
|
|
6635
6385
|
threadId,
|
|
6636
|
-
actorId:
|
|
6386
|
+
actorId: isResourceEventSlackMessage(queued.message) ? void 0 : queued.message.author.userId,
|
|
6637
6387
|
channelId,
|
|
6638
6388
|
runId,
|
|
6639
6389
|
conversation: preparedState.conversation,
|
|
@@ -7208,7 +6958,9 @@ function createReplyToThread(deps) {
|
|
|
7208
6958
|
},
|
|
7209
6959
|
routing: {
|
|
7210
6960
|
credentialContext,
|
|
7211
|
-
|
|
6961
|
+
// Always set the execution actor when known. Resource-event turns
|
|
6962
|
+
// carry the system principal; interactive turns carry the Slack user.
|
|
6963
|
+
actor: executionActor,
|
|
7212
6964
|
slackConversation,
|
|
7213
6965
|
source,
|
|
7214
6966
|
destination,
|
|
@@ -8236,27 +7988,57 @@ async function failContinuationStartup(args) {
|
|
|
8236
7988
|
);
|
|
8237
7989
|
}
|
|
8238
7990
|
}
|
|
8239
|
-
async function
|
|
8240
|
-
|
|
8241
|
-
|
|
7991
|
+
async function resolveSlackResumeUserActor(args) {
|
|
7992
|
+
try {
|
|
7993
|
+
const work = await getConversationWorkState({
|
|
7994
|
+
conversationId: args.conversationId
|
|
7995
|
+
});
|
|
7996
|
+
const workActor = work?.actor;
|
|
7997
|
+
if (workActor?.teamId === args.teamId && workActor.slackUserId === args.userId) {
|
|
7998
|
+
try {
|
|
7999
|
+
return createSlackActor(args.teamId, args.userId, {
|
|
8000
|
+
email: workActor.email,
|
|
8001
|
+
fullName: workActor.fullName,
|
|
8002
|
+
userName: workActor.slackUserName
|
|
8003
|
+
});
|
|
8004
|
+
} catch {
|
|
8005
|
+
}
|
|
8006
|
+
}
|
|
8007
|
+
} catch {
|
|
8008
|
+
}
|
|
8009
|
+
try {
|
|
8242
8010
|
return createSlackResumeActor({
|
|
8243
|
-
actor: stored,
|
|
8244
8011
|
teamId: args.teamId,
|
|
8245
8012
|
userId: args.userId
|
|
8246
8013
|
});
|
|
8014
|
+
} catch {
|
|
8015
|
+
return void 0;
|
|
8247
8016
|
}
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
return
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8017
|
+
}
|
|
8018
|
+
async function resolveResumeExecutionIdentity(args) {
|
|
8019
|
+
const routing = args.routingContext;
|
|
8020
|
+
if (routing?.credentialContext) {
|
|
8021
|
+
const actor2 = routing.dispatch?.actor ?? routing.actor ?? (!("type" in routing.credentialContext.actor) ? routing.credentialContext.actor : void 0);
|
|
8022
|
+
return actor2 ? { actor: actor2, credentialContext: routing.credentialContext } : void 0;
|
|
8023
|
+
}
|
|
8024
|
+
let actor = routing?.actor;
|
|
8025
|
+
if (!actor && isResourceEventConversationMessage(args.userMessage)) {
|
|
8026
|
+
actor = RESOURCE_EVENT_SYSTEM_ACTOR;
|
|
8027
|
+
}
|
|
8028
|
+
if (!actor && args.userMessage.author?.userId) {
|
|
8029
|
+
actor = await resolveSlackResumeUserActor({
|
|
8030
|
+
conversationId: args.conversationId,
|
|
8031
|
+
teamId: args.teamId,
|
|
8032
|
+
userId: args.userMessage.author.userId
|
|
8257
8033
|
});
|
|
8258
8034
|
}
|
|
8259
|
-
|
|
8035
|
+
if (!actor) {
|
|
8036
|
+
return void 0;
|
|
8037
|
+
}
|
|
8038
|
+
return {
|
|
8039
|
+
actor,
|
|
8040
|
+
credentialContext: credentialContextForActor(actor)
|
|
8041
|
+
};
|
|
8260
8042
|
}
|
|
8261
8043
|
function isContinuationResume(summary) {
|
|
8262
8044
|
return summary.state === "awaiting_resume" && (summary.resumeReason === "timeout" || summary.resumeReason === "yield" || summary.resumeReason === "retry");
|
|
@@ -8274,7 +8056,6 @@ async function failUnresumableContinuation(args) {
|
|
|
8274
8056
|
conversationId: args.conversationId
|
|
8275
8057
|
});
|
|
8276
8058
|
await recordAgentTurnSessionSummary({
|
|
8277
|
-
actor: args.summary.actor,
|
|
8278
8059
|
conversationId: args.conversationId,
|
|
8279
8060
|
destination: routing.destination,
|
|
8280
8061
|
dispatchId: args.summary.dispatchId,
|
|
@@ -8341,16 +8122,32 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
|
|
|
8341
8122
|
(message) => message.role === "user" && options.inputMessageIds?.includes(message.id)
|
|
8342
8123
|
) : void 0;
|
|
8343
8124
|
const userMessage = getTurnUserMessage(conversation, payload.sessionId) ?? dispatchUserMessage;
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8349
|
-
);
|
|
8125
|
+
if (!userMessage) {
|
|
8126
|
+
await failStrandedSessionWithFallback({
|
|
8127
|
+
conversationId: payload.conversationId,
|
|
8128
|
+
errorMessage: `Unable to locate the persisted user message for agent continuation session "${payload.sessionId}"`,
|
|
8129
|
+
sessionRecord: activeSessionRecord
|
|
8130
|
+
});
|
|
8131
|
+
return false;
|
|
8350
8132
|
}
|
|
8351
8133
|
if (conversation.processing.activeTurnId !== payload.sessionId) {
|
|
8352
8134
|
return false;
|
|
8353
8135
|
}
|
|
8136
|
+
const identity = await resolveResumeExecutionIdentity({
|
|
8137
|
+
conversationId: payload.conversationId,
|
|
8138
|
+
routingContext: options.routingContext,
|
|
8139
|
+
teamId: destination.teamId,
|
|
8140
|
+
userMessage
|
|
8141
|
+
});
|
|
8142
|
+
if (!identity) {
|
|
8143
|
+
await failStrandedSessionWithFallback({
|
|
8144
|
+
conversationId: payload.conversationId,
|
|
8145
|
+
errorMessage: "Unable to rebuild Slack actor for continuation",
|
|
8146
|
+
sessionRecord: activeSessionRecord
|
|
8147
|
+
});
|
|
8148
|
+
return false;
|
|
8149
|
+
}
|
|
8150
|
+
const { actor, credentialContext } = identity;
|
|
8354
8151
|
const channelConfiguration = getChannelConfigurationServiceById(
|
|
8355
8152
|
destination.channelId
|
|
8356
8153
|
);
|
|
@@ -8358,34 +8155,6 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
|
|
|
8358
8155
|
excludeMessageId: userMessage.id
|
|
8359
8156
|
});
|
|
8360
8157
|
const sandboxRef = getPersistedSandboxState(currentState);
|
|
8361
|
-
let actor;
|
|
8362
|
-
let credentialContext;
|
|
8363
|
-
if (options.routingContext?.credentialContext) {
|
|
8364
|
-
credentialContext = options.routingContext.credentialContext;
|
|
8365
|
-
} else if (systemActor) {
|
|
8366
|
-
credentialContext = { actor: systemActor };
|
|
8367
|
-
} else {
|
|
8368
|
-
actor = await resolveContinuationActor({
|
|
8369
|
-
conversationId: payload.conversationId,
|
|
8370
|
-
sessionRecordActor: activeSessionRecord.actor,
|
|
8371
|
-
teamId: destination.teamId,
|
|
8372
|
-
userId: userActorId
|
|
8373
|
-
});
|
|
8374
|
-
if (!actor) {
|
|
8375
|
-
await failStrandedSessionWithFallback({
|
|
8376
|
-
conversationId: payload.conversationId,
|
|
8377
|
-
errorMessage: "Stored Slack actor missing for continuation",
|
|
8378
|
-
sessionRecord: activeSessionRecord
|
|
8379
|
-
});
|
|
8380
|
-
return false;
|
|
8381
|
-
}
|
|
8382
|
-
credentialContext = {
|
|
8383
|
-
actor: {
|
|
8384
|
-
type: "user",
|
|
8385
|
-
userId: actor.userId
|
|
8386
|
-
}
|
|
8387
|
-
};
|
|
8388
|
-
}
|
|
8389
8158
|
const routing = await resolveTurnSessionRouting({
|
|
8390
8159
|
conversationId: payload.conversationId
|
|
8391
8160
|
});
|
|
@@ -8433,7 +8202,7 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
|
|
|
8433
8202
|
routing: {
|
|
8434
8203
|
...options.routingContext,
|
|
8435
8204
|
credentialContext,
|
|
8436
|
-
|
|
8205
|
+
actor,
|
|
8437
8206
|
destination: routingDestination,
|
|
8438
8207
|
source,
|
|
8439
8208
|
toolChannelId: artifacts.assistantContextChannelId ?? destination.channelId
|
|
@@ -8554,7 +8323,6 @@ async function failStrandedSessionWithFallback(args) {
|
|
|
8554
8323
|
}
|
|
8555
8324
|
if (args.sessionRecord.dispatchId) {
|
|
8556
8325
|
await recordAgentTurnSessionSummary({
|
|
8557
|
-
actor: args.sessionRecord.actor,
|
|
8558
8326
|
conversationId: args.conversationId,
|
|
8559
8327
|
destination: routing.destination,
|
|
8560
8328
|
dispatchId: args.sessionRecord.dispatchId,
|
|
@@ -8619,7 +8387,6 @@ async function recoverStrandedRunningSession(args) {
|
|
|
8619
8387
|
messages: sessionRecord.piMessages,
|
|
8620
8388
|
errorMessage: "Recovered running session after hard worker death",
|
|
8621
8389
|
modelId,
|
|
8622
|
-
actor: sessionRecord.actor,
|
|
8623
8390
|
surface: sessionRecord.surface
|
|
8624
8391
|
});
|
|
8625
8392
|
if (!parked) {
|
|
@@ -8949,7 +8716,7 @@ async function ingestResourceEvent(input, options) {
|
|
|
8949
8716
|
}
|
|
8950
8717
|
|
|
8951
8718
|
// src/chat/event-tasks/ingest.ts
|
|
8952
|
-
import { createHash
|
|
8719
|
+
import { createHash } from "crypto";
|
|
8953
8720
|
import {
|
|
8954
8721
|
createSlackSource as createSlackSource3,
|
|
8955
8722
|
RESOURCE_EVENT_SUMMARY_MAX_LENGTH,
|
|
@@ -8957,7 +8724,7 @@ import {
|
|
|
8957
8724
|
resourceEventSchema as resourceEventSchema2
|
|
8958
8725
|
} from "@sentry/junior-plugin-api";
|
|
8959
8726
|
function eventTaskDispatchKey(taskId, namespace, eventKey) {
|
|
8960
|
-
return `event-task:${
|
|
8727
|
+
return `event-task:${createHash("sha256").update(`${taskId}\0${namespace}\0${eventKey}`).digest("hex").slice(0, 32)}`;
|
|
8961
8728
|
}
|
|
8962
8729
|
function oneLine(value) {
|
|
8963
8730
|
return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 512);
|