@sentry/junior 0.137.0 → 0.139.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-MZOKEP3J.js → agent-hooks-MJXMD7JP.js} +11 -9
- package/dist/api/schema/task.d.ts +100 -1
- package/dist/api/schema.d.ts +2 -2
- package/dist/api/schema.js +9 -1
- package/dist/api.js +202 -55
- package/dist/app.d.ts +7 -0
- package/dist/app.js +601 -1356
- package/dist/{catalog-runtime-MD66YLFV.js → catalog-runtime-GCCFYPIK.js} +6 -6
- package/dist/chat/agent/request.d.ts +44 -4
- package/dist/chat/agent-dispatch/heartbeat.d.ts +5 -0
- package/dist/chat/agent-dispatch/types.d.ts +1 -1
- package/dist/chat/agent-invocations/errors.d.ts +8 -0
- package/dist/chat/agent-invocations/spawn.d.ts +12 -0
- package/dist/chat/agent-invocations/store.d.ts +44 -0
- package/dist/chat/agent-invocations/types.d.ts +449 -0
- package/dist/chat/agent-invocations/work.d.ts +31 -0
- package/dist/chat/config.d.ts +1 -0
- package/dist/chat/conversations/sql/store.d.ts +8 -0
- package/dist/chat/conversations/store.d.ts +7 -0
- package/dist/chat/credentials/context.d.ts +14 -0
- package/dist/chat/experimental.d.ts +16 -0
- package/dist/chat/resource-events/actor.d.ts +23 -0
- package/dist/chat/runtime/agent-runner.d.ts +2 -1
- package/dist/chat/services/auth-pause.d.ts +0 -1
- package/dist/chat/services/mcp-auth-orchestration.d.ts +3 -2
- package/dist/chat/services/plugin-auth-orchestration.d.ts +3 -2
- package/dist/chat/state/turn-session.d.ts +1 -5
- package/dist/chat/task-execution/state.d.ts +23 -11
- package/dist/chat/task-execution/store.d.ts +20 -11
- package/dist/chat/task-execution/worker.d.ts +2 -2
- package/dist/chat/tasks/execution-stats.d.ts +34 -3
- package/dist/chat/tasks/read.d.ts +3 -1
- package/dist/chat/tools/runtime/spawn-agent.d.ts +31 -0
- package/dist/chat/tools/types.d.ts +2 -0
- package/dist/{chunk-T6Z5S6PQ.js → chunk-2ECYPYKP.js} +1 -1
- package/dist/chunk-3T2JAGRH.js +115 -0
- package/dist/chunk-3Y47VMHV.js +6 -0
- package/dist/chunk-4V4QIYJH.js +41 -0
- package/dist/{chunk-SYCX4DOK.js → chunk-5GSZWRE2.js} +434 -65
- package/dist/chunk-5IDFPCON.js +46 -0
- package/dist/{chunk-36EG34YI.js → chunk-6OHTDR4F.js} +1 -1
- package/dist/chunk-6SU2DT27.js +441 -0
- package/dist/{chunk-UG6ZYPBI.js → chunk-75I3UBIL.js} +73 -60
- package/dist/chunk-AEQISMMU.js +711 -0
- package/dist/{chunk-5PNJMOY5.js → chunk-C2N6MNO4.js} +9 -2
- package/dist/{chunk-BZAMASJP.js → chunk-CXH25EL4.js} +2 -2
- package/dist/{chunk-K2NCQJKH.js → chunk-DW4PMHNW.js} +3 -3
- package/dist/chunk-EM225ITJ.js +56 -0
- package/dist/{chunk-UOXATPSI.js → chunk-G52UXKGO.js} +7 -5
- package/dist/chunk-GI52BW74.js +207 -0
- package/dist/{chunk-3Q342EJJ.js → chunk-GWQSZT4C.js} +2 -2
- package/dist/{chunk-EPBBYMNE.js → chunk-HUO3UTAQ.js} +1 -1
- package/dist/{chunk-WPPXIAFB.js → chunk-IIESAYDL.js} +17 -434
- package/dist/chunk-IUFM5JWV.js +24 -0
- package/dist/{chunk-UZQ4VY3M.js → chunk-J3S57AXY.js} +1 -1
- package/dist/{chunk-DQXAAVTR.js → chunk-J6EJQCHY.js} +46 -1471
- package/dist/{chunk-6ZK6FZIV.js → chunk-KCBZSJRU.js} +6 -27
- package/dist/chunk-MQ5RYATN.js +1523 -0
- package/dist/{chunk-5G34IEK2.js → chunk-MXTVUV3I.js} +2 -56
- package/dist/{chunk-YRPC6MJY.js → chunk-MXVD2BDS.js} +1 -1
- package/dist/{chunk-POBSY47Q.js → chunk-PJW6U46K.js} +337 -306
- package/dist/chunk-Q6QZTTLS.js +55 -0
- package/dist/{chunk-ZFS67WIR.js → chunk-QTBKPZDA.js} +57 -6
- package/dist/chunk-R776HKPK.js +81 -0
- package/dist/{chunk-77VDLF3Z.js → chunk-RUIXF3YQ.js} +10 -0
- package/dist/chunk-U27DSXKB.js +714 -0
- package/dist/{chunk-XZ7NPXAB.js → chunk-U7CMWQ7Z.js} +1 -1
- package/dist/{chunk-RB4NJKEX.js → chunk-UDBUS533.js} +125 -51
- package/dist/chunk-WQRX57EA.js +668 -0
- package/dist/chunk-WZH4JV7R.js +320 -0
- package/dist/{chunk-HCIVH3JS.js → chunk-YCTDA7BD.js} +28 -0
- package/dist/{chunk-YNFERGKP.js → chunk-YGZ2OLXL.js} +1 -1
- package/dist/{chunk-EWDSB24B.js → chunk-ZQCGQMF2.js} +16 -776
- package/dist/{chunk-KJ4HGRHN.js → chunk-ZYQSPQYR.js} +515 -601
- package/dist/cli/chat.js +68 -29
- package/dist/cli/check.js +7 -7
- package/dist/cli/plugins.js +15 -13
- package/dist/cli/snapshot-create.js +11 -10
- package/dist/cli/upgrade.js +8 -8
- package/dist/conversation-work-KATFHLG3.js +56 -0
- package/dist/db/schema/agent-invocations.d.ts +544 -0
- package/dist/db/schema/task-executions.d.ts +23 -2
- package/dist/db/schema.d.ts +563 -2
- package/dist/{db-66E7VDNC.js → db-UXPPGHDF.js} +7 -7
- package/dist/experimental-HH6OM6UH.js +13 -0
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +4 -3
- package/dist/{oauth-callback-server-7QPD4Q7P.js → oauth-callback-server-4ZYMD5UA.js} +28 -19
- package/dist/{runner-L2BKJKOD.js → runner-MZSEONRZ.js} +32 -18
- package/dist/{sandbox-egress-signals-A5HWIQH4.js → sandbox-egress-signals-EKPAVWQL.js} +2 -2
- package/dist/{skills-HOQ2NSPW.js → skills-IMVPXSQ7.js} +7 -7
- package/dist/spawn-S5LSVOCE.js +38 -0
- package/dist/{validation-ENHI7S2C.js → validation-ZKCY2BVR.js} +7 -7
- package/dist/version.js +1 -1
- package/dist/work-GG3XDYRX.js +46 -0
- package/dist/worker-23AUELCJ.js +24 -0
- package/migrations/0021_first_warhawk.sql +35 -0
- package/migrations/0022_task_execution_status.sql +3 -0
- package/migrations/meta/0021_snapshot.json +2176 -0
- package/migrations/meta/0022_snapshot.json +2186 -0
- package/migrations/meta/_journal.json +15 -1
- package/package.json +4 -4
- package/dist/chunk-6QW2RRQT.js +0 -233
package/dist/app.js
CHANGED
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
processConversationWork
|
|
3
|
+
} from "./chunk-WQRX57EA.js";
|
|
4
|
+
import {
|
|
5
|
+
bindSpawnAgent
|
|
6
|
+
} from "./chunk-4V4QIYJH.js";
|
|
7
|
+
import {
|
|
8
|
+
createAgentInvocationWorker,
|
|
9
|
+
enqueueAgentInvocation,
|
|
10
|
+
listPendingAgentInvocationMailboxAppends,
|
|
11
|
+
routeAgentInvocationWork
|
|
12
|
+
} from "./chunk-AEQISMMU.js";
|
|
13
|
+
import {
|
|
4
14
|
GET as GET2,
|
|
5
15
|
GET2 as GET3,
|
|
6
16
|
ResumeTurnBusyError,
|
|
7
|
-
ackMessages,
|
|
8
|
-
appendAndEnqueueInboundMessage,
|
|
9
|
-
beginConversationResume,
|
|
10
17
|
buildAuthPauseResponse,
|
|
11
18
|
buildSlackOutputMessage,
|
|
12
|
-
checkInConversationWork,
|
|
13
|
-
clearConsumedConversationWake,
|
|
14
|
-
clearExpiredConversationLease,
|
|
15
|
-
completeConversationWork,
|
|
16
|
-
countPendingConversationMessages,
|
|
17
19
|
createSlackAdapterAssistantStatusSession,
|
|
18
|
-
deadLetterAttempt,
|
|
19
|
-
drainConversationMailbox,
|
|
20
|
-
ensureConversationWake,
|
|
21
20
|
getAssistantThreadContext,
|
|
22
21
|
getAwaitingAgentContinueRequest,
|
|
23
22
|
getChannelId,
|
|
24
|
-
getConversationWorkState,
|
|
25
23
|
getMessageTs,
|
|
26
24
|
getRunId,
|
|
27
25
|
getSlackApiErrorCode,
|
|
@@ -29,61 +27,84 @@ import {
|
|
|
29
27
|
getThreadId,
|
|
30
28
|
getThreadTs,
|
|
31
29
|
getTurnRequestDeadline,
|
|
32
|
-
hasRunnableConversationWork,
|
|
33
|
-
isFinalAttempt,
|
|
34
|
-
isInvalidConversationRecordError,
|
|
35
30
|
isRetryableSlackPostError,
|
|
36
31
|
isSlackTitlePermissionError,
|
|
37
|
-
listActiveConversationIds,
|
|
38
32
|
publishAppHomeView,
|
|
39
33
|
receiveLocalOAuthCredential,
|
|
40
|
-
recordAttemptFailure,
|
|
41
|
-
releaseConversationWork,
|
|
42
|
-
removeActiveConversation,
|
|
43
|
-
requestConversationContinuation,
|
|
44
34
|
resumeSlackTurn,
|
|
45
35
|
runWithTurnRequestDeadline,
|
|
46
36
|
scheduleAgentContinue,
|
|
47
37
|
sendSlackReply,
|
|
48
38
|
shouldKeepProcessingReactionForToolInvocation,
|
|
49
39
|
splitSlackReplyText,
|
|
50
|
-
startConversationWork,
|
|
51
40
|
startSlackProcessingReaction,
|
|
52
41
|
stripLeadingBotMention
|
|
53
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-J6EJQCHY.js";
|
|
54
43
|
import "./chunk-FA6POGLH.js";
|
|
55
44
|
import {
|
|
56
|
-
|
|
45
|
+
CONVERSATION_WORK_STALE_ENQUEUE_MS,
|
|
46
|
+
appendAndEnqueueInboundMessage,
|
|
47
|
+
clearExpiredConversationLease,
|
|
48
|
+
ensureConversationWake,
|
|
49
|
+
getConversationWorkState,
|
|
50
|
+
hasRunnableConversationWork,
|
|
51
|
+
isInvalidConversationRecordError,
|
|
52
|
+
listActiveConversationIds,
|
|
53
|
+
removeActiveConversation
|
|
54
|
+
} from "./chunk-MQ5RYATN.js";
|
|
55
|
+
import {
|
|
57
56
|
buildDeliveredTurnStatePatch,
|
|
57
|
+
claimDispatchMailboxAppend,
|
|
58
58
|
completeAuthPauseTurn,
|
|
59
|
+
confirmDispatchMailboxAppend,
|
|
60
|
+
createOrGetDispatch,
|
|
59
61
|
finalizeFailedTurnReplyWithEvent,
|
|
60
62
|
getAgentTurnDiagnosticsAttributes,
|
|
63
|
+
getDispatchConversationId,
|
|
64
|
+
getDispatchInputMessageId,
|
|
65
|
+
getDispatchInputMessageIds,
|
|
66
|
+
getDispatchRecord,
|
|
67
|
+
getDispatchTurnId,
|
|
68
|
+
getPluginDispatchProjection,
|
|
61
69
|
getTurnUserMessage,
|
|
62
70
|
getTurnUserReplyAttachmentContext,
|
|
63
71
|
getTurnUserSlackMessageTs,
|
|
72
|
+
isTerminalDispatchStatus,
|
|
73
|
+
listPendingDispatchMailboxAppends,
|
|
74
|
+
markDispatchAwaitingResume,
|
|
75
|
+
markDispatchBlocked,
|
|
76
|
+
markDispatchCompleted,
|
|
77
|
+
markDispatchFailed,
|
|
78
|
+
markDispatchRunning,
|
|
64
79
|
persistAuthPauseTurnState,
|
|
65
80
|
processPluginTask,
|
|
66
81
|
requireTurnFailureEventId,
|
|
67
82
|
resolveTurnSessionRouting,
|
|
68
83
|
scheduleSessionCompletedPluginTasks
|
|
69
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-5GSZWRE2.js";
|
|
85
|
+
import {
|
|
86
|
+
ConversationTurnLifecycleService
|
|
87
|
+
} from "./chunk-Q6QZTTLS.js";
|
|
70
88
|
import {
|
|
71
89
|
GET,
|
|
72
90
|
conversationVisibilityFromSlackChannelType,
|
|
73
|
-
recordTaskExecution,
|
|
74
91
|
resolveSlackChannelTypeFromMessage,
|
|
75
92
|
resolveSlackConversationContext
|
|
76
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-3T2JAGRH.js";
|
|
77
94
|
import "./chunk-4CODA7P5.js";
|
|
95
|
+
import {
|
|
96
|
+
recordTaskExecution
|
|
97
|
+
} from "./chunk-GI52BW74.js";
|
|
78
98
|
import "./chunk-UTL3MHPC.js";
|
|
79
99
|
import {
|
|
80
|
-
ConversationQueueMessageRejectedError,
|
|
81
|
-
conversationQueueMessageSchema,
|
|
82
100
|
getVercelConversationWorkQueue,
|
|
83
|
-
isConversationQueueMessageRejectedError,
|
|
84
101
|
resolveConversationWorkQueueTopic,
|
|
85
102
|
verifyConversationQueueMessage
|
|
86
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-KCBZSJRU.js";
|
|
104
|
+
import {
|
|
105
|
+
conversationQueueMessageSchema,
|
|
106
|
+
isConversationQueueMessageRejectedError
|
|
107
|
+
} from "./chunk-IUFM5JWV.js";
|
|
87
108
|
import {
|
|
88
109
|
PLUGIN_TASK_QUEUE_TOPIC,
|
|
89
110
|
createVercelQueueClient,
|
|
@@ -92,7 +113,7 @@ import {
|
|
|
92
113
|
import {
|
|
93
114
|
validatePluginEgressCredentialHooks,
|
|
94
115
|
validatePluginRegistrations
|
|
95
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-J3S57AXY.js";
|
|
96
117
|
import {
|
|
97
118
|
defineJuniorPlugins,
|
|
98
119
|
pluginCatalogConfigFromEnv,
|
|
@@ -100,8 +121,6 @@ import {
|
|
|
100
121
|
pluginRuntimeRegistrationsFromPluginSet
|
|
101
122
|
} from "./chunk-FIANEE7Z.js";
|
|
102
123
|
import {
|
|
103
|
-
AuthorizationFlowDisabledError,
|
|
104
|
-
PluginCredentialFailureError,
|
|
105
124
|
SANDBOX_EGRESS_PROXY_PATH,
|
|
106
125
|
appendSlackLegacyAttachmentText,
|
|
107
126
|
buildSteeringPiMessage,
|
|
@@ -127,22 +146,29 @@ import {
|
|
|
127
146
|
setConfigDefaults,
|
|
128
147
|
shouldEmitDevAgentTrace,
|
|
129
148
|
shouldPropagateSandboxEgressTrace
|
|
130
|
-
} from "./chunk-
|
|
149
|
+
} from "./chunk-ZYQSPQYR.js";
|
|
150
|
+
import {
|
|
151
|
+
AuthorizationFlowDisabledError,
|
|
152
|
+
PluginCredentialFailureError
|
|
153
|
+
} from "./chunk-WZH4JV7R.js";
|
|
131
154
|
import "./chunk-DIB4GX3G.js";
|
|
132
155
|
import {
|
|
133
|
-
RetryableDeliveryError,
|
|
134
156
|
createUserTokenStore,
|
|
135
157
|
deleteMcpAuthSessionsForUserProvider,
|
|
136
158
|
deleteMcpServerSessionId,
|
|
137
|
-
deleteMcpStoredOAuthCredentials
|
|
159
|
+
deleteMcpStoredOAuthCredentials
|
|
160
|
+
} from "./chunk-ZQCGQMF2.js";
|
|
161
|
+
import {
|
|
162
|
+
RetryableDeliveryError
|
|
163
|
+
} from "./chunk-R776HKPK.js";
|
|
164
|
+
import {
|
|
138
165
|
formatProviderLabel,
|
|
139
166
|
postSlackMessage,
|
|
140
167
|
startOAuthFlow
|
|
141
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-U27DSXKB.js";
|
|
142
169
|
import {
|
|
143
170
|
ConversationTurnBoundaryError,
|
|
144
171
|
CooperativeTurnYieldError,
|
|
145
|
-
JUNIOR_THREAD_STATE_TTL_MS,
|
|
146
172
|
TurnInputCommitLostError,
|
|
147
173
|
TurnInputDeferredError,
|
|
148
174
|
abandonAgentTurnSessionRecord,
|
|
@@ -195,47 +221,54 @@ import {
|
|
|
195
221
|
trimTrailingAssistantMessages,
|
|
196
222
|
updateConversationStats,
|
|
197
223
|
upsertConversationMessage
|
|
198
|
-
} from "./chunk-
|
|
199
|
-
import "./chunk-
|
|
224
|
+
} from "./chunk-PJW6U46K.js";
|
|
225
|
+
import "./chunk-3Y47VMHV.js";
|
|
226
|
+
import "./chunk-HUO3UTAQ.js";
|
|
227
|
+
import {
|
|
228
|
+
getExperimentalFeatures,
|
|
229
|
+
setExperimentalFeatures
|
|
230
|
+
} from "./chunk-5IDFPCON.js";
|
|
200
231
|
import {
|
|
201
232
|
getSandboxResourceConfig,
|
|
202
233
|
setSandboxResourceConfig
|
|
203
|
-
} from "./chunk-
|
|
234
|
+
} from "./chunk-G52UXKGO.js";
|
|
204
235
|
import {
|
|
205
236
|
createSchedulerSqlStore,
|
|
206
237
|
findMatchingEventTasks
|
|
207
|
-
} from "./chunk-
|
|
238
|
+
} from "./chunk-DW4PMHNW.js";
|
|
208
239
|
import {
|
|
209
240
|
parseSlackThreadId
|
|
210
|
-
} from "./chunk-
|
|
241
|
+
} from "./chunk-MXVD2BDS.js";
|
|
211
242
|
import "./chunk-CDQ4YIZM.js";
|
|
212
243
|
import "./chunk-PDO5BLNM.js";
|
|
213
244
|
import "./chunk-UIE3R5XU.js";
|
|
214
245
|
import {
|
|
215
|
-
SlackActionError,
|
|
216
246
|
bindEventTaskCredentialSubject,
|
|
217
247
|
bindScheduledTaskCredentialSubject,
|
|
218
248
|
bindSlackDirectCredentialSubject,
|
|
219
249
|
createPluginLogger,
|
|
220
250
|
createPluginState,
|
|
221
251
|
createResourceEventTeamIdResolver,
|
|
222
|
-
downloadPrivateSlackFile,
|
|
223
252
|
getPluginApiRoutes,
|
|
224
253
|
getPluginRoutes,
|
|
225
254
|
getPlugins,
|
|
226
|
-
getSlackClient,
|
|
227
|
-
getWorkspaceTeamId,
|
|
228
|
-
isDmChannel,
|
|
229
|
-
normalizeSlackConversationId,
|
|
230
|
-
runWithSlackInstallationToken,
|
|
231
|
-
runWithWorkspaceTeamId,
|
|
232
255
|
setDashboardConversationLinkOptions,
|
|
233
256
|
setPlugins,
|
|
234
257
|
validatePlugins,
|
|
235
258
|
verifyEventTaskCredentialSubject,
|
|
236
259
|
verifyScheduledTaskCredentialSubject,
|
|
237
260
|
verifySlackDirectCredentialSubject
|
|
238
|
-
} from "./chunk-
|
|
261
|
+
} from "./chunk-IIESAYDL.js";
|
|
262
|
+
import {
|
|
263
|
+
SlackActionError,
|
|
264
|
+
downloadPrivateSlackFile,
|
|
265
|
+
getSlackClient,
|
|
266
|
+
getWorkspaceTeamId,
|
|
267
|
+
isDmChannel,
|
|
268
|
+
normalizeSlackConversationId,
|
|
269
|
+
runWithSlackInstallationToken,
|
|
270
|
+
runWithWorkspaceTeamId
|
|
271
|
+
} from "./chunk-6SU2DT27.js";
|
|
239
272
|
import {
|
|
240
273
|
contextProvenance,
|
|
241
274
|
createSlackDestination,
|
|
@@ -245,17 +278,22 @@ import {
|
|
|
245
278
|
getSqlExecutor,
|
|
246
279
|
instructionProvenanceFor,
|
|
247
280
|
requireSlackDestination,
|
|
248
|
-
withConversationEventLock
|
|
249
|
-
|
|
281
|
+
withConversationEventLock,
|
|
282
|
+
withConversationMutationLock
|
|
283
|
+
} from "./chunk-QTBKPZDA.js";
|
|
250
284
|
import {
|
|
285
|
+
juniorAgentBindings,
|
|
286
|
+
juniorAgentInvocations,
|
|
251
287
|
juniorConversationEvents,
|
|
252
288
|
juniorConversations
|
|
253
|
-
} from "./chunk-
|
|
289
|
+
} from "./chunk-UDBUS533.js";
|
|
254
290
|
import {
|
|
255
|
-
acquireActiveLock,
|
|
256
|
-
getStateAdapter,
|
|
257
291
|
sleep
|
|
258
|
-
} from "./chunk-
|
|
292
|
+
} from "./chunk-EM225ITJ.js";
|
|
293
|
+
import {
|
|
294
|
+
acquireActiveLock,
|
|
295
|
+
getStateAdapter
|
|
296
|
+
} from "./chunk-MXTVUV3I.js";
|
|
259
297
|
import {
|
|
260
298
|
STANDARD_MODEL_PROFILE,
|
|
261
299
|
botConfig,
|
|
@@ -273,19 +311,19 @@ import {
|
|
|
273
311
|
modelIdForProfile,
|
|
274
312
|
setSlackReactionConfig,
|
|
275
313
|
standardModelId
|
|
276
|
-
} from "./chunk-
|
|
314
|
+
} from "./chunk-75I3UBIL.js";
|
|
277
315
|
import {
|
|
278
316
|
juniorDestinations
|
|
279
317
|
} from "./chunk-VFUK3X5B.js";
|
|
280
|
-
import "./chunk-
|
|
281
|
-
import "./chunk-
|
|
318
|
+
import "./chunk-YGZ2OLXL.js";
|
|
319
|
+
import "./chunk-GWQSZT4C.js";
|
|
282
320
|
import {
|
|
283
321
|
pluginCatalogRuntime
|
|
284
|
-
} from "./chunk-
|
|
285
|
-
import "./chunk-
|
|
322
|
+
} from "./chunk-6OHTDR4F.js";
|
|
323
|
+
import "./chunk-CXH25EL4.js";
|
|
286
324
|
import {
|
|
287
|
-
|
|
288
|
-
} from "./chunk-
|
|
325
|
+
credentialContextForActor
|
|
326
|
+
} from "./chunk-RUIXF3YQ.js";
|
|
289
327
|
import {
|
|
290
328
|
createActor,
|
|
291
329
|
createSlackActor,
|
|
@@ -314,7 +352,7 @@ import {
|
|
|
314
352
|
withContext,
|
|
315
353
|
withLogContext,
|
|
316
354
|
withSpan
|
|
317
|
-
} from "./chunk-
|
|
355
|
+
} from "./chunk-2ECYPYKP.js";
|
|
318
356
|
import {
|
|
319
357
|
continueTrace
|
|
320
358
|
} from "./chunk-6GWA276C.js";
|
|
@@ -322,10 +360,10 @@ import "./chunk-OOUNJNMR.js";
|
|
|
322
360
|
import "./chunk-H4HBKISO.js";
|
|
323
361
|
import {
|
|
324
362
|
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
|
|
325
|
-
} from "./chunk-
|
|
363
|
+
} from "./chunk-C2N6MNO4.js";
|
|
326
364
|
import {
|
|
327
365
|
JUNIOR_VERSION
|
|
328
|
-
} from "./chunk-
|
|
366
|
+
} from "./chunk-U7CMWQ7Z.js";
|
|
329
367
|
import "./chunk-MLKGABMK.js";
|
|
330
368
|
|
|
331
369
|
// src/app.ts
|
|
@@ -387,400 +425,20 @@ async function verifyDispatchCallbackRequest(request) {
|
|
|
387
425
|
}
|
|
388
426
|
}
|
|
389
427
|
|
|
390
|
-
// src/chat/agent-dispatch/store.ts
|
|
391
|
-
import { createHash } from "crypto";
|
|
392
|
-
import {
|
|
393
|
-
destinationSchema,
|
|
394
|
-
destinationVisibilitySchema,
|
|
395
|
-
isSlackDestination,
|
|
396
|
-
replyAttributionSchema,
|
|
397
|
-
sourceSchema
|
|
398
|
-
} from "@sentry/junior-plugin-api";
|
|
399
|
-
import { z as z2 } from "zod";
|
|
400
|
-
var DISPATCH_PREFIX = "junior:agent_dispatch";
|
|
401
|
-
var DISPATCH_LOCK_TTL_MS = 10 * 60 * 1e3;
|
|
402
|
-
var DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS = 1e4;
|
|
403
|
-
var DISPATCH_MAILBOX_APPEND_INDEX_MAX_LENGTH = 1e4;
|
|
404
|
-
var nonEmptyExactStringSchema = z2.string().min(1).refine(
|
|
405
|
-
(value) => value === value.trim() && value.toLowerCase() !== "unknown"
|
|
406
|
-
);
|
|
407
|
-
var pendingDispatchMailboxAppendIndexSchema = z2.array(
|
|
408
|
-
nonEmptyExactStringSchema
|
|
409
|
-
);
|
|
410
|
-
var dispatchStatusSchema = z2.enum([
|
|
411
|
-
"pending",
|
|
412
|
-
"running",
|
|
413
|
-
"awaiting_resume",
|
|
414
|
-
"completed",
|
|
415
|
-
"failed",
|
|
416
|
-
"blocked"
|
|
417
|
-
]);
|
|
418
|
-
var dispatchActorSchema = z2.object({
|
|
419
|
-
platform: z2.literal("system"),
|
|
420
|
-
name: nonEmptyExactStringSchema
|
|
421
|
-
}).strict();
|
|
422
|
-
var dispatchRecordSchema = z2.object({
|
|
423
|
-
actor: dispatchActorSchema,
|
|
424
|
-
createdAtMs: z2.number().finite(),
|
|
425
|
-
credentialSubject: credentialSubjectSchema.optional(),
|
|
426
|
-
destination: destinationSchema,
|
|
427
|
-
destinationVisibility: destinationVisibilitySchema,
|
|
428
|
-
errorMessage: z2.string().optional(),
|
|
429
|
-
id: nonEmptyExactStringSchema,
|
|
430
|
-
idempotencyKey: z2.string().min(1),
|
|
431
|
-
input: z2.string().min(1),
|
|
432
|
-
metadata: z2.record(z2.string(), z2.string()).optional(),
|
|
433
|
-
plugin: nonEmptyExactStringSchema,
|
|
434
|
-
replyAttribution: replyAttributionSchema.optional(),
|
|
435
|
-
resultMessageTs: z2.string().optional(),
|
|
436
|
-
source: sourceSchema,
|
|
437
|
-
status: dispatchStatusSchema,
|
|
438
|
-
updatedAtMs: z2.number().finite()
|
|
439
|
-
}).strict().superRefine((record, ctx) => {
|
|
440
|
-
if (!isSlackDestination(record.destination)) {
|
|
441
|
-
ctx.addIssue({
|
|
442
|
-
code: z2.ZodIssueCode.custom,
|
|
443
|
-
message: "Dispatch destination platform must be slack",
|
|
444
|
-
path: ["destination"]
|
|
445
|
-
});
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
const subject = record.credentialSubject;
|
|
449
|
-
if (!subject) {
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
if (subject.allowedWhen === "private-direct-conversation") {
|
|
453
|
-
if (!record.destination.channelId.startsWith("D")) {
|
|
454
|
-
ctx.addIssue({
|
|
455
|
-
code: z2.ZodIssueCode.custom,
|
|
456
|
-
message: "Dispatch credentialSubject requires a private direct Slack destination",
|
|
457
|
-
path: ["credentialSubject"]
|
|
458
|
-
});
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
if (subject.binding.type !== "slack-direct-conversation" || subject.binding.teamId !== record.destination.teamId || subject.binding.channelId !== record.destination.channelId) {
|
|
462
|
-
ctx.addIssue({
|
|
463
|
-
code: z2.ZodIssueCode.custom,
|
|
464
|
-
message: "Dispatch credentialSubject binding must match destination",
|
|
465
|
-
path: ["credentialSubject", "binding"]
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
if (subject.binding.type !== subject.allowedWhen || subject.binding.plugin !== record.plugin || subject.binding.taskId !== subject.taskId) {
|
|
471
|
-
ctx.addIssue({
|
|
472
|
-
code: z2.ZodIssueCode.custom,
|
|
473
|
-
message: "Dispatch credentialSubject binding must match task",
|
|
474
|
-
path: ["credentialSubject", "binding"]
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
});
|
|
478
|
-
var storedDispatchRecordSchema = dispatchRecordSchema.extend({
|
|
479
|
-
attempt: z2.number().int().nonnegative().optional(),
|
|
480
|
-
lastCallbackAtMs: z2.number().finite().optional(),
|
|
481
|
-
leaseExpiresAtMs: z2.number().finite().optional(),
|
|
482
|
-
maxAttempts: z2.number().int().positive().optional(),
|
|
483
|
-
version: z2.number().int().positive().optional()
|
|
484
|
-
});
|
|
485
|
-
function getDispatchStorageKey(id) {
|
|
486
|
-
return `${DISPATCH_PREFIX}:record:${id}`;
|
|
487
|
-
}
|
|
488
|
-
function dispatchLockKey(id) {
|
|
489
|
-
return `${DISPATCH_PREFIX}:lock:${id}`;
|
|
490
|
-
}
|
|
491
|
-
function pendingDispatchMailboxAppendIndexKey() {
|
|
492
|
-
return `${DISPATCH_PREFIX}:incomplete`;
|
|
493
|
-
}
|
|
494
|
-
function pendingDispatchMailboxAppendIndexLockKey() {
|
|
495
|
-
return `${DISPATCH_PREFIX}:incomplete:lock`;
|
|
496
|
-
}
|
|
497
|
-
function normalizeMetadata(metadata) {
|
|
498
|
-
if (!metadata) {
|
|
499
|
-
return void 0;
|
|
500
|
-
}
|
|
501
|
-
const entries = Object.entries(metadata).filter(
|
|
502
|
-
(entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
|
|
503
|
-
);
|
|
504
|
-
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
505
|
-
}
|
|
506
|
-
function buildDispatchId(plugin, idempotencyKey) {
|
|
507
|
-
const digest = createHash("sha256").update(plugin).update("\0").update(idempotencyKey).digest("hex").slice(0, 32);
|
|
508
|
-
return `dispatch_${digest}`;
|
|
509
|
-
}
|
|
510
|
-
function parseDispatchRecord(value) {
|
|
511
|
-
const parsed = parseStoredDispatchRecord(value);
|
|
512
|
-
return parsed?.record;
|
|
513
|
-
}
|
|
514
|
-
function parseStoredDispatchRecord(value) {
|
|
515
|
-
const parsed = storedDispatchRecordSchema.safeParse(value);
|
|
516
|
-
if (!parsed.success) {
|
|
517
|
-
return void 0;
|
|
518
|
-
}
|
|
519
|
-
const {
|
|
520
|
-
attempt: _attempt,
|
|
521
|
-
lastCallbackAtMs: _lastCallbackAtMs,
|
|
522
|
-
leaseExpiresAtMs: _leaseExpiresAtMs,
|
|
523
|
-
maxAttempts: _maxAttempts,
|
|
524
|
-
version: _version,
|
|
525
|
-
...record
|
|
526
|
-
} = parsed.data;
|
|
527
|
-
return {
|
|
528
|
-
...typeof parsed.data.leaseExpiresAtMs === "number" ? { legacyLeaseExpiresAtMs: parsed.data.leaseExpiresAtMs } : {},
|
|
529
|
-
record
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
function getDispatchConversationId(dispatch2) {
|
|
533
|
-
return `agent-dispatch:${dispatch2.id}`;
|
|
534
|
-
}
|
|
535
|
-
function getDispatchInputMessageId(dispatchId) {
|
|
536
|
-
return `agent-dispatch:${dispatchId}`;
|
|
537
|
-
}
|
|
538
|
-
function getLegacyDispatchInputMessageId(dispatchId) {
|
|
539
|
-
return `dispatch:${dispatchId}:user`;
|
|
540
|
-
}
|
|
541
|
-
function getDispatchInputMessageIds(dispatchId) {
|
|
542
|
-
return [
|
|
543
|
-
getDispatchInputMessageId(dispatchId),
|
|
544
|
-
getLegacyDispatchInputMessageId(dispatchId)
|
|
545
|
-
];
|
|
546
|
-
}
|
|
547
|
-
function getDispatchTurnId(dispatchId) {
|
|
548
|
-
return `dispatch:${dispatchId}`;
|
|
549
|
-
}
|
|
550
|
-
function toDispatchProjection(record) {
|
|
551
|
-
return {
|
|
552
|
-
id: record.id,
|
|
553
|
-
status: record.status,
|
|
554
|
-
...record.resultMessageTs ? { resultMessageTs: record.resultMessageTs } : {},
|
|
555
|
-
...record.errorMessage ? { errorMessage: record.errorMessage } : {}
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
function isTerminalDispatchStatus(status) {
|
|
559
|
-
return status === "completed" || status === "failed" || status === "blocked";
|
|
560
|
-
}
|
|
561
|
-
async function withDispatchLock(dispatchId, task) {
|
|
562
|
-
const state = getStateAdapter();
|
|
563
|
-
await state.connect();
|
|
564
|
-
const lock = await state.acquireLock(
|
|
565
|
-
dispatchLockKey(dispatchId),
|
|
566
|
-
DISPATCH_LOCK_TTL_MS
|
|
567
|
-
);
|
|
568
|
-
if (!lock) {
|
|
569
|
-
throw new Error(`Could not acquire dispatch lock for ${dispatchId}`);
|
|
570
|
-
}
|
|
571
|
-
try {
|
|
572
|
-
return await task(state);
|
|
573
|
-
} finally {
|
|
574
|
-
await state.releaseLock(lock);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
async function putRecord(state, record) {
|
|
578
|
-
const parsed = dispatchRecordSchema.safeParse(record);
|
|
579
|
-
if (!parsed.success) {
|
|
580
|
-
throw new Error(
|
|
581
|
-
`Dispatch record is invalid: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"} ${issue.message}`).join("; ")}`
|
|
582
|
-
);
|
|
583
|
-
}
|
|
584
|
-
const next = parsed.data;
|
|
585
|
-
await state.set(
|
|
586
|
-
getDispatchStorageKey(next.id),
|
|
587
|
-
next,
|
|
588
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
589
|
-
);
|
|
590
|
-
}
|
|
591
|
-
async function updatePendingDispatchMailboxAppendIndex(state, update) {
|
|
592
|
-
const lock = await state.acquireLock(
|
|
593
|
-
pendingDispatchMailboxAppendIndexLockKey(),
|
|
594
|
-
DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS
|
|
595
|
-
);
|
|
596
|
-
if (!lock) {
|
|
597
|
-
throw new Error("Could not acquire dispatch mailbox append index lock");
|
|
598
|
-
}
|
|
599
|
-
try {
|
|
600
|
-
const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
|
|
601
|
-
const ids = stored === void 0 || stored === null ? [] : pendingDispatchMailboxAppendIndexSchema.parse(stored);
|
|
602
|
-
const next = [...new Set(update([...new Set(ids)]))].slice(
|
|
603
|
-
-DISPATCH_MAILBOX_APPEND_INDEX_MAX_LENGTH
|
|
604
|
-
);
|
|
605
|
-
if (next.length === ids.length && next.every((id, index) => id === ids[index])) {
|
|
606
|
-
return;
|
|
607
|
-
}
|
|
608
|
-
await state.set(
|
|
609
|
-
pendingDispatchMailboxAppendIndexKey(),
|
|
610
|
-
next,
|
|
611
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
612
|
-
);
|
|
613
|
-
} finally {
|
|
614
|
-
await state.releaseLock(lock);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
async function getDispatchRecord(id) {
|
|
618
|
-
const state = getStateAdapter();
|
|
619
|
-
await state.connect();
|
|
620
|
-
return parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
|
|
621
|
-
}
|
|
622
|
-
async function createOrGetDispatch(args) {
|
|
623
|
-
const id = buildDispatchId(args.plugin, args.options.idempotencyKey);
|
|
624
|
-
return await withDispatchLock(id, async (state) => {
|
|
625
|
-
const existing = parseDispatchRecord(
|
|
626
|
-
await state.get(getDispatchStorageKey(id))
|
|
627
|
-
);
|
|
628
|
-
if (existing) {
|
|
629
|
-
return { record: existing, status: "already_exists" };
|
|
630
|
-
}
|
|
631
|
-
const metadata = normalizeMetadata(args.options.metadata);
|
|
632
|
-
const record = {
|
|
633
|
-
actor: { platform: "system", name: args.plugin },
|
|
634
|
-
createdAtMs: args.nowMs,
|
|
635
|
-
...args.options.credentialSubject ? { credentialSubject: args.options.credentialSubject } : {},
|
|
636
|
-
destination: args.options.destination,
|
|
637
|
-
destinationVisibility: args.options.destinationVisibility,
|
|
638
|
-
id,
|
|
639
|
-
idempotencyKey: args.options.idempotencyKey,
|
|
640
|
-
input: args.options.input,
|
|
641
|
-
...metadata ? { metadata } : {},
|
|
642
|
-
plugin: args.plugin,
|
|
643
|
-
...args.options.replyAttribution ? { replyAttribution: args.options.replyAttribution } : {},
|
|
644
|
-
status: "pending",
|
|
645
|
-
source: args.options.source,
|
|
646
|
-
updatedAtMs: args.nowMs
|
|
647
|
-
};
|
|
648
|
-
await updatePendingDispatchMailboxAppendIndex(
|
|
649
|
-
state,
|
|
650
|
-
(ids) => ids.includes(id) ? ids : [...ids, id]
|
|
651
|
-
);
|
|
652
|
-
await putRecord(state, record);
|
|
653
|
-
return { record, status: "created" };
|
|
654
|
-
});
|
|
655
|
-
}
|
|
656
|
-
async function transitionDispatch(id, transition) {
|
|
657
|
-
return await withDispatchLock(id, async (state) => {
|
|
658
|
-
const current = parseDispatchRecord(
|
|
659
|
-
await state.get(getDispatchStorageKey(id))
|
|
660
|
-
);
|
|
661
|
-
if (!current) {
|
|
662
|
-
return void 0;
|
|
663
|
-
}
|
|
664
|
-
const transitioned = transition(current);
|
|
665
|
-
if (transitioned === current) {
|
|
666
|
-
return current;
|
|
667
|
-
}
|
|
668
|
-
const next = {
|
|
669
|
-
...transitioned,
|
|
670
|
-
updatedAtMs: Date.now()
|
|
671
|
-
};
|
|
672
|
-
await putRecord(state, next);
|
|
673
|
-
return next;
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
async function markDispatchRunning(id) {
|
|
677
|
-
return await transitionDispatch(
|
|
678
|
-
id,
|
|
679
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : { ...record, status: "running", errorMessage: void 0 }
|
|
680
|
-
);
|
|
681
|
-
}
|
|
682
|
-
async function markDispatchAwaitingResume(id) {
|
|
683
|
-
return await transitionDispatch(
|
|
684
|
-
id,
|
|
685
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
686
|
-
...record,
|
|
687
|
-
status: "awaiting_resume"
|
|
688
|
-
}
|
|
689
|
-
);
|
|
690
|
-
}
|
|
691
|
-
async function markDispatchBlocked(id, errorMessage, resultMessageTs) {
|
|
692
|
-
return await transitionDispatch(
|
|
693
|
-
id,
|
|
694
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
695
|
-
...record,
|
|
696
|
-
errorMessage,
|
|
697
|
-
...resultMessageTs ? { resultMessageTs } : {},
|
|
698
|
-
status: "blocked"
|
|
699
|
-
}
|
|
700
|
-
);
|
|
701
|
-
}
|
|
702
|
-
async function markDispatchCompleted(id, resultMessageTs) {
|
|
703
|
-
const previous = await getDispatchRecord(id);
|
|
704
|
-
const next = await transitionDispatch(
|
|
705
|
-
id,
|
|
706
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
707
|
-
...record,
|
|
708
|
-
errorMessage: void 0,
|
|
709
|
-
...resultMessageTs ? { resultMessageTs } : {},
|
|
710
|
-
status: "completed"
|
|
711
|
-
}
|
|
712
|
-
);
|
|
713
|
-
if (next?.status === "completed" && previous?.status !== "completed" && next.plugin === "junior") {
|
|
714
|
-
const eventTaskId = next.metadata?.eventTaskId;
|
|
715
|
-
if (eventTaskId) {
|
|
716
|
-
await recordTaskExecution("event", eventTaskId, {
|
|
717
|
-
conversationId: getDispatchConversationId(next),
|
|
718
|
-
executionId: next.id,
|
|
719
|
-
nowMs: next.updatedAtMs
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
return next;
|
|
724
|
-
}
|
|
725
|
-
async function markDispatchFailed(id, errorMessage, resultMessageTs) {
|
|
726
|
-
return await transitionDispatch(
|
|
727
|
-
id,
|
|
728
|
-
(record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
729
|
-
...record,
|
|
730
|
-
errorMessage,
|
|
731
|
-
...resultMessageTs ? { resultMessageTs } : {},
|
|
732
|
-
status: "failed"
|
|
733
|
-
}
|
|
734
|
-
);
|
|
735
|
-
}
|
|
736
|
-
async function confirmDispatchMailboxAppend(id) {
|
|
737
|
-
const state = getStateAdapter();
|
|
738
|
-
await state.connect();
|
|
739
|
-
await updatePendingDispatchMailboxAppendIndex(
|
|
740
|
-
state,
|
|
741
|
-
(ids) => ids.filter((candidate) => candidate !== id)
|
|
742
|
-
);
|
|
743
|
-
}
|
|
744
|
-
async function listPendingDispatchMailboxAppends() {
|
|
745
|
-
const state = getStateAdapter();
|
|
746
|
-
await state.connect();
|
|
747
|
-
const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
|
|
748
|
-
return stored === void 0 || stored === null ? [] : [...new Set(pendingDispatchMailboxAppendIndexSchema.parse(stored))];
|
|
749
|
-
}
|
|
750
|
-
async function claimDispatchMailboxAppend(id, nowMs) {
|
|
751
|
-
return await withDispatchLock(id, async (state) => {
|
|
752
|
-
const stored = parseStoredDispatchRecord(
|
|
753
|
-
await state.get(getDispatchStorageKey(id))
|
|
754
|
-
);
|
|
755
|
-
if (!stored || stored.legacyLeaseExpiresAtMs && stored.legacyLeaseExpiresAtMs > nowMs) {
|
|
756
|
-
return void 0;
|
|
757
|
-
}
|
|
758
|
-
await putRecord(state, stored.record);
|
|
759
|
-
return stored.record;
|
|
760
|
-
});
|
|
761
|
-
}
|
|
762
|
-
async function getPluginDispatchProjection(args) {
|
|
763
|
-
const record = await getDispatchRecord(args.id);
|
|
764
|
-
if (!record || record.plugin !== args.plugin) {
|
|
765
|
-
return void 0;
|
|
766
|
-
}
|
|
767
|
-
return toDispatchProjection(record);
|
|
768
|
-
}
|
|
769
|
-
|
|
770
428
|
// src/chat/agent-dispatch/work.ts
|
|
771
|
-
import { z as
|
|
772
|
-
var agentDispatchMailboxMetadataSchema =
|
|
773
|
-
dispatchId:
|
|
774
|
-
kind:
|
|
429
|
+
import { z as z2 } from "zod";
|
|
430
|
+
var agentDispatchMailboxMetadataSchema = z2.object({
|
|
431
|
+
dispatchId: z2.string().min(1),
|
|
432
|
+
kind: z2.literal("agent_dispatch")
|
|
775
433
|
}).strict();
|
|
776
434
|
var AGENT_DISPATCH_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
777
435
|
function buildDispatchRoutingContext(dispatch2) {
|
|
778
436
|
return {
|
|
779
437
|
actor: dispatch2.actor,
|
|
780
|
-
credentialContext:
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
438
|
+
credentialContext: credentialContextForActor(
|
|
439
|
+
dispatch2.actor,
|
|
440
|
+
dispatch2.credentialSubject
|
|
441
|
+
),
|
|
784
442
|
destinationVisibility: dispatch2.destinationVisibility,
|
|
785
443
|
dispatch: {
|
|
786
444
|
actor: dispatch2.actor,
|
|
@@ -1020,7 +678,7 @@ function createAgentDispatchConversationWorker(options) {
|
|
|
1020
678
|
`Dispatch ${dispatch2.id} belongs to ${expectedConversationId}, not ${context.conversationId}`
|
|
1021
679
|
);
|
|
1022
680
|
}
|
|
1023
|
-
if (context.destination.platform !== dispatch2.destination.platform || context.destination.teamId !== dispatch2.destination.teamId || context.destination.channelId !== dispatch2.destination.channelId) {
|
|
681
|
+
if (!context.destination || context.destination.platform !== dispatch2.destination.platform || context.destination.teamId !== dispatch2.destination.teamId || context.destination.channelId !== dispatch2.destination.channelId) {
|
|
1024
682
|
throw new Error(
|
|
1025
683
|
`Dispatch ${dispatch2.id} destination does not match its conversation lease`
|
|
1026
684
|
);
|
|
@@ -1159,6 +817,10 @@ function heartbeatIdempotencyKey(reason, conversationId, nowMs) {
|
|
|
1159
817
|
return `heartbeat:${reason}:${conversationId}:${nowMs}`;
|
|
1160
818
|
}
|
|
1161
819
|
async function recoverConversationWork(args) {
|
|
820
|
+
if (!getChatConfig().conversationWorkEnabled) {
|
|
821
|
+
logWarn("conversation.work.recovery.disabled");
|
|
822
|
+
return { expiredLeaseCount: 0, pendingCount: 0 };
|
|
823
|
+
}
|
|
1162
824
|
const result = {
|
|
1163
825
|
expiredLeaseCount: 0,
|
|
1164
826
|
pendingCount: 0
|
|
@@ -1203,12 +865,24 @@ async function recoverConversationWork(args) {
|
|
|
1203
865
|
return;
|
|
1204
866
|
}
|
|
1205
867
|
if (work.execution.lease && work.execution.lease.expiresAtMs <= args.nowMs) {
|
|
1206
|
-
const
|
|
868
|
+
const recovery = await clearExpiredConversationLease({
|
|
1207
869
|
conversationId,
|
|
1208
870
|
nowMs: args.nowMs,
|
|
1209
871
|
state: args.state
|
|
1210
872
|
});
|
|
1211
|
-
if (
|
|
873
|
+
if (recovery === "not_expired") {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
if (recovery === "stopped") {
|
|
877
|
+
logException(
|
|
878
|
+
new Error("Conversation work stopped after repeated failed attempts"),
|
|
879
|
+
"conversation.work.retry.exhausted",
|
|
880
|
+
{
|
|
881
|
+
"app.run.id": work.execution.runId ?? "unknown",
|
|
882
|
+
"app.worker.last_progress_at_ms": work.execution.lastProgressAtMs ?? work.createdAtMs,
|
|
883
|
+
"app.worker.retry_count": (work.execution.retryCount ?? 0) + 1
|
|
884
|
+
}
|
|
885
|
+
);
|
|
1212
886
|
return;
|
|
1213
887
|
}
|
|
1214
888
|
const wake2 = await ensureConversationWake({
|
|
@@ -1263,7 +937,7 @@ import {
|
|
|
1263
937
|
// src/chat/agent-dispatch/validation.ts
|
|
1264
938
|
import {
|
|
1265
939
|
dispatchOptionsSchema,
|
|
1266
|
-
isSlackDestination
|
|
940
|
+
isSlackDestination
|
|
1267
941
|
} from "@sentry/junior-plugin-api";
|
|
1268
942
|
function hasIssueAtPath(issues, path) {
|
|
1269
943
|
return issues.some(
|
|
@@ -1360,7 +1034,7 @@ function validateDispatchOptions(options) {
|
|
|
1360
1034
|
}
|
|
1361
1035
|
const candidate = parsed.data;
|
|
1362
1036
|
const { credentialSubject, destination } = candidate;
|
|
1363
|
-
if (!
|
|
1037
|
+
if (!isSlackDestination(destination)) {
|
|
1364
1038
|
throw new Error("Dispatch destination platform must be slack");
|
|
1365
1039
|
}
|
|
1366
1040
|
if (credentialSubject !== void 0) {
|
|
@@ -1585,6 +1259,15 @@ function shouldSkipRun(task, run) {
|
|
|
1585
1259
|
}
|
|
1586
1260
|
return void 0;
|
|
1587
1261
|
}
|
|
1262
|
+
async function recordScheduledExecution(args) {
|
|
1263
|
+
const dispatchId = args.run.dispatchId;
|
|
1264
|
+
await recordTaskExecution("scheduled", args.run.taskId, {
|
|
1265
|
+
...dispatchId ? { conversationId: getDispatchConversationId({ id: dispatchId }) } : {},
|
|
1266
|
+
executionId: args.run.id,
|
|
1267
|
+
nowMs: args.nowMs,
|
|
1268
|
+
status: args.status
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1588
1271
|
async function applyDispatchResult(args) {
|
|
1589
1272
|
if (args.dispatch.status === "completed") {
|
|
1590
1273
|
const completed = await args.store.markRunCompleted({
|
|
@@ -1599,14 +1282,11 @@ async function applyDispatchResult(args) {
|
|
|
1599
1282
|
run: args.run,
|
|
1600
1283
|
status: "completed"
|
|
1601
1284
|
});
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
nowMs: args.nowMs
|
|
1608
|
-
});
|
|
1609
|
-
}
|
|
1285
|
+
await recordScheduledExecution({
|
|
1286
|
+
nowMs: args.nowMs,
|
|
1287
|
+
run: args.run,
|
|
1288
|
+
status: "completed"
|
|
1289
|
+
});
|
|
1610
1290
|
return true;
|
|
1611
1291
|
}
|
|
1612
1292
|
if (args.dispatch.status === "blocked") {
|
|
@@ -1623,6 +1303,11 @@ async function applyDispatchResult(args) {
|
|
|
1623
1303
|
run: args.run,
|
|
1624
1304
|
status: "blocked"
|
|
1625
1305
|
});
|
|
1306
|
+
await recordScheduledExecution({
|
|
1307
|
+
nowMs: args.nowMs,
|
|
1308
|
+
run: args.run,
|
|
1309
|
+
status: "blocked"
|
|
1310
|
+
});
|
|
1626
1311
|
return true;
|
|
1627
1312
|
}
|
|
1628
1313
|
if (args.dispatch.status === "failed") {
|
|
@@ -1639,6 +1324,11 @@ async function applyDispatchResult(args) {
|
|
|
1639
1324
|
run: args.run,
|
|
1640
1325
|
status: "failed"
|
|
1641
1326
|
});
|
|
1327
|
+
await recordScheduledExecution({
|
|
1328
|
+
nowMs: args.nowMs,
|
|
1329
|
+
run: args.run,
|
|
1330
|
+
status: "failed"
|
|
1331
|
+
});
|
|
1642
1332
|
return true;
|
|
1643
1333
|
}
|
|
1644
1334
|
return false;
|
|
@@ -1661,6 +1351,11 @@ async function finishClaimedRun(args) {
|
|
|
1661
1351
|
run: args.run,
|
|
1662
1352
|
status: args.status
|
|
1663
1353
|
});
|
|
1354
|
+
await recordScheduledExecution({
|
|
1355
|
+
nowMs: args.nowMs,
|
|
1356
|
+
run: args.run,
|
|
1357
|
+
status: args.status
|
|
1358
|
+
});
|
|
1664
1359
|
}
|
|
1665
1360
|
async function runScheduledTaskHeartbeat(args) {
|
|
1666
1361
|
const store = createSchedulerSqlStore(getDb());
|
|
@@ -1765,6 +1460,7 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1765
1460
|
var DEFAULT_PLUGIN_LIMIT = 25;
|
|
1766
1461
|
var PLUGIN_HEARTBEAT_TIMEOUT_MS = 25e3;
|
|
1767
1462
|
var DISPATCH_MAILBOX_APPEND_LIMIT = 100;
|
|
1463
|
+
var AGENT_INVOCATION_MAILBOX_APPEND_LIMIT = 100;
|
|
1768
1464
|
async function runWithTimeout(promise, timeoutMs) {
|
|
1769
1465
|
let timeout;
|
|
1770
1466
|
try {
|
|
@@ -1851,6 +1547,23 @@ async function recoverPendingDispatchMailboxAppends(args) {
|
|
|
1851
1547
|
}
|
|
1852
1548
|
}
|
|
1853
1549
|
}
|
|
1550
|
+
async function recoverPendingAgentInvocationMailboxAppends(args) {
|
|
1551
|
+
const invocations = await listPendingAgentInvocationMailboxAppends(
|
|
1552
|
+
AGENT_INVOCATION_MAILBOX_APPEND_LIMIT
|
|
1553
|
+
);
|
|
1554
|
+
for (const invocation of invocations) {
|
|
1555
|
+
try {
|
|
1556
|
+
await enqueueAgentInvocation(invocation, {
|
|
1557
|
+
nowMs: args.nowMs,
|
|
1558
|
+
queue: args.conversationWorkQueue
|
|
1559
|
+
});
|
|
1560
|
+
} catch (error) {
|
|
1561
|
+
logException(error, "agent.invocation.mailbox.append_recovery.failed", {
|
|
1562
|
+
"app.agent.invocation_id": invocation.invocationId
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1854
1567
|
async function runHeartbeat(args) {
|
|
1855
1568
|
const queue = args.conversationWorkQueue ?? getVercelConversationWorkQueue();
|
|
1856
1569
|
await recoverConversationWork({
|
|
@@ -1861,6 +1574,10 @@ async function runHeartbeat(args) {
|
|
|
1861
1574
|
conversationWorkQueue: queue,
|
|
1862
1575
|
nowMs: args.nowMs
|
|
1863
1576
|
});
|
|
1577
|
+
await recoverPendingAgentInvocationMailboxAppends({
|
|
1578
|
+
conversationWorkQueue: queue,
|
|
1579
|
+
nowMs: args.nowMs
|
|
1580
|
+
});
|
|
1864
1581
|
try {
|
|
1865
1582
|
const dispatchCount = await runScheduledTaskHeartbeat({
|
|
1866
1583
|
conversationWorkQueue: queue,
|
|
@@ -1919,7 +1636,7 @@ async function GET4(request, waitUntil, options = {}) {
|
|
|
1919
1636
|
import { timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
1920
1637
|
|
|
1921
1638
|
// src/chat/conversations/sql/purge.ts
|
|
1922
|
-
import { and, asc, eq as eq2, inArray, isNull, sql } from "drizzle-orm";
|
|
1639
|
+
import { and, asc, eq as eq2, inArray, isNull, or, sql } from "drizzle-orm";
|
|
1923
1640
|
|
|
1924
1641
|
// src/chat/conversations/sql/privacy.ts
|
|
1925
1642
|
import { eq } from "drizzle-orm";
|
|
@@ -2010,6 +1727,16 @@ async function selectExpiredRoots(executor, args) {
|
|
|
2010
1727
|
select 1 from junior_conversation_events events
|
|
2011
1728
|
where events.conversation_id = tree.conversation_id
|
|
2012
1729
|
)
|
|
1730
|
+
or exists (
|
|
1731
|
+
select 1 from junior_agent_invocations invocations
|
|
1732
|
+
where invocations.parent_conversation_id = tree.conversation_id
|
|
1733
|
+
or invocations.child_conversation_id = tree.conversation_id
|
|
1734
|
+
)
|
|
1735
|
+
or exists (
|
|
1736
|
+
select 1 from junior_agent_bindings bindings
|
|
1737
|
+
where bindings.parent_conversation_id = tree.conversation_id
|
|
1738
|
+
or bindings.child_conversation_id = tree.conversation_id
|
|
1739
|
+
)
|
|
2013
1740
|
or (
|
|
2014
1741
|
${juniorDestinations.visibility} is distinct from 'public'
|
|
2015
1742
|
and exists (
|
|
@@ -2045,69 +1772,85 @@ async function selectExpiredRoots(executor, args) {
|
|
|
2045
1772
|
}));
|
|
2046
1773
|
}
|
|
2047
1774
|
async function purgeConversationTree(executor, args) {
|
|
2048
|
-
return await
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
}).from(juniorConversations).where(
|
|
2074
|
-
eq2(juniorConversations.conversationId, args.rootConversationId)
|
|
2075
|
-
).for("update");
|
|
2076
|
-
const root = roots[0];
|
|
2077
|
-
if (!root || args.retention && root.parentConversationId !== null) {
|
|
2078
|
-
return { purged: false, conversations: 0 };
|
|
2079
|
-
}
|
|
2080
|
-
const resolvedScrubMetadata = args.scrubMetadataFromRootVisibility ? (await resolveRootVisibility(executor, args.rootConversationId)).visibility !== "public" : args.scrubMetadata;
|
|
2081
|
-
const destinations = root.destinationId ? await executor.db().select({ visibility: juniorDestinations.visibility }).from(juniorDestinations).where(eq2(juniorDestinations.id, root.destinationId)).for("share") : [];
|
|
2082
|
-
const isPublic = destinations[0]?.visibility === "public";
|
|
2083
|
-
const ids = tree.map((conversation) => conversation.conversationId);
|
|
2084
|
-
if (args.retention) {
|
|
2085
|
-
const currentActivity = await executor.db().select({
|
|
1775
|
+
return await withConversationMutationLock(
|
|
1776
|
+
executor,
|
|
1777
|
+
args.rootConversationId,
|
|
1778
|
+
async () => {
|
|
1779
|
+
const initialRoots = await executor.db().select({
|
|
1780
|
+
conversationId: juniorConversations.conversationId,
|
|
1781
|
+
parentConversationId: juniorConversations.parentConversationId
|
|
1782
|
+
}).from(juniorConversations).where(eq2(juniorConversations.conversationId, args.rootConversationId));
|
|
1783
|
+
const initialRoot = initialRoots[0];
|
|
1784
|
+
if (!initialRoot || args.retention && initialRoot.parentConversationId !== null) {
|
|
1785
|
+
return { purged: false, conversations: 0 };
|
|
1786
|
+
}
|
|
1787
|
+
const tree = await discoverConversationTree(executor, initialRoot);
|
|
1788
|
+
return await withConversationEventLock(
|
|
1789
|
+
executor,
|
|
1790
|
+
args.rootConversationId,
|
|
1791
|
+
async () => {
|
|
1792
|
+
for (const conversation of tree.slice(1)) {
|
|
1793
|
+
await withConversationEventLock(
|
|
1794
|
+
executor,
|
|
1795
|
+
conversation.conversationId,
|
|
1796
|
+
async () => void 0
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1799
|
+
const roots = await executor.db().select({
|
|
2086
1800
|
conversationId: juniorConversations.conversationId,
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
1801
|
+
destinationId: juniorConversations.destinationId,
|
|
1802
|
+
parentConversationId: juniorConversations.parentConversationId
|
|
1803
|
+
}).from(juniorConversations).where(
|
|
1804
|
+
eq2(juniorConversations.conversationId, args.rootConversationId)
|
|
1805
|
+
).for("update");
|
|
1806
|
+
const root = roots[0];
|
|
1807
|
+
if (!root || args.retention && root.parentConversationId !== null) {
|
|
2090
1808
|
return { purged: false, conversations: 0 };
|
|
2091
1809
|
}
|
|
2092
|
-
const
|
|
2093
|
-
const
|
|
2094
|
-
|
|
2095
|
-
|
|
1810
|
+
const resolvedScrubMetadata = args.scrubMetadataFromRootVisibility ? (await resolveRootVisibility(executor, args.rootConversationId)).visibility !== "public" : args.scrubMetadata;
|
|
1811
|
+
const destinations = root.destinationId ? await executor.db().select({ visibility: juniorDestinations.visibility }).from(juniorDestinations).where(eq2(juniorDestinations.id, root.destinationId)).for("share") : [];
|
|
1812
|
+
const isPublic = destinations[0]?.visibility === "public";
|
|
1813
|
+
const ids = tree.map((conversation) => conversation.conversationId);
|
|
1814
|
+
if (args.retention) {
|
|
1815
|
+
const currentActivity = await executor.db().select({
|
|
1816
|
+
conversationId: juniorConversations.conversationId,
|
|
1817
|
+
lastActivityAt: juniorConversations.lastActivityAt
|
|
1818
|
+
}).from(juniorConversations).where(inArray(juniorConversations.conversationId, ids));
|
|
1819
|
+
if (currentActivity.length !== ids.length) {
|
|
1820
|
+
return { purged: false, conversations: 0 };
|
|
1821
|
+
}
|
|
1822
|
+
const windowMs = isPublic ? args.retention.publicWindowMs : args.retention.privateWindowMs;
|
|
1823
|
+
const effectiveLastActivityAt = Math.max(
|
|
1824
|
+
...currentActivity.map(
|
|
1825
|
+
(conversation) => conversation.lastActivityAt.getTime()
|
|
1826
|
+
)
|
|
1827
|
+
);
|
|
1828
|
+
if (effectiveLastActivityAt >= args.nowMs - windowMs) {
|
|
1829
|
+
return { purged: false, conversations: 0 };
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
await executor.db().delete(juniorConversationEvents).where(inArray(juniorConversationEvents.conversationId, ids));
|
|
1833
|
+
await executor.db().delete(juniorAgentInvocations).where(
|
|
1834
|
+
or(
|
|
1835
|
+
inArray(juniorAgentInvocations.parentConversationId, ids),
|
|
1836
|
+
inArray(juniorAgentInvocations.childConversationId, ids)
|
|
2096
1837
|
)
|
|
2097
1838
|
);
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
1839
|
+
await executor.db().delete(juniorAgentBindings).where(
|
|
1840
|
+
or(
|
|
1841
|
+
inArray(juniorAgentBindings.parentConversationId, ids),
|
|
1842
|
+
inArray(juniorAgentBindings.childConversationId, ids)
|
|
1843
|
+
)
|
|
1844
|
+
);
|
|
1845
|
+
await executor.db().update(juniorConversations).set({
|
|
1846
|
+
transcriptPurgedAt: new Date(args.nowMs),
|
|
1847
|
+
...(args.retention ? !isPublic : resolvedScrubMetadata) ? { title: null, channelName: null, actor: null } : {}
|
|
1848
|
+
}).where(inArray(juniorConversations.conversationId, ids));
|
|
1849
|
+
return { purged: true, conversations: ids.length };
|
|
2101
1850
|
}
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
...(args.retention ? !isPublic : resolvedScrubMetadata) ? { title: null, channelName: null, actor: null } : {}
|
|
2106
|
-
}).where(inArray(juniorConversations.conversationId, ids));
|
|
2107
|
-
return { purged: true, conversations: ids.length };
|
|
2108
|
-
}
|
|
2109
|
-
);
|
|
2110
|
-
});
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1853
|
+
);
|
|
2111
1854
|
}
|
|
2112
1855
|
|
|
2113
1856
|
// src/chat/conversations/retention.ts
|
|
@@ -2219,9 +1962,9 @@ function buildJwksUrl(value) {
|
|
|
2219
1962
|
return url;
|
|
2220
1963
|
}
|
|
2221
1964
|
async function getJwks(issuer) {
|
|
2222
|
-
const
|
|
1965
|
+
const now = Date.now();
|
|
2223
1966
|
const cached = jwksByIssuer.get(issuer);
|
|
2224
|
-
if (cached && cached.expiresAtMs >
|
|
1967
|
+
if (cached && cached.expiresAtMs > now) {
|
|
2225
1968
|
return cached.jwks;
|
|
2226
1969
|
}
|
|
2227
1970
|
if (cached) {
|
|
@@ -2246,7 +1989,7 @@ async function getJwks(issuer) {
|
|
|
2246
1989
|
}
|
|
2247
1990
|
jwksByIssuer.set(issuer, {
|
|
2248
1991
|
jwks,
|
|
2249
|
-
expiresAtMs:
|
|
1992
|
+
expiresAtMs: now + OIDC_DISCOVERY_CACHE_TTL_MS
|
|
2250
1993
|
});
|
|
2251
1994
|
return jwks;
|
|
2252
1995
|
}
|
|
@@ -2572,7 +2315,7 @@ import {
|
|
|
2572
2315
|
Message,
|
|
2573
2316
|
ThreadImpl
|
|
2574
2317
|
} from "chat";
|
|
2575
|
-
import { z as
|
|
2318
|
+
import { z as z4 } from "zod";
|
|
2576
2319
|
|
|
2577
2320
|
// src/chat/ingress/message-router.ts
|
|
2578
2321
|
function normalizeIncomingSlackThreadId(threadId, message) {
|
|
@@ -2743,14 +2486,14 @@ async function ensureSlackMessageActorIdentity(message, teamId, lookupSlackUser2
|
|
|
2743
2486
|
}
|
|
2744
2487
|
|
|
2745
2488
|
// src/chat/slack/user.ts
|
|
2746
|
-
import { z as
|
|
2747
|
-
var slackUserInfoSchema =
|
|
2748
|
-
ok:
|
|
2749
|
-
user:
|
|
2750
|
-
name:
|
|
2751
|
-
profile:
|
|
2752
|
-
email:
|
|
2753
|
-
real_name:
|
|
2489
|
+
import { z as z3 } from "zod";
|
|
2490
|
+
var slackUserInfoSchema = z3.object({
|
|
2491
|
+
ok: z3.literal(true),
|
|
2492
|
+
user: z3.object({
|
|
2493
|
+
name: z3.string().nullish(),
|
|
2494
|
+
profile: z3.object({
|
|
2495
|
+
email: z3.string().nullish(),
|
|
2496
|
+
real_name: z3.string().nullish()
|
|
2754
2497
|
}).optional()
|
|
2755
2498
|
})
|
|
2756
2499
|
});
|
|
@@ -2827,6 +2570,20 @@ async function lookupSlackUser(teamId, userId) {
|
|
|
2827
2570
|
}
|
|
2828
2571
|
}
|
|
2829
2572
|
|
|
2573
|
+
// src/chat/resource-events/actor.ts
|
|
2574
|
+
var RESOURCE_EVENT_SLACK_AUTHOR_ID = "UJRNEVENT";
|
|
2575
|
+
var RESOURCE_EVENT_SYSTEM_ACTOR = {
|
|
2576
|
+
platform: "system",
|
|
2577
|
+
name: "resource-event"
|
|
2578
|
+
};
|
|
2579
|
+
function isResourceEventConversationMessage(message) {
|
|
2580
|
+
return Boolean(message.meta?.eventType) || message.author?.userId === RESOURCE_EVENT_SLACK_AUTHOR_ID;
|
|
2581
|
+
}
|
|
2582
|
+
function isResourceEventSlackMessage(message) {
|
|
2583
|
+
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
2584
|
+
return raw?.event_type === "resource_event";
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2830
2587
|
// src/chat/slack/message-control.ts
|
|
2831
2588
|
var LEADING_MENTION_BEFORE_STEERING_RE = /^(\s*(?:<@[^>]+>|@[A-Za-z0-9._-]+\b)[\s,:-]*)!!\s*/;
|
|
2832
2589
|
function stripLeadingSteeringOverride(text) {
|
|
@@ -2834,17 +2591,17 @@ function stripLeadingSteeringOverride(text) {
|
|
|
2834
2591
|
}
|
|
2835
2592
|
|
|
2836
2593
|
// src/chat/task-execution/slack-work.ts
|
|
2837
|
-
var slackConversationRouteSchema =
|
|
2594
|
+
var slackConversationRouteSchema = z4.enum(["mention", "subscribed"]);
|
|
2838
2595
|
function hasSteeringOverride(text) {
|
|
2839
2596
|
return stripLeadingSteeringOverride(text) !== text;
|
|
2840
2597
|
}
|
|
2841
|
-
var serializedDateSchema =
|
|
2842
|
-
var mdastPointSchema =
|
|
2843
|
-
column:
|
|
2844
|
-
line:
|
|
2845
|
-
offset:
|
|
2598
|
+
var serializedDateSchema = z4.iso.datetime();
|
|
2599
|
+
var mdastPointSchema = z4.object({
|
|
2600
|
+
column: z4.number().int().positive(),
|
|
2601
|
+
line: z4.number().int().positive(),
|
|
2602
|
+
offset: z4.number().int().nonnegative().optional()
|
|
2846
2603
|
}).strict();
|
|
2847
|
-
var mdastPositionSchema =
|
|
2604
|
+
var mdastPositionSchema = z4.object({
|
|
2848
2605
|
end: mdastPointSchema,
|
|
2849
2606
|
start: mdastPointSchema
|
|
2850
2607
|
}).strict();
|
|
@@ -2956,7 +2713,7 @@ function isFormattedContentNode(value) {
|
|
|
2956
2713
|
return false;
|
|
2957
2714
|
}
|
|
2958
2715
|
}
|
|
2959
|
-
var formattedContentSchema =
|
|
2716
|
+
var formattedContentSchema = z4.custom(
|
|
2960
2717
|
(value) => {
|
|
2961
2718
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
2962
2719
|
return false;
|
|
@@ -2966,79 +2723,79 @@ var formattedContentSchema = z5.custom(
|
|
|
2966
2723
|
},
|
|
2967
2724
|
"must be a valid formatted-content root"
|
|
2968
2725
|
);
|
|
2969
|
-
var serializedMessageSchema =
|
|
2970
|
-
_type:
|
|
2971
|
-
attachments:
|
|
2972
|
-
|
|
2973
|
-
type:
|
|
2974
|
-
url:
|
|
2975
|
-
name:
|
|
2976
|
-
mimeType:
|
|
2977
|
-
size:
|
|
2978
|
-
width:
|
|
2979
|
-
height:
|
|
2980
|
-
fetchMetadata:
|
|
2726
|
+
var serializedMessageSchema = z4.object({
|
|
2727
|
+
_type: z4.literal("chat:Message"),
|
|
2728
|
+
attachments: z4.array(
|
|
2729
|
+
z4.object({
|
|
2730
|
+
type: z4.enum(["image", "file", "video", "audio"]),
|
|
2731
|
+
url: z4.string().optional(),
|
|
2732
|
+
name: z4.string().optional(),
|
|
2733
|
+
mimeType: z4.string().optional(),
|
|
2734
|
+
size: z4.number().finite().optional(),
|
|
2735
|
+
width: z4.number().finite().optional(),
|
|
2736
|
+
height: z4.number().finite().optional(),
|
|
2737
|
+
fetchMetadata: z4.record(z4.string(), z4.string()).optional()
|
|
2981
2738
|
}).strict()
|
|
2982
2739
|
),
|
|
2983
|
-
author:
|
|
2984
|
-
userId:
|
|
2985
|
-
userName:
|
|
2986
|
-
fullName:
|
|
2987
|
-
isBot:
|
|
2988
|
-
isMe:
|
|
2740
|
+
author: z4.object({
|
|
2741
|
+
userId: z4.string(),
|
|
2742
|
+
userName: z4.string(),
|
|
2743
|
+
fullName: z4.string(),
|
|
2744
|
+
isBot: z4.union([z4.boolean(), z4.literal("unknown")]),
|
|
2745
|
+
isMe: z4.boolean()
|
|
2989
2746
|
}).strict(),
|
|
2990
2747
|
formatted: formattedContentSchema,
|
|
2991
|
-
id:
|
|
2992
|
-
isMention:
|
|
2993
|
-
links:
|
|
2994
|
-
|
|
2995
|
-
url:
|
|
2996
|
-
title:
|
|
2997
|
-
description:
|
|
2998
|
-
imageUrl:
|
|
2999
|
-
siteName:
|
|
2748
|
+
id: z4.string().min(1),
|
|
2749
|
+
isMention: z4.boolean().optional(),
|
|
2750
|
+
links: z4.array(
|
|
2751
|
+
z4.object({
|
|
2752
|
+
url: z4.string(),
|
|
2753
|
+
title: z4.string().optional(),
|
|
2754
|
+
description: z4.string().optional(),
|
|
2755
|
+
imageUrl: z4.string().optional(),
|
|
2756
|
+
siteName: z4.string().optional()
|
|
3000
2757
|
}).strict()
|
|
3001
2758
|
).optional(),
|
|
3002
|
-
metadata:
|
|
2759
|
+
metadata: z4.object({
|
|
3003
2760
|
dateSent: serializedDateSchema,
|
|
3004
|
-
edited:
|
|
2761
|
+
edited: z4.boolean(),
|
|
3005
2762
|
editedAt: serializedDateSchema.optional()
|
|
3006
2763
|
}).strict(),
|
|
3007
|
-
raw:
|
|
3008
|
-
text:
|
|
3009
|
-
threadId:
|
|
2764
|
+
raw: z4.unknown(),
|
|
2765
|
+
text: z4.string(),
|
|
2766
|
+
threadId: z4.string().min(1)
|
|
3010
2767
|
}).strict();
|
|
3011
|
-
var serializedThreadSchema =
|
|
3012
|
-
_type:
|
|
3013
|
-
adapterName:
|
|
3014
|
-
channelId:
|
|
3015
|
-
channelVisibility:
|
|
2768
|
+
var serializedThreadSchema = z4.object({
|
|
2769
|
+
_type: z4.literal("chat:Thread"),
|
|
2770
|
+
adapterName: z4.literal("slack"),
|
|
2771
|
+
channelId: z4.string().min(1),
|
|
2772
|
+
channelVisibility: z4.enum(["private", "workspace", "external", "unknown"]).optional(),
|
|
3016
2773
|
currentMessage: serializedMessageSchema.optional(),
|
|
3017
|
-
id:
|
|
3018
|
-
isDM:
|
|
2774
|
+
id: z4.string().min(1),
|
|
2775
|
+
isDM: z4.boolean()
|
|
3019
2776
|
}).strict();
|
|
3020
|
-
var slackInstallationSchema =
|
|
3021
|
-
enterpriseId:
|
|
3022
|
-
isEnterpriseInstall:
|
|
3023
|
-
teamId:
|
|
2777
|
+
var slackInstallationSchema = z4.object({
|
|
2778
|
+
enterpriseId: z4.string().optional(),
|
|
2779
|
+
isEnterpriseInstall: z4.boolean().optional(),
|
|
2780
|
+
teamId: z4.string().optional()
|
|
3024
2781
|
}).strict();
|
|
3025
|
-
var slackConversationMessageMetadataBaseSchema =
|
|
2782
|
+
var slackConversationMessageMetadataBaseSchema = z4.object({
|
|
3026
2783
|
installation: slackInstallationSchema.optional(),
|
|
3027
2784
|
message: serializedMessageSchema,
|
|
3028
|
-
platform:
|
|
2785
|
+
platform: z4.literal("slack"),
|
|
3029
2786
|
route: slackConversationRouteSchema,
|
|
3030
2787
|
thread: serializedThreadSchema
|
|
3031
2788
|
});
|
|
3032
|
-
var slackConversationMessageMetadataSchema =
|
|
2789
|
+
var slackConversationMessageMetadataSchema = z4.union([
|
|
3033
2790
|
slackConversationMessageMetadataBaseSchema.strict(),
|
|
3034
2791
|
slackConversationMessageMetadataBaseSchema.extend({
|
|
3035
|
-
kind:
|
|
3036
|
-
resourceEvent:
|
|
3037
|
-
eventKey:
|
|
3038
|
-
eventType:
|
|
3039
|
-
namespace:
|
|
3040
|
-
identifier:
|
|
3041
|
-
subscriptionId:
|
|
2792
|
+
kind: z4.literal("resource_event"),
|
|
2793
|
+
resourceEvent: z4.object({
|
|
2794
|
+
eventKey: z4.string(),
|
|
2795
|
+
eventType: z4.string(),
|
|
2796
|
+
namespace: z4.string(),
|
|
2797
|
+
identifier: z4.string(),
|
|
2798
|
+
subscriptionId: z4.string()
|
|
3042
2799
|
}).strict()
|
|
3043
2800
|
}).strict()
|
|
3044
2801
|
]);
|
|
@@ -3071,7 +2828,7 @@ function slackSerializedResourceEventMessage(input) {
|
|
|
3071
2828
|
_type: "chat:Message",
|
|
3072
2829
|
attachments: [],
|
|
3073
2830
|
author: {
|
|
3074
|
-
userId:
|
|
2831
|
+
userId: RESOURCE_EVENT_SLACK_AUTHOR_ID,
|
|
3075
2832
|
userName: "junior-event",
|
|
3076
2833
|
fullName: "Junior event",
|
|
3077
2834
|
isBot: true,
|
|
@@ -3089,7 +2846,7 @@ function slackSerializedResourceEventMessage(input) {
|
|
|
3089
2846
|
resource_event_type: input.eventType,
|
|
3090
2847
|
thread_ts: input.threadTs,
|
|
3091
2848
|
type: "message",
|
|
3092
|
-
user:
|
|
2849
|
+
user: RESOURCE_EVENT_SLACK_AUTHOR_ID
|
|
3093
2850
|
},
|
|
3094
2851
|
text: input.text,
|
|
3095
2852
|
threadId: `slack:${input.channelId}:${input.threadTs}`
|
|
@@ -3133,7 +2890,7 @@ function createSlackResourceEventInboundMessage(input) {
|
|
|
3133
2890
|
receivedAtMs: Date.now(),
|
|
3134
2891
|
input: {
|
|
3135
2892
|
text: input.text,
|
|
3136
|
-
authorId:
|
|
2893
|
+
authorId: RESOURCE_EVENT_SLACK_AUTHOR_ID,
|
|
3137
2894
|
metadata: {
|
|
3138
2895
|
kind: "resource_event",
|
|
3139
2896
|
installation: {
|
|
@@ -3173,10 +2930,6 @@ function routeForRecords(records) {
|
|
|
3173
2930
|
return metadata.route === "mention";
|
|
3174
2931
|
}) ? "mention" : "subscribed";
|
|
3175
2932
|
}
|
|
3176
|
-
function isResourceEventNotificationMessage(message) {
|
|
3177
|
-
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
3178
|
-
return raw?.event_type === "resource_event";
|
|
3179
|
-
}
|
|
3180
2933
|
function restoreMessage(args) {
|
|
3181
2934
|
const metadata = parseSlackMetadata(args.record.input.metadata);
|
|
3182
2935
|
if (!metadata) {
|
|
@@ -3192,7 +2945,7 @@ function restoreMessage(args) {
|
|
|
3192
2945
|
async function bindSlackActorIdentities(args) {
|
|
3193
2946
|
const byAuthorId = /* @__PURE__ */ new Map();
|
|
3194
2947
|
for (const message of args.messages) {
|
|
3195
|
-
if (
|
|
2948
|
+
if (isResourceEventSlackMessage(message)) {
|
|
3196
2949
|
continue;
|
|
3197
2950
|
}
|
|
3198
2951
|
const authorId = requireSlackAuthorId(message);
|
|
@@ -3352,7 +3105,7 @@ function createSlackConversationWorker(options) {
|
|
|
3352
3105
|
if (route === "mention") {
|
|
3353
3106
|
await options.runtime.handleNewMention(thread, latestMessage, {
|
|
3354
3107
|
conversationId: context.conversationId,
|
|
3355
|
-
destination
|
|
3108
|
+
destination,
|
|
3356
3109
|
messageContext,
|
|
3357
3110
|
drainSteeringMessages,
|
|
3358
3111
|
ack,
|
|
@@ -3365,7 +3118,7 @@ function createSlackConversationWorker(options) {
|
|
|
3365
3118
|
latestMessage,
|
|
3366
3119
|
{
|
|
3367
3120
|
conversationId: context.conversationId,
|
|
3368
|
-
destination
|
|
3121
|
+
destination,
|
|
3369
3122
|
messageContext,
|
|
3370
3123
|
drainSteeringMessages,
|
|
3371
3124
|
ack,
|
|
@@ -4143,663 +3896,114 @@ async function handleSlackWebhook(args) {
|
|
|
4143
3896
|
if (shouldPersistBeforeAck(parsed)) {
|
|
4144
3897
|
const failureResponse = await withLogContext(
|
|
4145
3898
|
eventLogContext,
|
|
4146
|
-
async () => {
|
|
4147
|
-
try {
|
|
4148
|
-
await handleSlackEvent({
|
|
4149
|
-
body: parsed,
|
|
4150
|
-
services: args.services
|
|
4151
|
-
});
|
|
4152
|
-
} catch (error) {
|
|
4153
|
-
if (error instanceof SlackEventPersistenceError) {
|
|
4154
|
-
logException(error.cause, "slack.event.persist.failed");
|
|
4155
|
-
} else {
|
|
4156
|
-
logException(error, "slack.event.routing.failed");
|
|
4157
|
-
}
|
|
4158
|
-
return new Response("Slack event handling failed", { status: 503 });
|
|
4159
|
-
}
|
|
4160
|
-
return void 0;
|
|
4161
|
-
}
|
|
4162
|
-
);
|
|
4163
|
-
if (failureResponse) {
|
|
4164
|
-
return failureResponse;
|
|
4165
|
-
}
|
|
4166
|
-
} else {
|
|
4167
|
-
enqueue(
|
|
4168
|
-
args.waitUntil,
|
|
4169
|
-
withLogContext(
|
|
4170
|
-
eventLogContext,
|
|
4171
|
-
() => handleSlackEvent({
|
|
4172
|
-
body: parsed,
|
|
4173
|
-
services: args.services
|
|
4174
|
-
}).catch((error) => {
|
|
4175
|
-
logException(error, "slack.event.enqueue.failed");
|
|
4176
|
-
})
|
|
4177
|
-
)
|
|
4178
|
-
);
|
|
4179
|
-
}
|
|
4180
|
-
}
|
|
4181
|
-
return new Response("ok", { status: 200 });
|
|
4182
|
-
}
|
|
4183
|
-
|
|
4184
|
-
// src/handlers/webhooks.ts
|
|
4185
|
-
async function handleWebhookRequest(request, platform, run) {
|
|
4186
|
-
const requestContext = createRequestContext(request, { platform });
|
|
4187
|
-
const requestUrl = new URL(request.url);
|
|
4188
|
-
return await withContext(requestContext, async () => {
|
|
4189
|
-
try {
|
|
4190
|
-
return await withSpan(
|
|
4191
|
-
"http.server.request",
|
|
4192
|
-
"http.server",
|
|
4193
|
-
requestContext,
|
|
4194
|
-
async () => {
|
|
4195
|
-
try {
|
|
4196
|
-
const response = await run();
|
|
4197
|
-
if (response.status >= 400) {
|
|
4198
|
-
let responseBodySnippet;
|
|
4199
|
-
try {
|
|
4200
|
-
responseBodySnippet = (await response.clone().text()).slice(
|
|
4201
|
-
0,
|
|
4202
|
-
300
|
|
4203
|
-
);
|
|
4204
|
-
} catch {
|
|
4205
|
-
responseBodySnippet = void 0;
|
|
4206
|
-
}
|
|
4207
|
-
logWarn("webhook.response.unsuccessful", {
|
|
4208
|
-
"http.response.status_code": response.status,
|
|
4209
|
-
"http.request.header.x_slack_signature": request.headers.get("x-slack-signature") ?? void 0,
|
|
4210
|
-
"http.request.header.x_slack_request_timestamp": request.headers.get("x-slack-request-timestamp") ?? void 0,
|
|
4211
|
-
...responseBodySnippet ? { "app.webhook.response_body": responseBodySnippet } : {}
|
|
4212
|
-
});
|
|
4213
|
-
}
|
|
4214
|
-
setSpanAttributes({
|
|
4215
|
-
"http.response.status_code": response.status
|
|
4216
|
-
});
|
|
4217
|
-
setSpanStatus(response.status >= 500 ? "error" : "ok");
|
|
4218
|
-
return response;
|
|
4219
|
-
} catch (error) {
|
|
4220
|
-
setSpanStatus("error");
|
|
4221
|
-
throw error;
|
|
4222
|
-
}
|
|
4223
|
-
},
|
|
4224
|
-
{
|
|
4225
|
-
"http.request.method": request.method,
|
|
4226
|
-
"url.path": requestUrl.pathname
|
|
4227
|
-
}
|
|
4228
|
-
);
|
|
4229
|
-
} catch (error) {
|
|
4230
|
-
logException(error, "webhook.handler.failed");
|
|
4231
|
-
throw error;
|
|
4232
|
-
}
|
|
4233
|
-
});
|
|
4234
|
-
}
|
|
4235
|
-
|
|
4236
|
-
// src/handlers/slack-webhook.ts
|
|
4237
|
-
async function POST2(request, waitUntil, services) {
|
|
4238
|
-
return handleWebhookRequest(
|
|
4239
|
-
request,
|
|
4240
|
-
"slack",
|
|
4241
|
-
() => handleSlackWebhook({
|
|
4242
|
-
request,
|
|
4243
|
-
services,
|
|
4244
|
-
waitUntil
|
|
4245
|
-
})
|
|
4246
|
-
);
|
|
4247
|
-
}
|
|
4248
|
-
|
|
4249
|
-
// src/chat/task-execution/vercel-callback.ts
|
|
4250
|
-
import {
|
|
4251
|
-
handleCallback,
|
|
4252
|
-
registerDevConsumer
|
|
4253
|
-
} from "@vercel/queue";
|
|
4254
|
-
|
|
4255
|
-
// src/chat/task-execution/worker.ts
|
|
4256
|
-
var CONVERSATION_WORK_DEFER_DELAY_MS = 15e3;
|
|
4257
|
-
function now(options) {
|
|
4258
|
-
return options.nowMs?.() ?? Date.now();
|
|
4259
|
-
}
|
|
4260
|
-
function selectContiguousActorBatch(messages) {
|
|
4261
|
-
const first = messages[0];
|
|
4262
|
-
if (!first) {
|
|
4263
|
-
return [];
|
|
4264
|
-
}
|
|
4265
|
-
const nextActorIndex = messages.findIndex(
|
|
4266
|
-
(message) => message.input.authorId !== first.input.authorId
|
|
4267
|
-
);
|
|
4268
|
-
return messages.slice(
|
|
4269
|
-
0,
|
|
4270
|
-
nextActorIndex === -1 ? messages.length : nextActorIndex
|
|
4271
|
-
);
|
|
4272
|
-
}
|
|
4273
|
-
function selectAttemptMessages(work) {
|
|
4274
|
-
const messages = work.messages;
|
|
4275
|
-
const interrupts = messages.filter(
|
|
4276
|
-
(message) => message.delivery === "interrupt"
|
|
4277
|
-
);
|
|
4278
|
-
if (interrupts.length > 0) {
|
|
4279
|
-
return selectContiguousActorBatch(interrupts);
|
|
4280
|
-
}
|
|
4281
|
-
return work.execution.status === "awaiting_resume" ? [] : selectContiguousActorBatch(messages);
|
|
4282
|
-
}
|
|
4283
|
-
function nudgeIdempotencyKey(reason, conversationId, nowMs) {
|
|
4284
|
-
return `${reason}:${conversationId}:${nowMs}`;
|
|
4285
|
-
}
|
|
4286
|
-
async function requestLostLeaseRecovery(args) {
|
|
4287
|
-
const resumeRequested = await requestConversationContinuation({
|
|
4288
|
-
conversationId: args.conversationId,
|
|
4289
|
-
destination: args.destination,
|
|
4290
|
-
leaseToken: args.leaseToken,
|
|
4291
|
-
conversationStore: args.options.conversationStore,
|
|
4292
|
-
nowMs: args.nowMs,
|
|
4293
|
-
state: args.options.state
|
|
4294
|
-
});
|
|
4295
|
-
if (!resumeRequested) {
|
|
4296
|
-
return;
|
|
4297
|
-
}
|
|
4298
|
-
const released = await releaseConversationWork({
|
|
4299
|
-
conversationId: args.conversationId,
|
|
4300
|
-
leaseToken: args.leaseToken,
|
|
4301
|
-
conversationStore: args.options.conversationStore,
|
|
4302
|
-
nowMs: args.nowMs,
|
|
4303
|
-
state: args.options.state
|
|
4304
|
-
});
|
|
4305
|
-
if (!released) {
|
|
4306
|
-
return;
|
|
4307
|
-
}
|
|
4308
|
-
await ensureConversationWake({
|
|
4309
|
-
conversationId: args.conversationId,
|
|
4310
|
-
conversationStore: args.options.conversationStore,
|
|
4311
|
-
idempotencyKey: nudgeIdempotencyKey(
|
|
4312
|
-
"lost_lease",
|
|
4313
|
-
args.conversationId,
|
|
4314
|
-
args.nowMs
|
|
4315
|
-
),
|
|
4316
|
-
nowMs: args.nowMs,
|
|
4317
|
-
queue: args.options.queue,
|
|
4318
|
-
replaceExistingWake: true,
|
|
4319
|
-
state: args.options.state
|
|
4320
|
-
});
|
|
4321
|
-
}
|
|
4322
|
-
async function recordFailedDeliveryAttempt(args) {
|
|
4323
|
-
const failure = await recordAttemptFailure({
|
|
4324
|
-
conversationId: args.conversationId,
|
|
4325
|
-
inboundMessageIds: args.messageIds,
|
|
4326
|
-
leaseToken: args.leaseToken,
|
|
4327
|
-
conversationStore: args.options.conversationStore,
|
|
4328
|
-
nowMs: args.nowMs,
|
|
4329
|
-
state: args.options.state
|
|
4330
|
-
});
|
|
4331
|
-
for (const message of failure.deadLetteredMessages) {
|
|
4332
|
-
logWarn("conversation.work.dead_lettered", {
|
|
4333
|
-
"app.conversation.source": message.source,
|
|
4334
|
-
"app.inbound.attempt_count": message.attemptCount ?? 0,
|
|
4335
|
-
"app.inbound.message_id": message.inboundMessageId,
|
|
4336
|
-
"app.inbound.pending_count": failure.pendingCount
|
|
4337
|
-
});
|
|
4338
|
-
}
|
|
4339
|
-
return failure;
|
|
4340
|
-
}
|
|
4341
|
-
function isTerminalFailure(failure) {
|
|
4342
|
-
return failure.status === "recorded" && failure.deadLetteredMessages.length > 0 && failure.pendingCount === 0;
|
|
4343
|
-
}
|
|
4344
|
-
function startLeaseCheckIn(args) {
|
|
4345
|
-
const timer = setInterval(() => {
|
|
4346
|
-
const nowMs = now(args.options);
|
|
4347
|
-
void checkInConversationWork({
|
|
4348
|
-
conversationId: args.conversationId,
|
|
4349
|
-
leaseToken: args.leaseToken,
|
|
4350
|
-
conversationStore: args.options.conversationStore,
|
|
4351
|
-
nowMs,
|
|
4352
|
-
state: args.options.state
|
|
4353
|
-
}).then(
|
|
4354
|
-
(checkedIn) => {
|
|
4355
|
-
if (!checkedIn) {
|
|
4356
|
-
args.onLostLease();
|
|
4357
|
-
logWarn("conversation.work.check_in.failed");
|
|
4358
|
-
}
|
|
4359
|
-
},
|
|
4360
|
-
(error) => {
|
|
4361
|
-
logException(error, "conversation.work.check_in.failed");
|
|
4362
|
-
}
|
|
4363
|
-
);
|
|
4364
|
-
}, args.options.checkInIntervalMs ?? CONVERSATION_WORK_CHECK_IN_INTERVAL_MS);
|
|
4365
|
-
timer.unref?.();
|
|
4366
|
-
return timer;
|
|
4367
|
-
}
|
|
4368
|
-
async function processConversationWork(message, options) {
|
|
4369
|
-
return withLogContext(
|
|
4370
|
-
{ conversationId: message.conversationId },
|
|
4371
|
-
() => processConversationWorkInContext(message, options)
|
|
4372
|
-
);
|
|
4373
|
-
}
|
|
4374
|
-
async function processConversationWorkInContext(message, options) {
|
|
4375
|
-
const conversationId = message.conversationId;
|
|
4376
|
-
let initial;
|
|
4377
|
-
try {
|
|
4378
|
-
initial = await getConversationWorkState({
|
|
4379
|
-
conversationId,
|
|
4380
|
-
state: options.state
|
|
4381
|
-
});
|
|
4382
|
-
} catch (error) {
|
|
4383
|
-
if (isInvalidConversationRecordError(error)) {
|
|
4384
|
-
throw new ConversationQueueMessageRejectedError(
|
|
4385
|
-
"invalid_record",
|
|
4386
|
-
`Conversation record failed validation for ${conversationId}`,
|
|
4387
|
-
{ conversationId }
|
|
4388
|
-
);
|
|
4389
|
-
}
|
|
4390
|
-
throw error;
|
|
4391
|
-
}
|
|
4392
|
-
if (!initial || countPendingConversationMessages(initial) === 0 && initial.execution.status === "idle" && !initial.execution.lease) {
|
|
4393
|
-
if (initial) {
|
|
4394
|
-
await clearConsumedConversationWake({
|
|
4395
|
-
conversationId,
|
|
4396
|
-
conversationStore: options.conversationStore,
|
|
4397
|
-
nowMs: now(options),
|
|
4398
|
-
state: options.state
|
|
4399
|
-
});
|
|
4400
|
-
}
|
|
4401
|
-
return { status: "no_work" };
|
|
4402
|
-
}
|
|
4403
|
-
if (!initial.destination) {
|
|
4404
|
-
throw new ConversationQueueMessageRejectedError(
|
|
4405
|
-
"invalid_record",
|
|
4406
|
-
`Conversation work is missing destination context for ${conversationId}`,
|
|
4407
|
-
{ conversationId }
|
|
4408
|
-
);
|
|
4409
|
-
}
|
|
4410
|
-
const destination = initial.destination;
|
|
4411
|
-
const lease = await startConversationWork({
|
|
4412
|
-
conversationId,
|
|
4413
|
-
conversationStore: options.conversationStore,
|
|
4414
|
-
nowMs: now(options),
|
|
4415
|
-
state: options.state
|
|
4416
|
-
});
|
|
4417
|
-
if (lease.status === "no_work") {
|
|
4418
|
-
await clearConsumedConversationWake({
|
|
4419
|
-
conversationId,
|
|
4420
|
-
conversationStore: options.conversationStore,
|
|
4421
|
-
nowMs: now(options),
|
|
4422
|
-
state: options.state
|
|
4423
|
-
});
|
|
4424
|
-
return { status: "no_work" };
|
|
4425
|
-
}
|
|
4426
|
-
if (lease.status === "active") {
|
|
4427
|
-
const nudgeNowMs = now(options);
|
|
4428
|
-
await ensureConversationWake({
|
|
4429
|
-
conversationId,
|
|
4430
|
-
conversationStore: options.conversationStore,
|
|
4431
|
-
delayMs: CONVERSATION_WORK_DEFER_DELAY_MS,
|
|
4432
|
-
idempotencyKey: nudgeIdempotencyKey("active", conversationId, nudgeNowMs),
|
|
4433
|
-
nowMs: nudgeNowMs,
|
|
4434
|
-
queue: options.queue,
|
|
4435
|
-
replaceExistingWake: true,
|
|
4436
|
-
state: options.state
|
|
4437
|
-
});
|
|
4438
|
-
logInfo("conversation.work.nudge.deferred", {
|
|
4439
|
-
"app.lease.expires_at_ms": lease.leaseExpiresAtMs
|
|
4440
|
-
});
|
|
4441
|
-
return { status: "active" };
|
|
4442
|
-
}
|
|
4443
|
-
const startedAtMs = now(options);
|
|
4444
|
-
const softYieldDeadlineMs = startedAtMs + (options.softYieldAfterMs ?? getChatConfig().conversationWorkSoftYieldAfterMs);
|
|
4445
|
-
let attemptMessageIds = [];
|
|
4446
|
-
let attemptSelectedMessageIds = /* @__PURE__ */ new Set();
|
|
4447
|
-
let attemptStartMessageIds = /* @__PURE__ */ new Set();
|
|
4448
|
-
let leaseLost = false;
|
|
4449
|
-
const markLeaseLost = () => {
|
|
4450
|
-
leaseLost = true;
|
|
4451
|
-
};
|
|
4452
|
-
const timer = startLeaseCheckIn({
|
|
4453
|
-
conversationId,
|
|
4454
|
-
leaseToken: lease.leaseToken,
|
|
4455
|
-
onLostLease: markLeaseLost,
|
|
4456
|
-
options
|
|
4457
|
-
});
|
|
4458
|
-
logInfo("conversation.work.lease.acquired", {
|
|
4459
|
-
"app.lease.expires_at_ms": lease.leaseExpiresAtMs,
|
|
4460
|
-
"app.worker.soft_yield_deadline_ms": softYieldDeadlineMs
|
|
4461
|
-
});
|
|
4462
|
-
const drain = (handle) => drainConversationMailbox({
|
|
4463
|
-
conversationId,
|
|
4464
|
-
leaseToken: lease.leaseToken,
|
|
4465
|
-
conversationStore: options.conversationStore,
|
|
4466
|
-
handle: async (messages) => {
|
|
4467
|
-
const candidates = messages.filter(
|
|
4468
|
-
(message2) => message2.delivery === "interrupt" && (attemptSelectedMessageIds.has(message2.inboundMessageId) || !attemptStartMessageIds.has(message2.inboundMessageId))
|
|
4469
|
-
);
|
|
4470
|
-
if (candidates.length === 0) {
|
|
4471
|
-
return [];
|
|
4472
|
-
}
|
|
4473
|
-
return await handle(candidates) ?? candidates.map((message2) => message2.inboundMessageId);
|
|
4474
|
-
},
|
|
4475
|
-
nowMs: now(options),
|
|
4476
|
-
state: options.state
|
|
4477
|
-
});
|
|
4478
|
-
const shouldYield = () => leaseLost || now(options) >= softYieldDeadlineMs;
|
|
4479
|
-
const checkIn = async () => {
|
|
4480
|
-
const checkedIn = await checkInConversationWork({
|
|
4481
|
-
conversationId,
|
|
4482
|
-
leaseToken: lease.leaseToken,
|
|
4483
|
-
conversationStore: options.conversationStore,
|
|
4484
|
-
nowMs: now(options),
|
|
4485
|
-
state: options.state
|
|
4486
|
-
});
|
|
4487
|
-
if (!checkedIn) {
|
|
4488
|
-
markLeaseLost();
|
|
4489
|
-
}
|
|
4490
|
-
return checkedIn;
|
|
4491
|
-
};
|
|
4492
|
-
const yieldWork = async () => {
|
|
4493
|
-
const yieldNowMs = now(options);
|
|
4494
|
-
await ensureConversationWake({
|
|
4495
|
-
conversationId,
|
|
4496
|
-
conversationStore: options.conversationStore,
|
|
4497
|
-
idempotencyKey: nudgeIdempotencyKey("yield", conversationId, yieldNowMs),
|
|
4498
|
-
nowMs: yieldNowMs,
|
|
4499
|
-
queue: options.queue,
|
|
4500
|
-
replaceExistingWake: true,
|
|
4501
|
-
state: options.state
|
|
4502
|
-
});
|
|
4503
|
-
const released = await releaseConversationWork({
|
|
4504
|
-
conversationId,
|
|
4505
|
-
leaseToken: lease.leaseToken,
|
|
4506
|
-
conversationStore: options.conversationStore,
|
|
4507
|
-
nowMs: yieldNowMs,
|
|
4508
|
-
state: options.state
|
|
4509
|
-
});
|
|
4510
|
-
if (!released) {
|
|
4511
|
-
return { status: "lost_lease" };
|
|
4512
|
-
}
|
|
4513
|
-
logInfo("conversation.work.yielded", {
|
|
4514
|
-
"app.worker.elapsed_ms": now(options) - startedAtMs,
|
|
4515
|
-
"app.worker.soft_yield_deadline_ms": softYieldDeadlineMs
|
|
4516
|
-
});
|
|
4517
|
-
return { status: "yielded" };
|
|
4518
|
-
};
|
|
4519
|
-
try {
|
|
4520
|
-
let hasRun = false;
|
|
4521
|
-
while (true) {
|
|
4522
|
-
attemptMessageIds = [];
|
|
4523
|
-
const leasedWork = await getConversationWorkState({
|
|
4524
|
-
conversationId,
|
|
4525
|
-
state: options.state
|
|
4526
|
-
});
|
|
4527
|
-
if (!leasedWork || leasedWork.lease?.leaseToken !== lease.leaseToken || leaseLost) {
|
|
4528
|
-
markLeaseLost();
|
|
4529
|
-
await requestLostLeaseRecovery({
|
|
4530
|
-
conversationId,
|
|
4531
|
-
destination,
|
|
4532
|
-
leaseToken: lease.leaseToken,
|
|
4533
|
-
nowMs: now(options),
|
|
4534
|
-
options
|
|
4535
|
-
});
|
|
4536
|
-
return { status: "lost_lease" };
|
|
4537
|
-
}
|
|
4538
|
-
const resumePending = leasedWork.execution.status === "awaiting_resume";
|
|
4539
|
-
const attemptMessages = selectAttemptMessages(leasedWork);
|
|
4540
|
-
attemptStartMessageIds = new Set(
|
|
4541
|
-
leasedWork.messages.map((message2) => message2.inboundMessageId)
|
|
4542
|
-
);
|
|
4543
|
-
if (hasRun && shouldYield()) {
|
|
4544
|
-
if (resumePending) {
|
|
4545
|
-
return await yieldWork();
|
|
4546
|
-
}
|
|
4547
|
-
break;
|
|
4548
|
-
}
|
|
4549
|
-
if (resumePending && attemptMessages.length === 0) {
|
|
4550
|
-
const resumeStarted = await beginConversationResume({
|
|
4551
|
-
conversationId,
|
|
4552
|
-
leaseToken: lease.leaseToken,
|
|
4553
|
-
conversationStore: options.conversationStore,
|
|
4554
|
-
nowMs: now(options),
|
|
4555
|
-
state: options.state
|
|
4556
|
-
});
|
|
4557
|
-
if (!resumeStarted) {
|
|
4558
|
-
markLeaseLost();
|
|
4559
|
-
await requestLostLeaseRecovery({
|
|
4560
|
-
conversationId,
|
|
4561
|
-
destination,
|
|
4562
|
-
leaseToken: lease.leaseToken,
|
|
4563
|
-
nowMs: now(options),
|
|
4564
|
-
options
|
|
4565
|
-
});
|
|
4566
|
-
return { status: "lost_lease" };
|
|
3899
|
+
async () => {
|
|
3900
|
+
try {
|
|
3901
|
+
await handleSlackEvent({
|
|
3902
|
+
body: parsed,
|
|
3903
|
+
services: args.services
|
|
3904
|
+
});
|
|
3905
|
+
} catch (error) {
|
|
3906
|
+
if (error instanceof SlackEventPersistenceError) {
|
|
3907
|
+
logException(error.cause, "slack.event.persist.failed");
|
|
3908
|
+
} else {
|
|
3909
|
+
logException(error, "slack.event.routing.failed");
|
|
3910
|
+
}
|
|
3911
|
+
return new Response("Slack event handling failed", { status: 503 });
|
|
3912
|
+
}
|
|
3913
|
+
return void 0;
|
|
4567
3914
|
}
|
|
4568
|
-
}
|
|
4569
|
-
attemptMessageIds = attemptMessages.map(
|
|
4570
|
-
(message2) => message2.inboundMessageId
|
|
4571
3915
|
);
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
const acknowledged = await ackMessages({
|
|
4575
|
-
conversationId,
|
|
4576
|
-
inboundMessageIds: attemptMessageIds,
|
|
4577
|
-
leaseToken: lease.leaseToken,
|
|
4578
|
-
conversationStore: options.conversationStore,
|
|
4579
|
-
nowMs: now(options),
|
|
4580
|
-
state: options.state
|
|
4581
|
-
});
|
|
4582
|
-
if (!acknowledged) {
|
|
4583
|
-
markLeaseLost();
|
|
4584
|
-
throw new Error(
|
|
4585
|
-
`Conversation work lease lost before inbox ack for ${conversationId}`
|
|
4586
|
-
);
|
|
4587
|
-
}
|
|
4588
|
-
};
|
|
4589
|
-
const workerContext = {
|
|
4590
|
-
attempt: {
|
|
4591
|
-
ack,
|
|
4592
|
-
conversationId,
|
|
4593
|
-
destination,
|
|
4594
|
-
drain,
|
|
4595
|
-
isFinalAttempt: attemptMessages.some(
|
|
4596
|
-
(message2) => isFinalAttempt(message2)
|
|
4597
|
-
),
|
|
4598
|
-
messages: attemptMessages
|
|
4599
|
-
},
|
|
4600
|
-
conversationId,
|
|
4601
|
-
destination,
|
|
4602
|
-
shouldYield,
|
|
4603
|
-
checkIn
|
|
4604
|
-
};
|
|
4605
|
-
const result = await options.run(workerContext);
|
|
4606
|
-
hasRun = true;
|
|
4607
|
-
if (result.status === "lost_lease") {
|
|
4608
|
-
await requestLostLeaseRecovery({
|
|
4609
|
-
conversationId,
|
|
4610
|
-
destination,
|
|
4611
|
-
leaseToken: lease.leaseToken,
|
|
4612
|
-
nowMs: now(options),
|
|
4613
|
-
options
|
|
4614
|
-
});
|
|
4615
|
-
return { status: "lost_lease" };
|
|
4616
|
-
}
|
|
4617
|
-
if (leaseLost) {
|
|
4618
|
-
await requestLostLeaseRecovery({
|
|
4619
|
-
conversationId,
|
|
4620
|
-
destination,
|
|
4621
|
-
leaseToken: lease.leaseToken,
|
|
4622
|
-
nowMs: now(options),
|
|
4623
|
-
options
|
|
4624
|
-
});
|
|
4625
|
-
return { status: "lost_lease" };
|
|
4626
|
-
}
|
|
4627
|
-
if (result.status === "yielded") {
|
|
4628
|
-
const resumeRequested = await requestConversationContinuation({
|
|
4629
|
-
conversationId,
|
|
4630
|
-
destination,
|
|
4631
|
-
leaseToken: lease.leaseToken,
|
|
4632
|
-
conversationStore: options.conversationStore,
|
|
4633
|
-
nowMs: now(options),
|
|
4634
|
-
state: options.state
|
|
4635
|
-
});
|
|
4636
|
-
if (!resumeRequested) {
|
|
4637
|
-
return { status: "lost_lease" };
|
|
4638
|
-
}
|
|
4639
|
-
return await yieldWork();
|
|
4640
|
-
}
|
|
4641
|
-
if (result.status === "deferred") {
|
|
4642
|
-
const deferredNowMs = now(options);
|
|
4643
|
-
const released = await releaseConversationWork({
|
|
4644
|
-
conversationId,
|
|
4645
|
-
leaseToken: lease.leaseToken,
|
|
4646
|
-
conversationStore: options.conversationStore,
|
|
4647
|
-
nowMs: deferredNowMs,
|
|
4648
|
-
state: options.state
|
|
4649
|
-
});
|
|
4650
|
-
if (!released) {
|
|
4651
|
-
return { status: "lost_lease" };
|
|
4652
|
-
}
|
|
4653
|
-
const wake = await ensureConversationWake({
|
|
4654
|
-
conversationId,
|
|
4655
|
-
conversationStore: options.conversationStore,
|
|
4656
|
-
idempotencyKey: nudgeIdempotencyKey(
|
|
4657
|
-
"deferred",
|
|
4658
|
-
conversationId,
|
|
4659
|
-
deferredNowMs
|
|
4660
|
-
),
|
|
4661
|
-
nowMs: deferredNowMs,
|
|
4662
|
-
queue: options.queue,
|
|
4663
|
-
state: options.state
|
|
4664
|
-
});
|
|
4665
|
-
return wake.status === "enqueued" ? { status: "pending_requeued" } : { status: "completed" };
|
|
4666
|
-
}
|
|
4667
|
-
if (attemptMessageIds.length > 0) {
|
|
4668
|
-
const failure = await recordFailedDeliveryAttempt({
|
|
4669
|
-
conversationId,
|
|
4670
|
-
leaseToken: lease.leaseToken,
|
|
4671
|
-
nowMs: now(options),
|
|
4672
|
-
messageIds: attemptMessageIds,
|
|
4673
|
-
options
|
|
4674
|
-
});
|
|
4675
|
-
if (isTerminalFailure(failure)) {
|
|
4676
|
-
await deadLetterAttempt({
|
|
4677
|
-
conversationId,
|
|
4678
|
-
leaseToken: lease.leaseToken,
|
|
4679
|
-
conversationStore: options.conversationStore,
|
|
4680
|
-
nowMs: now(options),
|
|
4681
|
-
state: options.state
|
|
4682
|
-
});
|
|
4683
|
-
return { status: "failed" };
|
|
4684
|
-
}
|
|
4685
|
-
if (failure.status === "lost_lease") {
|
|
4686
|
-
return { status: "lost_lease" };
|
|
4687
|
-
}
|
|
4688
|
-
if (failure.status === "recorded") {
|
|
4689
|
-
break;
|
|
4690
|
-
}
|
|
4691
|
-
}
|
|
4692
|
-
const next = await getConversationWorkState({
|
|
4693
|
-
conversationId,
|
|
4694
|
-
state: options.state
|
|
4695
|
-
});
|
|
4696
|
-
if (!next || next.lease?.leaseToken !== lease.leaseToken) {
|
|
4697
|
-
return { status: "lost_lease" };
|
|
4698
|
-
}
|
|
4699
|
-
if (next.execution.status !== "awaiting_resume" && countPendingConversationMessages(next) === 0) {
|
|
4700
|
-
break;
|
|
3916
|
+
if (failureResponse) {
|
|
3917
|
+
return failureResponse;
|
|
4701
3918
|
}
|
|
3919
|
+
} else {
|
|
3920
|
+
enqueue(
|
|
3921
|
+
args.waitUntil,
|
|
3922
|
+
withLogContext(
|
|
3923
|
+
eventLogContext,
|
|
3924
|
+
() => handleSlackEvent({
|
|
3925
|
+
body: parsed,
|
|
3926
|
+
services: args.services
|
|
3927
|
+
}).catch((error) => {
|
|
3928
|
+
logException(error, "slack.event.enqueue.failed");
|
|
3929
|
+
})
|
|
3930
|
+
)
|
|
3931
|
+
);
|
|
4702
3932
|
}
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
}
|
|
4713
|
-
if (completion === "pending") {
|
|
4714
|
-
const nudgeNowMs = now(options);
|
|
4715
|
-
const wake = await ensureConversationWake({
|
|
4716
|
-
conversationId,
|
|
4717
|
-
conversationStore: options.conversationStore,
|
|
4718
|
-
idempotencyKey: nudgeIdempotencyKey(
|
|
4719
|
-
"pending",
|
|
4720
|
-
conversationId,
|
|
4721
|
-
nudgeNowMs
|
|
4722
|
-
),
|
|
4723
|
-
nowMs: nudgeNowMs,
|
|
4724
|
-
queue: options.queue,
|
|
4725
|
-
state: options.state
|
|
4726
|
-
});
|
|
4727
|
-
return wake.status === "enqueued" ? { status: "pending_requeued" } : { status: "completed" };
|
|
4728
|
-
}
|
|
4729
|
-
logInfo("conversation.work.completed", {
|
|
4730
|
-
"app.worker.elapsed_ms": now(options) - startedAtMs
|
|
4731
|
-
});
|
|
4732
|
-
return { status: "completed" };
|
|
4733
|
-
} catch (error) {
|
|
4734
|
-
const errorNowMs = now(options);
|
|
4735
|
-
let recoveryRecorded = false;
|
|
3933
|
+
}
|
|
3934
|
+
return new Response("ok", { status: 200 });
|
|
3935
|
+
}
|
|
3936
|
+
|
|
3937
|
+
// src/handlers/webhooks.ts
|
|
3938
|
+
async function handleWebhookRequest(request, platform, run) {
|
|
3939
|
+
const requestContext = createRequestContext(request, { platform });
|
|
3940
|
+
const requestUrl = new URL(request.url);
|
|
3941
|
+
return await withContext(requestContext, async () => {
|
|
4736
3942
|
try {
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
});
|
|
3943
|
+
return await withSpan(
|
|
3944
|
+
"http.server.request",
|
|
3945
|
+
"http.server",
|
|
3946
|
+
requestContext,
|
|
3947
|
+
async () => {
|
|
3948
|
+
try {
|
|
3949
|
+
const response = await run();
|
|
3950
|
+
if (response.status >= 400) {
|
|
3951
|
+
let responseBodySnippet;
|
|
3952
|
+
try {
|
|
3953
|
+
responseBodySnippet = (await response.clone().text()).slice(
|
|
3954
|
+
0,
|
|
3955
|
+
300
|
|
3956
|
+
);
|
|
3957
|
+
} catch {
|
|
3958
|
+
responseBodySnippet = void 0;
|
|
3959
|
+
}
|
|
3960
|
+
logWarn("webhook.response.unsuccessful", {
|
|
3961
|
+
"http.response.status_code": response.status,
|
|
3962
|
+
"http.request.header.x_slack_signature": request.headers.get("x-slack-signature") ?? void 0,
|
|
3963
|
+
"http.request.header.x_slack_request_timestamp": request.headers.get("x-slack-request-timestamp") ?? void 0,
|
|
3964
|
+
...responseBodySnippet ? { "app.webhook.response_body": responseBodySnippet } : {}
|
|
3965
|
+
});
|
|
3966
|
+
}
|
|
3967
|
+
setSpanAttributes({
|
|
3968
|
+
"http.response.status_code": response.status
|
|
3969
|
+
});
|
|
3970
|
+
setSpanStatus(response.status >= 500 ? "error" : "ok");
|
|
3971
|
+
return response;
|
|
3972
|
+
} catch (error) {
|
|
3973
|
+
setSpanStatus("error");
|
|
3974
|
+
throw error;
|
|
3975
|
+
}
|
|
3976
|
+
},
|
|
3977
|
+
{
|
|
3978
|
+
"http.request.method": request.method,
|
|
3979
|
+
"url.path": requestUrl.pathname
|
|
4775
3980
|
}
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
conversationStore: options.conversationStore,
|
|
4780
|
-
nowMs: errorNowMs,
|
|
4781
|
-
state: options.state
|
|
4782
|
-
});
|
|
4783
|
-
}
|
|
4784
|
-
recoveryRecorded = true;
|
|
4785
|
-
} catch (recoveryError) {
|
|
4786
|
-
logException(recoveryError, "conversation.work.requeue.failed");
|
|
4787
|
-
}
|
|
4788
|
-
if (!isProviderRetryError(error)) {
|
|
4789
|
-
logException(error, "conversation.work.failed", {
|
|
4790
|
-
"app.worker.elapsed_ms": now(options) - startedAtMs
|
|
4791
|
-
});
|
|
4792
|
-
}
|
|
4793
|
-
if (!recoveryRecorded) {
|
|
3981
|
+
);
|
|
3982
|
+
} catch (error) {
|
|
3983
|
+
logException(error, "webhook.handler.failed");
|
|
4794
3984
|
throw error;
|
|
4795
3985
|
}
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
|
|
3989
|
+
// src/handlers/slack-webhook.ts
|
|
3990
|
+
async function POST2(request, waitUntil, services) {
|
|
3991
|
+
return handleWebhookRequest(
|
|
3992
|
+
request,
|
|
3993
|
+
"slack",
|
|
3994
|
+
() => handleSlackWebhook({
|
|
3995
|
+
request,
|
|
3996
|
+
services,
|
|
3997
|
+
waitUntil
|
|
3998
|
+
})
|
|
3999
|
+
);
|
|
4800
4000
|
}
|
|
4801
4001
|
|
|
4802
4002
|
// src/chat/task-execution/vercel-callback.ts
|
|
4003
|
+
import {
|
|
4004
|
+
handleCallback,
|
|
4005
|
+
registerDevConsumer
|
|
4006
|
+
} from "@vercel/queue";
|
|
4803
4007
|
var CONVERSATION_WORK_VISIBILITY_TIMEOUT_BUFFER_SECONDS = 30;
|
|
4804
4008
|
var CONVERSATION_WORK_DEV_CONSUMER_GROUP = "junior_conversation_work_dev";
|
|
4805
4009
|
function parseConversationQueueMessage(message) {
|
|
@@ -4825,6 +4029,15 @@ async function processConversationQueueMessage(message, options) {
|
|
|
4825
4029
|
});
|
|
4826
4030
|
}
|
|
4827
4031
|
async function handleConversationQueueMessage(message, metadata, options) {
|
|
4032
|
+
if (!getChatConfig().conversationWorkEnabled) {
|
|
4033
|
+
logWarn("conversation.work.processing.disabled", {
|
|
4034
|
+
"app.queue.consumer_group": metadata.consumerGroup,
|
|
4035
|
+
"app.queue.delivery_count": metadata.deliveryCount,
|
|
4036
|
+
"app.queue.message_id": metadata.messageId,
|
|
4037
|
+
"app.queue.topic_name": metadata.topicName
|
|
4038
|
+
});
|
|
4039
|
+
return;
|
|
4040
|
+
}
|
|
4828
4041
|
const verification = verifyConversationQueueMessage(message);
|
|
4829
4042
|
if (verification.status === "rejected") {
|
|
4830
4043
|
logConversationQueueMessageRejected(verification.reason, metadata);
|
|
@@ -4951,7 +4164,7 @@ function registerVercelPluginTaskDevConsumer() {
|
|
|
4951
4164
|
}
|
|
4952
4165
|
|
|
4953
4166
|
// src/chat/services/subscribed-decision.ts
|
|
4954
|
-
import { z as
|
|
4167
|
+
import { z as z5 } from "zod";
|
|
4955
4168
|
|
|
4956
4169
|
// src/chat/services/subscribed-reply-router-policy.ts
|
|
4957
4170
|
function buildSubscribedReplyRouterPolicy(assistantName) {
|
|
@@ -4996,13 +4209,13 @@ Assess conversation floor ownership and whether the latest message continues wor
|
|
|
4996
4209
|
}
|
|
4997
4210
|
|
|
4998
4211
|
// src/chat/services/subscribed-decision.ts
|
|
4999
|
-
var replyDecisionSchema =
|
|
5000
|
-
should_reply:
|
|
5001
|
-
should_unsubscribe:
|
|
4212
|
+
var replyDecisionSchema = z5.object({
|
|
4213
|
+
should_reply: z5.boolean().describe("Whether Junior should respond to this thread message."),
|
|
4214
|
+
should_unsubscribe: z5.boolean().describe(
|
|
5002
4215
|
"Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
|
|
5003
4216
|
),
|
|
5004
|
-
confidence:
|
|
5005
|
-
reason:
|
|
4217
|
+
confidence: z5.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
|
|
4218
|
+
reason: z5.string().describe("Short reason for the decision; use an empty string if none.")
|
|
5006
4219
|
}).strict();
|
|
5007
4220
|
var ROUTER_CONFIDENCE_THRESHOLD = 0.7;
|
|
5008
4221
|
var ROUTER_CLASSIFIER_MAX_TOKENS = 400;
|
|
@@ -5457,10 +4670,6 @@ function buildLogContext(deps, args) {
|
|
|
5457
4670
|
function actorUserName(message) {
|
|
5458
4671
|
return getMessageActorIdentity(message)?.userName;
|
|
5459
4672
|
}
|
|
5460
|
-
function isResourceEventNotificationMessage2(message) {
|
|
5461
|
-
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
5462
|
-
return raw?.event_type === "resource_event";
|
|
5463
|
-
}
|
|
5464
4673
|
function createSlackTurnRuntime(deps) {
|
|
5465
4674
|
const logContext = (args) => buildLogContext(deps, args);
|
|
5466
4675
|
const maybeHandleThreadOptOutDecision = async (args) => {
|
|
@@ -5881,7 +5090,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
5881
5090
|
const threadId = deps.getThreadId(thread, message);
|
|
5882
5091
|
const channelId = deps.getChannelId(thread, message);
|
|
5883
5092
|
const runId = deps.getRunId(thread, message);
|
|
5884
|
-
const isResourceEventNotification =
|
|
5093
|
+
const isResourceEventNotification = isResourceEventSlackMessage(message);
|
|
5885
5094
|
const actorId = isResourceEventNotification ? void 0 : message.author.userId;
|
|
5886
5095
|
const turnContext = logContext({
|
|
5887
5096
|
threadId,
|
|
@@ -6649,14 +5858,16 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
6649
5858
|
listThreadReplies: overrides.visionContext?.listThreadReplies ?? listThreadReplies,
|
|
6650
5859
|
downloadFile: overrides.visionContext?.downloadFile ?? downloadPrivateSlackFile
|
|
6651
5860
|
});
|
|
5861
|
+
const agentRunner = overrides.replyExecutor?.agentRunner ?? createAgentRunner(executeAgentRun, {
|
|
5862
|
+
bindSpawnAgent: (request) => bindSpawnAgent(request, { queue: getVercelConversationWorkQueue }),
|
|
5863
|
+
tracePropagation: overrides.sandbox?.tracePropagation
|
|
5864
|
+
});
|
|
6652
5865
|
return {
|
|
6653
5866
|
conversationMemory,
|
|
6654
5867
|
contextCompactor,
|
|
6655
5868
|
replyExecutor: {
|
|
6656
5869
|
contextCompactor: overrides.replyExecutor?.contextCompactor ?? contextCompactor,
|
|
6657
|
-
agentRunner
|
|
6658
|
-
tracePropagation: overrides.sandbox?.tracePropagation
|
|
6659
|
-
}),
|
|
5870
|
+
agentRunner,
|
|
6660
5871
|
getAwaitingAgentContinueRequest: overrides.replyExecutor?.getAwaitingAgentContinueRequest ?? getAwaitingAgentContinueRequest,
|
|
6661
5872
|
lookupSlackUser: overrides.replyExecutor?.lookupSlackUser ?? lookupSlackUser,
|
|
6662
5873
|
scheduleAgentContinue: overrides.replyExecutor?.scheduleAgentContinue ?? scheduleAgentContinue,
|
|
@@ -6677,11 +5888,11 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
6677
5888
|
import { createSlackSource as createSlackSource2 } from "@sentry/junior-plugin-api";
|
|
6678
5889
|
|
|
6679
5890
|
// src/chat/slack/action-token.ts
|
|
6680
|
-
import { z as
|
|
6681
|
-
var slackActionTokenSchema =
|
|
6682
|
-
var slackMessageEnvelopeSchema =
|
|
6683
|
-
raw:
|
|
6684
|
-
action_token:
|
|
5891
|
+
import { z as z6 } from "zod";
|
|
5892
|
+
var slackActionTokenSchema = z6.string().trim().min(1).brand();
|
|
5893
|
+
var slackMessageEnvelopeSchema = z6.object({
|
|
5894
|
+
raw: z6.object({
|
|
5895
|
+
action_token: z6.unknown().optional()
|
|
6685
5896
|
}).optional()
|
|
6686
5897
|
});
|
|
6687
5898
|
function readSlackActionToken(message) {
|
|
@@ -6845,7 +6056,7 @@ function queuedInstructionActor(queued) {
|
|
|
6845
6056
|
};
|
|
6846
6057
|
}
|
|
6847
6058
|
function queuedInstructionProvenance(queued, teamId) {
|
|
6848
|
-
if (
|
|
6059
|
+
if (isResourceEventSlackMessage(queued.message)) {
|
|
6849
6060
|
return contextProvenance;
|
|
6850
6061
|
}
|
|
6851
6062
|
const identity = getMessageActorIdentity(queued.message);
|
|
@@ -6859,13 +6070,6 @@ function queuedInstructionProvenance(queued, teamId) {
|
|
|
6859
6070
|
);
|
|
6860
6071
|
return instructionProvenanceFor(author);
|
|
6861
6072
|
}
|
|
6862
|
-
function isResourceEventMessage(message) {
|
|
6863
|
-
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
6864
|
-
return raw?.event_type === "resource_event";
|
|
6865
|
-
}
|
|
6866
|
-
function resourceEventCredentialContext(message) {
|
|
6867
|
-
return isResourceEventMessage(message) ? { actor: { platform: "system", name: "resource-event" } } : void 0;
|
|
6868
|
-
}
|
|
6869
6073
|
async function resolveChannelName(thread) {
|
|
6870
6074
|
const existingName = thread.channel.name?.trim();
|
|
6871
6075
|
if (existingName) {
|
|
@@ -6994,7 +6198,7 @@ function createReplyToThread(deps) {
|
|
|
6994
6198
|
)
|
|
6995
6199
|
};
|
|
6996
6200
|
await Promise.all(
|
|
6997
|
-
(options.queuedMessages ?? []).filter((queued) => !
|
|
6201
|
+
(options.queuedMessages ?? []).filter((queued) => !isResourceEventSlackMessage(queued.message)).map(
|
|
6998
6202
|
(queued) => ensureSlackMessageActorIdentity(
|
|
6999
6203
|
queued.message,
|
|
7000
6204
|
teamId,
|
|
@@ -7003,15 +6207,28 @@ function createReplyToThread(deps) {
|
|
|
7003
6207
|
)
|
|
7004
6208
|
);
|
|
7005
6209
|
const effectiveUserText = currentText.userText;
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
6210
|
+
let executionActor;
|
|
6211
|
+
let credentialContext;
|
|
6212
|
+
if (options.execution) {
|
|
6213
|
+
executionActor = options.execution.dispatch.actor;
|
|
6214
|
+
credentialContext = options.execution.credentialContext;
|
|
6215
|
+
} else if (isResourceEventSlackMessage(message)) {
|
|
6216
|
+
executionActor = RESOURCE_EVENT_SYSTEM_ACTOR;
|
|
6217
|
+
credentialContext = credentialContextForActor(executionActor);
|
|
6218
|
+
} else {
|
|
6219
|
+
executionActor = await ensureSlackMessageActorIdentity(
|
|
6220
|
+
message,
|
|
6221
|
+
teamId,
|
|
6222
|
+
deps.services.lookupSlackUser
|
|
6223
|
+
);
|
|
6224
|
+
if (executionActor) {
|
|
6225
|
+
credentialContext = credentialContextForActor(executionActor);
|
|
6226
|
+
}
|
|
6227
|
+
}
|
|
6228
|
+
if (!executionActor || !credentialContext) {
|
|
6229
|
+
throw new Error("Slack reply execution requires an actor");
|
|
6230
|
+
}
|
|
6231
|
+
const actor = "userId" in executionActor ? executionActor : void 0;
|
|
7015
6232
|
const slackActorId = actor?.userId;
|
|
7016
6233
|
const preparedState = options.preparedState ?? await deps.prepareTurnState({
|
|
7017
6234
|
thread,
|
|
@@ -7085,7 +6302,7 @@ function createReplyToThread(deps) {
|
|
|
7085
6302
|
attachments,
|
|
7086
6303
|
{
|
|
7087
6304
|
threadId,
|
|
7088
|
-
actorId:
|
|
6305
|
+
actorId: isResourceEventSlackMessage(queued.message) ? void 0 : queued.message.author.userId,
|
|
7089
6306
|
channelId,
|
|
7090
6307
|
runId,
|
|
7091
6308
|
conversation: preparedState.conversation,
|
|
@@ -7660,7 +6877,9 @@ function createReplyToThread(deps) {
|
|
|
7660
6877
|
},
|
|
7661
6878
|
routing: {
|
|
7662
6879
|
credentialContext,
|
|
7663
|
-
|
|
6880
|
+
// Always set the execution actor when known. Resource-event turns
|
|
6881
|
+
// carry the system principal; interactive turns carry the Slack user.
|
|
6882
|
+
actor: executionActor,
|
|
7664
6883
|
slackConversation,
|
|
7665
6884
|
source,
|
|
7666
6885
|
destination,
|
|
@@ -7673,7 +6892,7 @@ function createReplyToThread(deps) {
|
|
|
7673
6892
|
policy: {
|
|
7674
6893
|
configuration: preparedState.configuration,
|
|
7675
6894
|
channelConfiguration: preparedState.channelConfiguration,
|
|
7676
|
-
|
|
6895
|
+
disabledFeatures: options.execution?.disabledFeatures ?? (message.author.isBot === true ? ["interactive-auth"] : void 0),
|
|
7677
6896
|
turnDeadlineAtMs: getTurnRequestDeadline()?.deadlineAtMs
|
|
7678
6897
|
},
|
|
7679
6898
|
state: {
|
|
@@ -8387,7 +7606,7 @@ function createSlackDispatchTurnRunner(options) {
|
|
|
8387
7606
|
conversationId,
|
|
8388
7607
|
destination: dispatch2.destination,
|
|
8389
7608
|
execution: {
|
|
8390
|
-
|
|
7609
|
+
disabledFeatures: ["interactive-auth"],
|
|
8391
7610
|
channelConfiguration: options.getChannelConfiguration(
|
|
8392
7611
|
dispatch2.destination.channelId
|
|
8393
7612
|
),
|
|
@@ -8688,27 +7907,57 @@ async function failContinuationStartup(args) {
|
|
|
8688
7907
|
);
|
|
8689
7908
|
}
|
|
8690
7909
|
}
|
|
8691
|
-
async function
|
|
8692
|
-
|
|
8693
|
-
|
|
7910
|
+
async function resolveSlackResumeUserActor(args) {
|
|
7911
|
+
try {
|
|
7912
|
+
const work = await getConversationWorkState({
|
|
7913
|
+
conversationId: args.conversationId
|
|
7914
|
+
});
|
|
7915
|
+
const workActor = work?.actor;
|
|
7916
|
+
if (workActor?.teamId === args.teamId && workActor.slackUserId === args.userId) {
|
|
7917
|
+
try {
|
|
7918
|
+
return createSlackActor(args.teamId, args.userId, {
|
|
7919
|
+
email: workActor.email,
|
|
7920
|
+
fullName: workActor.fullName,
|
|
7921
|
+
userName: workActor.slackUserName
|
|
7922
|
+
});
|
|
7923
|
+
} catch {
|
|
7924
|
+
}
|
|
7925
|
+
}
|
|
7926
|
+
} catch {
|
|
7927
|
+
}
|
|
7928
|
+
try {
|
|
8694
7929
|
return createSlackResumeActor({
|
|
8695
|
-
actor: stored,
|
|
8696
7930
|
teamId: args.teamId,
|
|
8697
7931
|
userId: args.userId
|
|
8698
7932
|
});
|
|
7933
|
+
} catch {
|
|
7934
|
+
return void 0;
|
|
8699
7935
|
}
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
return
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
7936
|
+
}
|
|
7937
|
+
async function resolveResumeExecutionIdentity(args) {
|
|
7938
|
+
const routing = args.routingContext;
|
|
7939
|
+
if (routing?.credentialContext) {
|
|
7940
|
+
const actor2 = routing.dispatch?.actor ?? routing.actor ?? (!("type" in routing.credentialContext.actor) ? routing.credentialContext.actor : void 0);
|
|
7941
|
+
return actor2 ? { actor: actor2, credentialContext: routing.credentialContext } : void 0;
|
|
7942
|
+
}
|
|
7943
|
+
let actor = routing?.actor;
|
|
7944
|
+
if (!actor && isResourceEventConversationMessage(args.userMessage)) {
|
|
7945
|
+
actor = RESOURCE_EVENT_SYSTEM_ACTOR;
|
|
7946
|
+
}
|
|
7947
|
+
if (!actor && args.userMessage.author?.userId) {
|
|
7948
|
+
actor = await resolveSlackResumeUserActor({
|
|
7949
|
+
conversationId: args.conversationId,
|
|
7950
|
+
teamId: args.teamId,
|
|
7951
|
+
userId: args.userMessage.author.userId
|
|
8709
7952
|
});
|
|
8710
7953
|
}
|
|
8711
|
-
|
|
7954
|
+
if (!actor) {
|
|
7955
|
+
return void 0;
|
|
7956
|
+
}
|
|
7957
|
+
return {
|
|
7958
|
+
actor,
|
|
7959
|
+
credentialContext: credentialContextForActor(actor)
|
|
7960
|
+
};
|
|
8712
7961
|
}
|
|
8713
7962
|
function isContinuationResume(summary) {
|
|
8714
7963
|
return summary.state === "awaiting_resume" && (summary.resumeReason === "timeout" || summary.resumeReason === "yield" || summary.resumeReason === "retry");
|
|
@@ -8726,7 +7975,6 @@ async function failUnresumableContinuation(args) {
|
|
|
8726
7975
|
conversationId: args.conversationId
|
|
8727
7976
|
});
|
|
8728
7977
|
await recordAgentTurnSessionSummary({
|
|
8729
|
-
actor: args.summary.actor,
|
|
8730
7978
|
conversationId: args.conversationId,
|
|
8731
7979
|
destination: routing.destination,
|
|
8732
7980
|
dispatchId: args.summary.dispatchId,
|
|
@@ -8793,16 +8041,32 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
|
|
|
8793
8041
|
(message) => message.role === "user" && options.inputMessageIds?.includes(message.id)
|
|
8794
8042
|
) : void 0;
|
|
8795
8043
|
const userMessage = getTurnUserMessage(conversation, payload.sessionId) ?? dispatchUserMessage;
|
|
8796
|
-
|
|
8797
|
-
|
|
8798
|
-
|
|
8799
|
-
|
|
8800
|
-
|
|
8801
|
-
);
|
|
8044
|
+
if (!userMessage) {
|
|
8045
|
+
await failStrandedSessionWithFallback({
|
|
8046
|
+
conversationId: payload.conversationId,
|
|
8047
|
+
errorMessage: `Unable to locate the persisted user message for agent continuation session "${payload.sessionId}"`,
|
|
8048
|
+
sessionRecord: activeSessionRecord
|
|
8049
|
+
});
|
|
8050
|
+
return false;
|
|
8802
8051
|
}
|
|
8803
8052
|
if (conversation.processing.activeTurnId !== payload.sessionId) {
|
|
8804
8053
|
return false;
|
|
8805
8054
|
}
|
|
8055
|
+
const identity = await resolveResumeExecutionIdentity({
|
|
8056
|
+
conversationId: payload.conversationId,
|
|
8057
|
+
routingContext: options.routingContext,
|
|
8058
|
+
teamId: destination.teamId,
|
|
8059
|
+
userMessage
|
|
8060
|
+
});
|
|
8061
|
+
if (!identity) {
|
|
8062
|
+
await failStrandedSessionWithFallback({
|
|
8063
|
+
conversationId: payload.conversationId,
|
|
8064
|
+
errorMessage: "Unable to rebuild Slack actor for continuation",
|
|
8065
|
+
sessionRecord: activeSessionRecord
|
|
8066
|
+
});
|
|
8067
|
+
return false;
|
|
8068
|
+
}
|
|
8069
|
+
const { actor, credentialContext } = identity;
|
|
8806
8070
|
const channelConfiguration = getChannelConfigurationServiceById(
|
|
8807
8071
|
destination.channelId
|
|
8808
8072
|
);
|
|
@@ -8810,34 +8074,6 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
|
|
|
8810
8074
|
excludeMessageId: userMessage.id
|
|
8811
8075
|
});
|
|
8812
8076
|
const sandboxRef = getPersistedSandboxState(currentState);
|
|
8813
|
-
let actor;
|
|
8814
|
-
let credentialContext;
|
|
8815
|
-
if (options.routingContext?.credentialContext) {
|
|
8816
|
-
credentialContext = options.routingContext.credentialContext;
|
|
8817
|
-
} else if (systemActor) {
|
|
8818
|
-
credentialContext = { actor: systemActor };
|
|
8819
|
-
} else {
|
|
8820
|
-
actor = await resolveContinuationActor({
|
|
8821
|
-
conversationId: payload.conversationId,
|
|
8822
|
-
sessionRecordActor: activeSessionRecord.actor,
|
|
8823
|
-
teamId: destination.teamId,
|
|
8824
|
-
userId: userActorId
|
|
8825
|
-
});
|
|
8826
|
-
if (!actor) {
|
|
8827
|
-
await failStrandedSessionWithFallback({
|
|
8828
|
-
conversationId: payload.conversationId,
|
|
8829
|
-
errorMessage: "Stored Slack actor missing for continuation",
|
|
8830
|
-
sessionRecord: activeSessionRecord
|
|
8831
|
-
});
|
|
8832
|
-
return false;
|
|
8833
|
-
}
|
|
8834
|
-
credentialContext = {
|
|
8835
|
-
actor: {
|
|
8836
|
-
type: "user",
|
|
8837
|
-
userId: actor.userId
|
|
8838
|
-
}
|
|
8839
|
-
};
|
|
8840
|
-
}
|
|
8841
8077
|
const routing = await resolveTurnSessionRouting({
|
|
8842
8078
|
conversationId: payload.conversationId
|
|
8843
8079
|
});
|
|
@@ -8885,7 +8121,7 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
|
|
|
8885
8121
|
routing: {
|
|
8886
8122
|
...options.routingContext,
|
|
8887
8123
|
credentialContext,
|
|
8888
|
-
|
|
8124
|
+
actor,
|
|
8889
8125
|
destination: routingDestination,
|
|
8890
8126
|
source,
|
|
8891
8127
|
toolChannelId: artifacts.assistantContextChannelId ?? destination.channelId
|
|
@@ -9006,7 +8242,6 @@ async function failStrandedSessionWithFallback(args) {
|
|
|
9006
8242
|
}
|
|
9007
8243
|
if (args.sessionRecord.dispatchId) {
|
|
9008
8244
|
await recordAgentTurnSessionSummary({
|
|
9009
|
-
actor: args.sessionRecord.actor,
|
|
9010
8245
|
conversationId: args.conversationId,
|
|
9011
8246
|
destination: routing.destination,
|
|
9012
8247
|
dispatchId: args.sessionRecord.dispatchId,
|
|
@@ -9071,7 +8306,6 @@ async function recoverStrandedRunningSession(args) {
|
|
|
9071
8306
|
messages: sessionRecord.piMessages,
|
|
9072
8307
|
errorMessage: "Recovered running session after hard worker death",
|
|
9073
8308
|
modelId,
|
|
9074
|
-
actor: sessionRecord.actor,
|
|
9075
8309
|
surface: sessionRecord.surface
|
|
9076
8310
|
});
|
|
9077
8311
|
if (!parked) {
|
|
@@ -9279,12 +8513,18 @@ function createProductionConversationWorkOptions(options) {
|
|
|
9279
8513
|
},
|
|
9280
8514
|
runTurn: runtime.runDispatchTurn
|
|
9281
8515
|
});
|
|
8516
|
+
const providerWorker = createAgentDispatchWorkRouter({
|
|
8517
|
+
dispatchWorker,
|
|
8518
|
+
fallbackWorker: slackWorker
|
|
8519
|
+
});
|
|
9282
8520
|
return {
|
|
9283
8521
|
conversationStore,
|
|
9284
8522
|
queue,
|
|
9285
|
-
run:
|
|
9286
|
-
|
|
9287
|
-
|
|
8523
|
+
run: routeAgentInvocationWork({
|
|
8524
|
+
invocationWorker: createAgentInvocationWorker({
|
|
8525
|
+
agentRunner
|
|
8526
|
+
}),
|
|
8527
|
+
fallbackWorker: providerWorker
|
|
9288
8528
|
})
|
|
9289
8529
|
};
|
|
9290
8530
|
}
|
|
@@ -9395,7 +8635,7 @@ async function ingestResourceEvent(input, options) {
|
|
|
9395
8635
|
}
|
|
9396
8636
|
|
|
9397
8637
|
// src/chat/event-tasks/ingest.ts
|
|
9398
|
-
import { createHash
|
|
8638
|
+
import { createHash } from "crypto";
|
|
9399
8639
|
import {
|
|
9400
8640
|
createSlackSource as createSlackSource3,
|
|
9401
8641
|
RESOURCE_EVENT_SUMMARY_MAX_LENGTH,
|
|
@@ -9403,7 +8643,7 @@ import {
|
|
|
9403
8643
|
resourceEventSchema as resourceEventSchema2
|
|
9404
8644
|
} from "@sentry/junior-plugin-api";
|
|
9405
8645
|
function eventTaskDispatchKey(taskId, namespace, eventKey) {
|
|
9406
|
-
return `event-task:${
|
|
8646
|
+
return `event-task:${createHash("sha256").update(`${taskId}\0${namespace}\0${eventKey}`).digest("hex").slice(0, 32)}`;
|
|
9407
8647
|
}
|
|
9408
8648
|
function oneLine(value) {
|
|
9409
8649
|
return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 512);
|
|
@@ -9815,6 +9055,7 @@ async function createApp(options) {
|
|
|
9815
9055
|
const previousConfigDefaults = getConfigDefaults();
|
|
9816
9056
|
const previousSlackReactionConfig = getSlackReactionConfig();
|
|
9817
9057
|
const previousSandboxResources = getSandboxResourceConfig();
|
|
9058
|
+
const previousExperimentalFeatures = getExperimentalFeatures();
|
|
9818
9059
|
const previousDashboardLinkOptions = setDashboardConversationLinkOptions(dashboard);
|
|
9819
9060
|
let pluginRoutes = [];
|
|
9820
9061
|
let pluginApiRoutes = [];
|
|
@@ -9850,6 +9091,7 @@ async function createApp(options) {
|
|
|
9850
9091
|
options?.sandbox?.egressTracePropagationDomains
|
|
9851
9092
|
);
|
|
9852
9093
|
setSandboxResourceConfig(options?.sandbox);
|
|
9094
|
+
setExperimentalFeatures(options?.experimental);
|
|
9853
9095
|
setConfigDefaults(options?.configDefaults);
|
|
9854
9096
|
warnUnregisteredConfigDefaults(options?.configDefaults);
|
|
9855
9097
|
if (options?.slack) {
|
|
@@ -9873,12 +9115,15 @@ async function createApp(options) {
|
|
|
9873
9115
|
setConfigDefaults(previousConfigDefaults);
|
|
9874
9116
|
setSlackReactionConfig(previousSlackReactionConfig);
|
|
9875
9117
|
setSandboxResourceConfig(previousSandboxResources);
|
|
9118
|
+
setExperimentalFeatures(previousExperimentalFeatures);
|
|
9876
9119
|
setDashboardConversationLinkOptions(previousDashboardLinkOptions);
|
|
9877
9120
|
throw error;
|
|
9878
9121
|
}
|
|
9879
9122
|
const waitUntil = options?.waitUntil ?? await defaultWaitUntil();
|
|
9880
9123
|
const tracePropagation = { domains: sandboxEgressTracePropagationDomains };
|
|
9124
|
+
const conversationWorkQueue = getVercelConversationWorkQueue();
|
|
9881
9125
|
const agentRunner = createAgentRunner(executeAgentRun, {
|
|
9126
|
+
bindSpawnAgent: (request) => bindSpawnAgent(request, { queue: conversationWorkQueue }),
|
|
9882
9127
|
tracePropagation
|
|
9883
9128
|
});
|
|
9884
9129
|
const runtimeServiceOverrides = {
|