@sentry/junior 0.174.0 → 0.176.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-HBZUWB4D.js → agent-hooks-ZPCHKYXI.js} +13 -12
- package/dist/api.js +27 -27
- package/dist/app.js +272 -344
- package/dist/{catalog-runtime-J3R3LC7Y.js → catalog-runtime-3Z2Y5IP6.js} +5 -5
- package/dist/chat/agent-dispatch/heartbeat.d.ts +1 -1
- package/dist/chat/agent-dispatch/store.d.ts +3 -16
- package/dist/chat/resource-events/catalog.d.ts +2 -0
- package/dist/chat/resource-events/notification.d.ts +1 -1
- package/dist/chat/resource-events/tool-support.d.ts +4 -0
- package/dist/{chunk-47LO5GDT.js → chunk-2N7YRFMW.js} +12 -12
- package/dist/{chunk-RL23S5DG.js → chunk-5JB5JJO5.js} +1 -1
- package/dist/{chunk-2BNKQSPC.js → chunk-64EGCW34.js} +8 -16
- package/dist/{chunk-DIW6IQYK.js → chunk-665JOQEP.js} +6 -6
- package/dist/{chunk-WEL4NWRR.js → chunk-6NQJQP7O.js} +5 -5
- package/dist/{chunk-5EWBGDW2.js → chunk-AJEZETLT.js} +1 -1
- package/dist/{chunk-GWZBBIV6.js → chunk-B65VEBJV.js} +2 -2
- package/dist/{chunk-HJFWO72I.js → chunk-B6IOTX7W.js} +1 -1
- package/dist/{chunk-T5VGNZ7F.js → chunk-B7U2QBMT.js} +16 -58
- package/dist/{chunk-ZBWAXCR3.js → chunk-BNGK2J6X.js} +1 -1
- package/dist/{chunk-IYI7RPHU.js → chunk-CI4JX64I.js} +1 -1
- package/dist/{chunk-XOXKL2DL.js → chunk-CNC65LIX.js} +1 -1
- package/dist/{chunk-4ALVTB7F.js → chunk-COFZR2CO.js} +1 -1
- package/dist/{chunk-KIU7RKE5.js → chunk-CTYWFV6L.js} +6 -6
- package/dist/{chunk-VZFLAGFK.js → chunk-CUA5SZR5.js} +1 -1
- package/dist/{chunk-2E353AHN.js → chunk-DVHYQDGM.js} +1 -1
- package/dist/{chunk-BFNNCBTK.js → chunk-FNOLPLXJ.js} +4 -4
- package/dist/{chunk-GX2ISGLH.js → chunk-GYRGJVWR.js} +472 -903
- package/dist/{chunk-FFUNPZA2.js → chunk-H7KTMGNI.js} +1 -1
- package/dist/{chunk-OTAPFODZ.js → chunk-IPOB6IL5.js} +98 -96
- package/dist/{chunk-JVORBSUR.js → chunk-JHCAX7XY.js} +3 -3
- package/dist/{chunk-BLBKORDG.js → chunk-JIZ3RFER.js} +505 -11
- package/dist/{chunk-DRRUFZKZ.js → chunk-KYHHJ6LS.js} +1 -1
- package/dist/{chunk-N7Y3T47I.js → chunk-OKXHYVKE.js} +4 -4
- package/dist/{chunk-REUKFWLH.js → chunk-PS3ZPRL2.js} +1 -1
- package/dist/{chunk-7V25DLCB.js → chunk-Q374NKGS.js} +8 -8
- package/dist/{chunk-W6HVH5JJ.js → chunk-RSIHA3XC.js} +5 -5
- package/dist/{chunk-Z23POK2V.js → chunk-SBIQ5MZW.js} +1 -1
- package/dist/{chunk-WH7F67EN.js → chunk-SGLLADGQ.js} +17 -17
- package/dist/{chunk-AJMUVCXW.js → chunk-VUAHVGPY.js} +4 -4
- package/dist/{chunk-6FWEUJGH.js → chunk-VVLQGGJJ.js} +1 -1
- package/dist/{chunk-OXYAEFKS.js → chunk-Z2YZ6QLG.js} +2 -2
- package/dist/cli/chat.js +31 -31
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +14 -13
- package/dist/cli/snapshot-create.js +10 -10
- package/dist/cli/upgrade.js +7 -7
- package/dist/{db-6JOWUGLP.js → db-63K2IY36.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-ZLOKNXOW.js → oauth-callback-server-JZXBDXGO.js} +24 -24
- package/dist/{runner-YD4J2GBE.js → runner-3KWZJVK6.js} +16 -16
- package/dist/{skills-YMSY2LFN.js → skills-TFQQ3WSE.js} +6 -6
- package/dist/spawn-3GVQNWFH.js +37 -0
- package/dist/{validation-KAOZ7UHD.js → validation-RKLSF2UH.js} +6 -6
- package/dist/version.js +1 -1
- package/dist/{work-ILZ3L7AD.js → work-RKDS3J2X.js} +19 -19
- package/dist/worker-5RJNDPYW.js +24 -0
- package/package.json +4 -4
- package/dist/chat/agent-dispatch/signing.d.ts +0 -14
- package/dist/handlers/agent-dispatch.d.ts +0 -12
- package/dist/spawn-ZVO5IUCR.js +0 -37
- package/dist/worker-D34ZL6RU.js +0 -24
package/dist/app.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
processConversationWork
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VUAHVGPY.js";
|
|
4
4
|
import {
|
|
5
5
|
bindSpawnAgent
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-BNGK2J6X.js";
|
|
7
7
|
import {
|
|
8
8
|
createAgentInvocationWorker,
|
|
9
9
|
enqueueAgentInvocation,
|
|
10
10
|
listPendingAgentInvocationMailboxAppends,
|
|
11
11
|
routeAgentInvocationWork
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-CTYWFV6L.js";
|
|
13
13
|
import {
|
|
14
14
|
GET as GET2,
|
|
15
15
|
GET2 as GET3,
|
|
@@ -36,12 +36,12 @@ import {
|
|
|
36
36
|
startSlackProcessingReaction,
|
|
37
37
|
stripLeadingBotMention,
|
|
38
38
|
wakePausedTurn
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-SGLLADGQ.js";
|
|
40
40
|
import "./chunk-FA6POGLH.js";
|
|
41
41
|
import {
|
|
42
42
|
getTurnRequestDeadline,
|
|
43
43
|
runWithTurnRequestDeadline
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-PS3ZPRL2.js";
|
|
45
45
|
import {
|
|
46
46
|
GET,
|
|
47
47
|
apiTurnIdForMessage,
|
|
@@ -58,8 +58,8 @@ import {
|
|
|
58
58
|
resolveSlackConversationContext,
|
|
59
59
|
routeApiTurnWork,
|
|
60
60
|
webActorFromEmail
|
|
61
|
-
} from "./chunk-
|
|
62
|
-
import "./chunk-
|
|
61
|
+
} from "./chunk-2N7YRFMW.js";
|
|
62
|
+
import "./chunk-VVLQGGJJ.js";
|
|
63
63
|
import {
|
|
64
64
|
CONVERSATION_WORK_STALE_ENQUEUE_MS,
|
|
65
65
|
appendAndEnqueueInboundMessage,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
isInvalidConversationRecordError,
|
|
71
71
|
listActiveConversationIds,
|
|
72
72
|
removeActiveConversation
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-OKXHYVKE.js";
|
|
74
74
|
import {
|
|
75
75
|
buildDeliveredTurnStatePatch,
|
|
76
76
|
claimDispatchMailboxAppend,
|
|
@@ -81,7 +81,6 @@ import {
|
|
|
81
81
|
getAgentTurnDiagnosticsAttributes,
|
|
82
82
|
getDispatchConversationId,
|
|
83
83
|
getDispatchInputMessageId,
|
|
84
|
-
getDispatchInputMessageIds,
|
|
85
84
|
getDispatchRecord,
|
|
86
85
|
getDispatchTurnId,
|
|
87
86
|
getPluginDispatchProjection,
|
|
@@ -101,7 +100,7 @@ import {
|
|
|
101
100
|
requireTurnFailureEventId,
|
|
102
101
|
resolveTurnSessionRouting,
|
|
103
102
|
scheduleSessionCompletedPluginTasks
|
|
104
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-B7U2QBMT.js";
|
|
105
104
|
import {
|
|
106
105
|
ConversationTurnLifecycleService,
|
|
107
106
|
coerceThreadConversationState,
|
|
@@ -111,7 +110,7 @@ import {
|
|
|
111
110
|
persistThreadRuntimeState,
|
|
112
111
|
persistThreadState,
|
|
113
112
|
persistThreadStateById
|
|
114
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-6NQJQP7O.js";
|
|
115
114
|
import "./chunk-UTL3MHPC.js";
|
|
116
115
|
import {
|
|
117
116
|
getVercelConversationWorkQueue,
|
|
@@ -130,7 +129,7 @@ import {
|
|
|
130
129
|
import {
|
|
131
130
|
validatePluginEgressCredentialHooks,
|
|
132
131
|
validatePluginRegistrations
|
|
133
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-COFZR2CO.js";
|
|
134
133
|
import {
|
|
135
134
|
defineJuniorPlugins,
|
|
136
135
|
pluginCatalogConfigFromEnv,
|
|
@@ -140,15 +139,12 @@ import {
|
|
|
140
139
|
import {
|
|
141
140
|
SANDBOX_EGRESS_PROXY_PATH,
|
|
142
141
|
buildSteeringPiMessage,
|
|
143
|
-
cancelSubscriptions,
|
|
144
142
|
clearSandboxEgressSignals,
|
|
145
143
|
consumeSandboxEgressAuthRequiredSignal,
|
|
146
144
|
consumeSandboxEgressPermissionDeniedSignal,
|
|
147
145
|
createContextCompactor,
|
|
148
|
-
deliverResourceEventSubscription,
|
|
149
146
|
executeAgentRun,
|
|
150
147
|
executeCredentialedEgressRequest,
|
|
151
|
-
findMatchingResourceEventSubscriptions,
|
|
152
148
|
getConfigDefaults,
|
|
153
149
|
latestReportedProgress,
|
|
154
150
|
listThreadReplies,
|
|
@@ -165,11 +161,11 @@ import {
|
|
|
165
161
|
shouldEmitDevAgentTrace,
|
|
166
162
|
shouldPropagateSandboxEgressTrace,
|
|
167
163
|
unpublishedArtifactHeaders
|
|
168
|
-
} from "./chunk-
|
|
164
|
+
} from "./chunk-GYRGJVWR.js";
|
|
169
165
|
import {
|
|
170
166
|
AuthorizationFlowDisabledError,
|
|
171
167
|
PluginCredentialFailureError
|
|
172
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-RSIHA3XC.js";
|
|
173
169
|
import "./chunk-DIB4GX3G.js";
|
|
174
170
|
import {
|
|
175
171
|
createAgentRunner,
|
|
@@ -177,7 +173,7 @@ import {
|
|
|
177
173
|
deleteMcpAuthSessionsForUserProvider,
|
|
178
174
|
deleteMcpServerSessionId,
|
|
179
175
|
deleteMcpStoredOAuthCredentials
|
|
180
|
-
} from "./chunk-
|
|
176
|
+
} from "./chunk-Q374NKGS.js";
|
|
181
177
|
import {
|
|
182
178
|
RetryableDeliveryError
|
|
183
179
|
} from "./chunk-RF6J3DIO.js";
|
|
@@ -185,7 +181,7 @@ import {
|
|
|
185
181
|
formatProviderLabel,
|
|
186
182
|
postSlackMessage,
|
|
187
183
|
startOAuthFlow
|
|
188
|
-
} from "./chunk-
|
|
184
|
+
} from "./chunk-665JOQEP.js";
|
|
189
185
|
import "./chunk-6ZWRNC4D.js";
|
|
190
186
|
import {
|
|
191
187
|
getExperimentalFeatures,
|
|
@@ -196,13 +192,15 @@ import {
|
|
|
196
192
|
collectAttachmentGarbage,
|
|
197
193
|
createSchedulerSqlStore,
|
|
198
194
|
findMatchingEventTasks,
|
|
195
|
+
getResourceEventCatalog,
|
|
199
196
|
logScheduledTaskRunSkipped,
|
|
200
197
|
requestAttachmentDeletion,
|
|
198
|
+
resourceEventGuidance,
|
|
201
199
|
scheduledTaskRunAttributes
|
|
202
|
-
} from "./chunk-
|
|
200
|
+
} from "./chunk-IPOB6IL5.js";
|
|
203
201
|
import {
|
|
204
202
|
parseSlackThreadId
|
|
205
|
-
} from "./chunk-
|
|
203
|
+
} from "./chunk-AJEZETLT.js";
|
|
206
204
|
import {
|
|
207
205
|
ConversationTurnBoundaryError,
|
|
208
206
|
CooperativeTurnYieldError,
|
|
@@ -254,12 +252,11 @@ import {
|
|
|
254
252
|
trimTrailingAssistantMessages,
|
|
255
253
|
turnHasReply,
|
|
256
254
|
upsertConversationMessage
|
|
257
|
-
} from "./chunk-
|
|
258
|
-
import "./chunk-3Y47VMHV.js";
|
|
255
|
+
} from "./chunk-64EGCW34.js";
|
|
259
256
|
import {
|
|
260
257
|
getSandboxResourceConfig,
|
|
261
258
|
setSandboxResourceConfig
|
|
262
|
-
} from "./chunk-
|
|
259
|
+
} from "./chunk-FNOLPLXJ.js";
|
|
263
260
|
import "./chunk-PDO5BLNM.js";
|
|
264
261
|
import "./chunk-UIE3R5XU.js";
|
|
265
262
|
import {
|
|
@@ -267,10 +264,13 @@ import {
|
|
|
267
264
|
bindEventTaskCredentialSubject,
|
|
268
265
|
bindScheduledTaskCredentialSubject,
|
|
269
266
|
bindSlackDirectCredentialSubject,
|
|
267
|
+
cancelSubscriptions,
|
|
270
268
|
createPluginLogger,
|
|
271
269
|
createPluginState,
|
|
272
270
|
createResourceEventTeamIdResolver,
|
|
271
|
+
deliverResourceEventSubscription,
|
|
273
272
|
downloadPrivateSlackFile,
|
|
273
|
+
findMatchingResourceEventSubscriptions,
|
|
274
274
|
getPluginApiRoutes,
|
|
275
275
|
getPluginRoutes,
|
|
276
276
|
getPlugins,
|
|
@@ -287,7 +287,8 @@ import {
|
|
|
287
287
|
verifyEventTaskCredentialSubject,
|
|
288
288
|
verifyScheduledTaskCredentialSubject,
|
|
289
289
|
verifySlackDirectCredentialSubject
|
|
290
|
-
} from "./chunk-
|
|
290
|
+
} from "./chunk-JIZ3RFER.js";
|
|
291
|
+
import "./chunk-3Y47VMHV.js";
|
|
291
292
|
import {
|
|
292
293
|
contextProvenance,
|
|
293
294
|
createSlackDestination,
|
|
@@ -300,21 +301,21 @@ import {
|
|
|
300
301
|
requireSlackDestination,
|
|
301
302
|
withConversationEventLock,
|
|
302
303
|
withConversationMutationLock
|
|
303
|
-
} from "./chunk-
|
|
304
|
+
} from "./chunk-JHCAX7XY.js";
|
|
304
305
|
import {
|
|
305
306
|
juniorAgentBindings,
|
|
306
307
|
juniorAgentInvocations,
|
|
307
308
|
juniorConversationEvents,
|
|
308
309
|
juniorConversations
|
|
309
|
-
} from "./chunk-
|
|
310
|
+
} from "./chunk-CUA5SZR5.js";
|
|
310
311
|
import {
|
|
311
312
|
sleep
|
|
312
|
-
} from "./chunk-
|
|
313
|
+
} from "./chunk-CNC65LIX.js";
|
|
313
314
|
import {
|
|
314
315
|
acquireActiveLock,
|
|
315
316
|
getStateAdapter,
|
|
316
317
|
withActiveLock
|
|
317
|
-
} from "./chunk-
|
|
318
|
+
} from "./chunk-B6IOTX7W.js";
|
|
318
319
|
import {
|
|
319
320
|
STANDARD_MODEL_PROFILE,
|
|
320
321
|
botConfig,
|
|
@@ -332,16 +333,16 @@ import {
|
|
|
332
333
|
modelIdForProfile,
|
|
333
334
|
setSlackReactionConfig,
|
|
334
335
|
standardModelId
|
|
335
|
-
} from "./chunk-
|
|
336
|
+
} from "./chunk-Z2YZ6QLG.js";
|
|
336
337
|
import {
|
|
337
338
|
juniorDestinations
|
|
338
339
|
} from "./chunk-VFUK3X5B.js";
|
|
339
|
-
import "./chunk-
|
|
340
|
-
import "./chunk-
|
|
340
|
+
import "./chunk-H7KTMGNI.js";
|
|
341
|
+
import "./chunk-B65VEBJV.js";
|
|
341
342
|
import {
|
|
342
343
|
pluginCatalogRuntime
|
|
343
|
-
} from "./chunk-
|
|
344
|
-
import "./chunk-
|
|
344
|
+
} from "./chunk-5JB5JJO5.js";
|
|
345
|
+
import "./chunk-CI4JX64I.js";
|
|
345
346
|
import {
|
|
346
347
|
credentialContextForActor
|
|
347
348
|
} from "./chunk-CGA4ERJ5.js";
|
|
@@ -373,7 +374,7 @@ import {
|
|
|
373
374
|
withContext,
|
|
374
375
|
withLogContext,
|
|
375
376
|
withSpan
|
|
376
|
-
} from "./chunk-
|
|
377
|
+
} from "./chunk-SBIQ5MZW.js";
|
|
377
378
|
import {
|
|
378
379
|
continueTrace
|
|
379
380
|
} from "./chunk-6GWA276C.js";
|
|
@@ -381,10 +382,10 @@ import "./chunk-OOUNJNMR.js";
|
|
|
381
382
|
import "./chunk-H4HBKISO.js";
|
|
382
383
|
import {
|
|
383
384
|
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
|
|
384
|
-
} from "./chunk-
|
|
385
|
+
} from "./chunk-KYHHJ6LS.js";
|
|
385
386
|
import {
|
|
386
387
|
JUNIOR_VERSION
|
|
387
|
-
} from "./chunk-
|
|
388
|
+
} from "./chunk-DVHYQDGM.js";
|
|
388
389
|
import "./chunk-MLKGABMK.js";
|
|
389
390
|
|
|
390
391
|
// src/app.ts
|
|
@@ -392,65 +393,139 @@ import { createRequire } from "module";
|
|
|
392
393
|
import { pathToFileURL } from "url";
|
|
393
394
|
import { Hono } from "hono";
|
|
394
395
|
|
|
395
|
-
// src/
|
|
396
|
-
import {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
var
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
var DISPATCH_SIGNATURE_HEADER = "x-junior-dispatch-signature";
|
|
403
|
-
var legacyDispatchCallbackSchema = z.object({
|
|
404
|
-
expectedVersion: z.number().int().positive(),
|
|
405
|
-
id: z.string().min(1)
|
|
406
|
-
}).strict();
|
|
407
|
-
function getDispatchSecret() {
|
|
408
|
-
return process.env.JUNIOR_SECRET?.trim() || void 0;
|
|
409
|
-
}
|
|
410
|
-
function buildSignedPayload(timestamp, body) {
|
|
411
|
-
return `${DISPATCH_HMAC_CONTEXT}:${timestamp}:${body}`;
|
|
412
|
-
}
|
|
413
|
-
function signBody(secret, timestamp, body) {
|
|
414
|
-
const digest = createHmac("sha256", secret).update(buildSignedPayload(timestamp, body)).digest("hex");
|
|
415
|
-
return `${DISPATCH_SIGNATURE_VERSION}=${digest}`;
|
|
416
|
-
}
|
|
417
|
-
function timingSafeMatch(expected, actual) {
|
|
418
|
-
const expectedBuffer = Buffer.from(expected);
|
|
419
|
-
const actualBuffer = Buffer.from(actual);
|
|
420
|
-
if (expectedBuffer.length !== actualBuffer.length) {
|
|
421
|
-
return false;
|
|
422
|
-
}
|
|
423
|
-
return timingSafeEqual(expectedBuffer, actualBuffer);
|
|
396
|
+
// src/handlers/heartbeat.ts
|
|
397
|
+
import { timingSafeEqual } from "crypto";
|
|
398
|
+
|
|
399
|
+
// src/chat/task-execution/heartbeat.ts
|
|
400
|
+
var DEFAULT_RECOVERY_LIMIT = 25;
|
|
401
|
+
function heartbeatIdempotencyKey(reason, conversationId, nowMs) {
|
|
402
|
+
return `heartbeat:${reason}:${conversationId}:${nowMs}`;
|
|
424
403
|
}
|
|
425
|
-
async function
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
if (!timestamp || !signature || !secret) {
|
|
430
|
-
return void 0;
|
|
431
|
-
}
|
|
432
|
-
const parsedTimestamp = Number.parseInt(timestamp, 10);
|
|
433
|
-
if (!Number.isFinite(parsedTimestamp) || Math.abs(Date.now() - parsedTimestamp) > DISPATCH_MAX_SKEW_MS) {
|
|
434
|
-
return void 0;
|
|
435
|
-
}
|
|
436
|
-
const body = await request.text();
|
|
437
|
-
const expectedSignature = signBody(secret, timestamp, body);
|
|
438
|
-
if (!timingSafeMatch(expectedSignature, signature)) {
|
|
439
|
-
return void 0;
|
|
404
|
+
async function recoverConversationWork(args) {
|
|
405
|
+
if (!getChatConfig().conversationWorkEnabled) {
|
|
406
|
+
logWarn("conversation.work.recovery.disabled");
|
|
407
|
+
return { expiredLeaseCount: 0, pendingCount: 0 };
|
|
440
408
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
|
|
409
|
+
const result = {
|
|
410
|
+
expiredLeaseCount: 0,
|
|
411
|
+
pendingCount: 0
|
|
412
|
+
};
|
|
413
|
+
const staleBeforeMs = args.nowMs - CONVERSATION_WORK_STALE_ENQUEUE_MS;
|
|
414
|
+
const ids = await listActiveConversationIds({
|
|
415
|
+
limit: args.limit ?? DEFAULT_RECOVERY_LIMIT,
|
|
416
|
+
staleBeforeMs,
|
|
417
|
+
state: args.state
|
|
418
|
+
});
|
|
419
|
+
for (const conversationId of ids) {
|
|
420
|
+
await withLogContext({ conversationId }, async () => {
|
|
421
|
+
let work;
|
|
422
|
+
try {
|
|
423
|
+
work = await getConversationWorkState({
|
|
424
|
+
conversationId,
|
|
425
|
+
state: args.state
|
|
426
|
+
});
|
|
427
|
+
} catch (error) {
|
|
428
|
+
logException(error, "conversation.work.recovery.failed");
|
|
429
|
+
if (isInvalidConversationRecordError(error)) {
|
|
430
|
+
await removeActiveConversation({
|
|
431
|
+
conversationId,
|
|
432
|
+
state: args.state
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
try {
|
|
438
|
+
if (!work) {
|
|
439
|
+
await removeActiveConversation({
|
|
440
|
+
conversationId,
|
|
441
|
+
state: args.state
|
|
442
|
+
});
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (work.execution.status === "idle") {
|
|
446
|
+
await removeActiveConversation({
|
|
447
|
+
conversationId,
|
|
448
|
+
state: args.state
|
|
449
|
+
});
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (work.execution.lease && work.execution.lease.expiresAtMs <= args.nowMs) {
|
|
453
|
+
const recovery = await clearExpiredConversationLease({
|
|
454
|
+
conversationId,
|
|
455
|
+
nowMs: args.nowMs,
|
|
456
|
+
state: args.state
|
|
457
|
+
});
|
|
458
|
+
if (recovery === "not_expired") {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
if (recovery === "stopped") {
|
|
462
|
+
logException(
|
|
463
|
+
new Error(
|
|
464
|
+
"Conversation work stopped after repeated failed attempts"
|
|
465
|
+
),
|
|
466
|
+
"conversation.work.retry.exhausted",
|
|
467
|
+
{
|
|
468
|
+
"app.run.id": work.execution.runId ?? "unknown",
|
|
469
|
+
"app.worker.last_progress_at_ms": work.execution.lastProgressAtMs ?? work.createdAtMs,
|
|
470
|
+
"app.worker.retry_count": (work.execution.retryCount ?? 0) + 1
|
|
471
|
+
}
|
|
472
|
+
);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const wake2 = await ensureConversationWake({
|
|
476
|
+
conversationId,
|
|
477
|
+
idempotencyKey: heartbeatIdempotencyKey(
|
|
478
|
+
"lease",
|
|
479
|
+
conversationId,
|
|
480
|
+
args.nowMs
|
|
481
|
+
),
|
|
482
|
+
nowMs: args.nowMs,
|
|
483
|
+
queue: args.queue,
|
|
484
|
+
replaceExistingWake: true,
|
|
485
|
+
state: args.state
|
|
486
|
+
});
|
|
487
|
+
if (wake2.status === "enqueued") {
|
|
488
|
+
result.expiredLeaseCount += 1;
|
|
489
|
+
logInfo("conversation.work.lease_expired.requeued");
|
|
490
|
+
}
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (work.execution.lease || !hasRunnableConversationWork(work)) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const wake = await ensureConversationWake({
|
|
497
|
+
conversationId,
|
|
498
|
+
idempotencyKey: heartbeatIdempotencyKey(
|
|
499
|
+
"pending",
|
|
500
|
+
conversationId,
|
|
501
|
+
args.nowMs
|
|
502
|
+
),
|
|
503
|
+
nowMs: args.nowMs,
|
|
504
|
+
queue: args.queue,
|
|
505
|
+
state: args.state
|
|
506
|
+
});
|
|
507
|
+
if (wake.status === "enqueued") {
|
|
508
|
+
result.pendingCount += 1;
|
|
509
|
+
logInfo("conversation.work.pending.requeued");
|
|
510
|
+
}
|
|
511
|
+
} catch (error) {
|
|
512
|
+
logException(error, "conversation.work.recovery.failed");
|
|
513
|
+
}
|
|
514
|
+
});
|
|
446
515
|
}
|
|
516
|
+
return result;
|
|
447
517
|
}
|
|
448
518
|
|
|
519
|
+
// src/chat/scheduled-tasks/heartbeat.ts
|
|
520
|
+
import {
|
|
521
|
+
createSlackSource
|
|
522
|
+
} from "@sentry/junior-plugin-api";
|
|
523
|
+
|
|
449
524
|
// src/chat/agent-dispatch/work.ts
|
|
450
|
-
import { z
|
|
451
|
-
var agentDispatchMailboxMetadataSchema =
|
|
452
|
-
dispatchId:
|
|
453
|
-
kind:
|
|
525
|
+
import { z } from "zod";
|
|
526
|
+
var agentDispatchMailboxMetadataSchema = z.object({
|
|
527
|
+
dispatchId: z.string().min(1),
|
|
528
|
+
kind: z.literal("agent_dispatch")
|
|
454
529
|
}).strict();
|
|
455
530
|
var AGENT_DISPATCH_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
456
531
|
function buildDispatchRoutingContext(dispatch2) {
|
|
@@ -494,7 +569,7 @@ function buildAgentDispatchInboundMessage(dispatch2, nowMs = Date.now()) {
|
|
|
494
569
|
}
|
|
495
570
|
async function enqueueAgentDispatch(dispatch2, options) {
|
|
496
571
|
const nowMs = options.nowMs ?? Date.now();
|
|
497
|
-
const claimedDispatch = await claimDispatchMailboxAppend(dispatch2.id
|
|
572
|
+
const claimedDispatch = await claimDispatchMailboxAppend(dispatch2.id);
|
|
498
573
|
if (!claimedDispatch) {
|
|
499
574
|
return;
|
|
500
575
|
}
|
|
@@ -574,22 +649,11 @@ async function resolveAgentDispatchId(context) {
|
|
|
574
649
|
);
|
|
575
650
|
}
|
|
576
651
|
const durableDispatchId = durableDispatchIds.values().next().value;
|
|
577
|
-
if (durableDispatchId) {
|
|
578
|
-
const dispatch3 = await getDispatchRecord(durableDispatchId);
|
|
579
|
-
if (dispatch3 && !isTerminalDispatchStatus(dispatch3.status)) {
|
|
580
|
-
return durableDispatchId;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
const prefix = "agent-dispatch:";
|
|
584
|
-
if (!context.conversationId.startsWith(prefix)) {
|
|
585
|
-
return void 0;
|
|
586
|
-
}
|
|
587
|
-
const dispatchId = context.conversationId.slice(prefix.length);
|
|
588
|
-
const dispatch2 = await getDispatchRecord(dispatchId);
|
|
589
|
-
if (!dispatch2) {
|
|
652
|
+
if (!durableDispatchId) {
|
|
590
653
|
return void 0;
|
|
591
654
|
}
|
|
592
|
-
|
|
655
|
+
const dispatch2 = await getDispatchRecord(durableDispatchId);
|
|
656
|
+
return dispatch2 && !isTerminalDispatchStatus(dispatch2.status) ? durableDispatchId : void 0;
|
|
593
657
|
}
|
|
594
658
|
function createAgentDispatchWorkRouter(options) {
|
|
595
659
|
return async (context) => {
|
|
@@ -803,161 +867,6 @@ function createAgentDispatchConversationWorker(options) {
|
|
|
803
867
|
};
|
|
804
868
|
}
|
|
805
869
|
|
|
806
|
-
// src/handlers/agent-dispatch.ts
|
|
807
|
-
async function POST(request, waitUntil, options) {
|
|
808
|
-
const payload = await verifyDispatchCallbackRequest(request);
|
|
809
|
-
if (!payload) {
|
|
810
|
-
return new Response("Unauthorized", { status: 401 });
|
|
811
|
-
}
|
|
812
|
-
waitUntil(
|
|
813
|
-
(async () => {
|
|
814
|
-
const dispatch2 = await getDispatchRecord(payload.id);
|
|
815
|
-
if (!dispatch2) {
|
|
816
|
-
throw new Error(`Dispatch record is missing for ${payload.id}`);
|
|
817
|
-
}
|
|
818
|
-
if (isTerminalDispatchStatus(dispatch2.status)) {
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
await enqueueAgentDispatch(dispatch2, {
|
|
822
|
-
queue: options.conversationWorkQueue
|
|
823
|
-
});
|
|
824
|
-
})().catch((error) => {
|
|
825
|
-
logException(error, "agent.dispatch.callback.failed", {
|
|
826
|
-
"app.dispatch.id": payload.id
|
|
827
|
-
});
|
|
828
|
-
})
|
|
829
|
-
);
|
|
830
|
-
return new Response("Accepted", { status: 202 });
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
// src/handlers/heartbeat.ts
|
|
834
|
-
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
835
|
-
|
|
836
|
-
// src/chat/task-execution/heartbeat.ts
|
|
837
|
-
var DEFAULT_RECOVERY_LIMIT = 25;
|
|
838
|
-
function heartbeatIdempotencyKey(reason, conversationId, nowMs) {
|
|
839
|
-
return `heartbeat:${reason}:${conversationId}:${nowMs}`;
|
|
840
|
-
}
|
|
841
|
-
async function recoverConversationWork(args) {
|
|
842
|
-
if (!getChatConfig().conversationWorkEnabled) {
|
|
843
|
-
logWarn("conversation.work.recovery.disabled");
|
|
844
|
-
return { expiredLeaseCount: 0, pendingCount: 0 };
|
|
845
|
-
}
|
|
846
|
-
const result = {
|
|
847
|
-
expiredLeaseCount: 0,
|
|
848
|
-
pendingCount: 0
|
|
849
|
-
};
|
|
850
|
-
const staleBeforeMs = args.nowMs - CONVERSATION_WORK_STALE_ENQUEUE_MS;
|
|
851
|
-
const ids = await listActiveConversationIds({
|
|
852
|
-
limit: args.limit ?? DEFAULT_RECOVERY_LIMIT,
|
|
853
|
-
staleBeforeMs,
|
|
854
|
-
state: args.state
|
|
855
|
-
});
|
|
856
|
-
for (const conversationId of ids) {
|
|
857
|
-
await withLogContext({ conversationId }, async () => {
|
|
858
|
-
let work;
|
|
859
|
-
try {
|
|
860
|
-
work = await getConversationWorkState({
|
|
861
|
-
conversationId,
|
|
862
|
-
state: args.state
|
|
863
|
-
});
|
|
864
|
-
} catch (error) {
|
|
865
|
-
logException(error, "conversation.work.recovery.failed");
|
|
866
|
-
if (isInvalidConversationRecordError(error)) {
|
|
867
|
-
await removeActiveConversation({
|
|
868
|
-
conversationId,
|
|
869
|
-
state: args.state
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
|
-
return;
|
|
873
|
-
}
|
|
874
|
-
try {
|
|
875
|
-
if (!work) {
|
|
876
|
-
await removeActiveConversation({
|
|
877
|
-
conversationId,
|
|
878
|
-
state: args.state
|
|
879
|
-
});
|
|
880
|
-
return;
|
|
881
|
-
}
|
|
882
|
-
if (work.execution.status === "idle") {
|
|
883
|
-
await removeActiveConversation({
|
|
884
|
-
conversationId,
|
|
885
|
-
state: args.state
|
|
886
|
-
});
|
|
887
|
-
return;
|
|
888
|
-
}
|
|
889
|
-
if (work.execution.lease && work.execution.lease.expiresAtMs <= args.nowMs) {
|
|
890
|
-
const recovery = await clearExpiredConversationLease({
|
|
891
|
-
conversationId,
|
|
892
|
-
nowMs: args.nowMs,
|
|
893
|
-
state: args.state
|
|
894
|
-
});
|
|
895
|
-
if (recovery === "not_expired") {
|
|
896
|
-
return;
|
|
897
|
-
}
|
|
898
|
-
if (recovery === "stopped") {
|
|
899
|
-
logException(
|
|
900
|
-
new Error(
|
|
901
|
-
"Conversation work stopped after repeated failed attempts"
|
|
902
|
-
),
|
|
903
|
-
"conversation.work.retry.exhausted",
|
|
904
|
-
{
|
|
905
|
-
"app.run.id": work.execution.runId ?? "unknown",
|
|
906
|
-
"app.worker.last_progress_at_ms": work.execution.lastProgressAtMs ?? work.createdAtMs,
|
|
907
|
-
"app.worker.retry_count": (work.execution.retryCount ?? 0) + 1
|
|
908
|
-
}
|
|
909
|
-
);
|
|
910
|
-
return;
|
|
911
|
-
}
|
|
912
|
-
const wake2 = await ensureConversationWake({
|
|
913
|
-
conversationId,
|
|
914
|
-
idempotencyKey: heartbeatIdempotencyKey(
|
|
915
|
-
"lease",
|
|
916
|
-
conversationId,
|
|
917
|
-
args.nowMs
|
|
918
|
-
),
|
|
919
|
-
nowMs: args.nowMs,
|
|
920
|
-
queue: args.queue,
|
|
921
|
-
replaceExistingWake: true,
|
|
922
|
-
state: args.state
|
|
923
|
-
});
|
|
924
|
-
if (wake2.status === "enqueued") {
|
|
925
|
-
result.expiredLeaseCount += 1;
|
|
926
|
-
logInfo("conversation.work.lease_expired.requeued");
|
|
927
|
-
}
|
|
928
|
-
return;
|
|
929
|
-
}
|
|
930
|
-
if (work.execution.lease || !hasRunnableConversationWork(work)) {
|
|
931
|
-
return;
|
|
932
|
-
}
|
|
933
|
-
const wake = await ensureConversationWake({
|
|
934
|
-
conversationId,
|
|
935
|
-
idempotencyKey: heartbeatIdempotencyKey(
|
|
936
|
-
"pending",
|
|
937
|
-
conversationId,
|
|
938
|
-
args.nowMs
|
|
939
|
-
),
|
|
940
|
-
nowMs: args.nowMs,
|
|
941
|
-
queue: args.queue,
|
|
942
|
-
state: args.state
|
|
943
|
-
});
|
|
944
|
-
if (wake.status === "enqueued") {
|
|
945
|
-
result.pendingCount += 1;
|
|
946
|
-
logInfo("conversation.work.pending.requeued");
|
|
947
|
-
}
|
|
948
|
-
} catch (error) {
|
|
949
|
-
logException(error, "conversation.work.recovery.failed");
|
|
950
|
-
}
|
|
951
|
-
});
|
|
952
|
-
}
|
|
953
|
-
return result;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
// src/chat/scheduled-tasks/heartbeat.ts
|
|
957
|
-
import {
|
|
958
|
-
createSlackSource
|
|
959
|
-
} from "@sentry/junior-plugin-api";
|
|
960
|
-
|
|
961
870
|
// src/chat/agent-dispatch/validation.ts
|
|
962
871
|
import {
|
|
963
872
|
dispatchOptionsSchema,
|
|
@@ -1725,7 +1634,7 @@ function verifyHeartbeatRequest(request) {
|
|
|
1725
1634
|
}
|
|
1726
1635
|
const actual = Buffer.from(authorization.slice("Bearer ".length));
|
|
1727
1636
|
const expected = Buffer.from(secret);
|
|
1728
|
-
return actual.length === expected.length &&
|
|
1637
|
+
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
1729
1638
|
}
|
|
1730
1639
|
async function GET4(request, waitUntil, options = {}) {
|
|
1731
1640
|
if (!verifyHeartbeatRequest(request)) {
|
|
@@ -1746,7 +1655,7 @@ async function GET4(request, waitUntil, options = {}) {
|
|
|
1746
1655
|
}
|
|
1747
1656
|
|
|
1748
1657
|
// src/handlers/retention.ts
|
|
1749
|
-
import { timingSafeEqual as
|
|
1658
|
+
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
1750
1659
|
|
|
1751
1660
|
// src/chat/conversations/sql/purge.ts
|
|
1752
1661
|
import { and, asc, eq as eq2, inArray, isNull, or, sql } from "drizzle-orm";
|
|
@@ -2044,7 +1953,7 @@ function verifyRetentionRequest(request) {
|
|
|
2044
1953
|
}
|
|
2045
1954
|
const actual = Buffer.from(authorization.slice("Bearer ".length));
|
|
2046
1955
|
const expected = Buffer.from(secret);
|
|
2047
|
-
return actual.length === expected.length &&
|
|
1956
|
+
return actual.length === expected.length && timingSafeEqual2(actual, expected);
|
|
2048
1957
|
}
|
|
2049
1958
|
async function GET5(request, options = {}) {
|
|
2050
1959
|
if (!verifyRetentionRequest(request)) {
|
|
@@ -2442,7 +2351,7 @@ import {
|
|
|
2442
2351
|
Message,
|
|
2443
2352
|
ThreadImpl
|
|
2444
2353
|
} from "chat";
|
|
2445
|
-
import { z as
|
|
2354
|
+
import { z as z2 } from "zod";
|
|
2446
2355
|
|
|
2447
2356
|
// src/chat/ingress/message-router.ts
|
|
2448
2357
|
function normalizeIncomingSlackThreadId(threadId, message) {
|
|
@@ -2633,17 +2542,17 @@ function stripLeadingSteeringOverride(text) {
|
|
|
2633
2542
|
}
|
|
2634
2543
|
|
|
2635
2544
|
// src/chat/task-execution/slack-work.ts
|
|
2636
|
-
var slackConversationRouteSchema =
|
|
2545
|
+
var slackConversationRouteSchema = z2.enum(["mention", "subscribed"]);
|
|
2637
2546
|
function hasSteeringOverride(text) {
|
|
2638
2547
|
return stripLeadingSteeringOverride(text) !== text;
|
|
2639
2548
|
}
|
|
2640
|
-
var serializedDateSchema =
|
|
2641
|
-
var mdastPointSchema =
|
|
2642
|
-
column:
|
|
2643
|
-
line:
|
|
2644
|
-
offset:
|
|
2549
|
+
var serializedDateSchema = z2.iso.datetime();
|
|
2550
|
+
var mdastPointSchema = z2.object({
|
|
2551
|
+
column: z2.number().int().positive(),
|
|
2552
|
+
line: z2.number().int().positive(),
|
|
2553
|
+
offset: z2.number().int().nonnegative().optional()
|
|
2645
2554
|
}).strict();
|
|
2646
|
-
var mdastPositionSchema =
|
|
2555
|
+
var mdastPositionSchema = z2.object({
|
|
2647
2556
|
end: mdastPointSchema,
|
|
2648
2557
|
start: mdastPointSchema
|
|
2649
2558
|
}).strict();
|
|
@@ -2755,7 +2664,7 @@ function isFormattedContentNode(value) {
|
|
|
2755
2664
|
return false;
|
|
2756
2665
|
}
|
|
2757
2666
|
}
|
|
2758
|
-
var formattedContentSchema =
|
|
2667
|
+
var formattedContentSchema = z2.custom(
|
|
2759
2668
|
(value) => {
|
|
2760
2669
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
2761
2670
|
return false;
|
|
@@ -2765,79 +2674,79 @@ var formattedContentSchema = z3.custom(
|
|
|
2765
2674
|
},
|
|
2766
2675
|
"must be a valid formatted-content root"
|
|
2767
2676
|
);
|
|
2768
|
-
var serializedMessageSchema =
|
|
2769
|
-
_type:
|
|
2770
|
-
attachments:
|
|
2771
|
-
|
|
2772
|
-
type:
|
|
2773
|
-
url:
|
|
2774
|
-
name:
|
|
2775
|
-
mimeType:
|
|
2776
|
-
size:
|
|
2777
|
-
width:
|
|
2778
|
-
height:
|
|
2779
|
-
fetchMetadata:
|
|
2677
|
+
var serializedMessageSchema = z2.object({
|
|
2678
|
+
_type: z2.literal("chat:Message"),
|
|
2679
|
+
attachments: z2.array(
|
|
2680
|
+
z2.object({
|
|
2681
|
+
type: z2.enum(["image", "file", "video", "audio"]),
|
|
2682
|
+
url: z2.string().optional(),
|
|
2683
|
+
name: z2.string().optional(),
|
|
2684
|
+
mimeType: z2.string().optional(),
|
|
2685
|
+
size: z2.number().finite().optional(),
|
|
2686
|
+
width: z2.number().finite().optional(),
|
|
2687
|
+
height: z2.number().finite().optional(),
|
|
2688
|
+
fetchMetadata: z2.record(z2.string(), z2.string()).optional()
|
|
2780
2689
|
}).strict()
|
|
2781
2690
|
),
|
|
2782
|
-
author:
|
|
2783
|
-
userId:
|
|
2784
|
-
userName:
|
|
2785
|
-
fullName:
|
|
2786
|
-
isBot:
|
|
2787
|
-
isMe:
|
|
2691
|
+
author: z2.object({
|
|
2692
|
+
userId: z2.string(),
|
|
2693
|
+
userName: z2.string(),
|
|
2694
|
+
fullName: z2.string(),
|
|
2695
|
+
isBot: z2.union([z2.boolean(), z2.literal("unknown")]),
|
|
2696
|
+
isMe: z2.boolean()
|
|
2788
2697
|
}).strict(),
|
|
2789
2698
|
formatted: formattedContentSchema,
|
|
2790
|
-
id:
|
|
2791
|
-
isMention:
|
|
2792
|
-
links:
|
|
2793
|
-
|
|
2794
|
-
url:
|
|
2795
|
-
title:
|
|
2796
|
-
description:
|
|
2797
|
-
imageUrl:
|
|
2798
|
-
siteName:
|
|
2699
|
+
id: z2.string().min(1),
|
|
2700
|
+
isMention: z2.boolean().optional(),
|
|
2701
|
+
links: z2.array(
|
|
2702
|
+
z2.object({
|
|
2703
|
+
url: z2.string(),
|
|
2704
|
+
title: z2.string().optional(),
|
|
2705
|
+
description: z2.string().optional(),
|
|
2706
|
+
imageUrl: z2.string().optional(),
|
|
2707
|
+
siteName: z2.string().optional()
|
|
2799
2708
|
}).strict()
|
|
2800
2709
|
).optional(),
|
|
2801
|
-
metadata:
|
|
2710
|
+
metadata: z2.object({
|
|
2802
2711
|
dateSent: serializedDateSchema,
|
|
2803
|
-
edited:
|
|
2712
|
+
edited: z2.boolean(),
|
|
2804
2713
|
editedAt: serializedDateSchema.optional()
|
|
2805
2714
|
}).strict(),
|
|
2806
|
-
raw:
|
|
2807
|
-
text:
|
|
2808
|
-
threadId:
|
|
2715
|
+
raw: z2.unknown(),
|
|
2716
|
+
text: z2.string(),
|
|
2717
|
+
threadId: z2.string().min(1)
|
|
2809
2718
|
}).strict();
|
|
2810
|
-
var serializedThreadSchema =
|
|
2811
|
-
_type:
|
|
2812
|
-
adapterName:
|
|
2813
|
-
channelId:
|
|
2814
|
-
channelVisibility:
|
|
2719
|
+
var serializedThreadSchema = z2.object({
|
|
2720
|
+
_type: z2.literal("chat:Thread"),
|
|
2721
|
+
adapterName: z2.literal("slack"),
|
|
2722
|
+
channelId: z2.string().min(1),
|
|
2723
|
+
channelVisibility: z2.enum(["private", "workspace", "external", "unknown"]).optional(),
|
|
2815
2724
|
currentMessage: serializedMessageSchema.optional(),
|
|
2816
|
-
id:
|
|
2817
|
-
isDM:
|
|
2725
|
+
id: z2.string().min(1),
|
|
2726
|
+
isDM: z2.boolean()
|
|
2818
2727
|
}).strict();
|
|
2819
|
-
var slackInstallationSchema =
|
|
2820
|
-
enterpriseId:
|
|
2821
|
-
isEnterpriseInstall:
|
|
2822
|
-
teamId:
|
|
2728
|
+
var slackInstallationSchema = z2.object({
|
|
2729
|
+
enterpriseId: z2.string().optional(),
|
|
2730
|
+
isEnterpriseInstall: z2.boolean().optional(),
|
|
2731
|
+
teamId: z2.string().optional()
|
|
2823
2732
|
}).strict();
|
|
2824
|
-
var slackConversationMessageMetadataBaseSchema =
|
|
2733
|
+
var slackConversationMessageMetadataBaseSchema = z2.object({
|
|
2825
2734
|
installation: slackInstallationSchema.optional(),
|
|
2826
2735
|
message: serializedMessageSchema,
|
|
2827
|
-
platform:
|
|
2736
|
+
platform: z2.literal("slack"),
|
|
2828
2737
|
route: slackConversationRouteSchema,
|
|
2829
2738
|
thread: serializedThreadSchema
|
|
2830
2739
|
});
|
|
2831
|
-
var slackConversationMessageMetadataSchema =
|
|
2740
|
+
var slackConversationMessageMetadataSchema = z2.union([
|
|
2832
2741
|
slackConversationMessageMetadataBaseSchema.strict(),
|
|
2833
2742
|
slackConversationMessageMetadataBaseSchema.extend({
|
|
2834
|
-
kind:
|
|
2835
|
-
resourceEvent:
|
|
2836
|
-
eventKey:
|
|
2837
|
-
eventType:
|
|
2838
|
-
namespace:
|
|
2839
|
-
identifier:
|
|
2840
|
-
subscriptionId:
|
|
2743
|
+
kind: z2.literal("resource_event"),
|
|
2744
|
+
resourceEvent: z2.object({
|
|
2745
|
+
eventKey: z2.string(),
|
|
2746
|
+
eventType: z2.string(),
|
|
2747
|
+
namespace: z2.string(),
|
|
2748
|
+
identifier: z2.string(),
|
|
2749
|
+
subscriptionId: z2.string()
|
|
2841
2750
|
}).strict()
|
|
2842
2751
|
}).strict()
|
|
2843
2752
|
]);
|
|
@@ -4125,7 +4034,7 @@ async function handleWebhookRequest(request, platform, run) {
|
|
|
4125
4034
|
}
|
|
4126
4035
|
|
|
4127
4036
|
// src/handlers/slack-webhook.ts
|
|
4128
|
-
async function
|
|
4037
|
+
async function POST(request, waitUntil, services) {
|
|
4129
4038
|
return handleWebhookRequest(
|
|
4130
4039
|
request,
|
|
4131
4040
|
"slack",
|
|
@@ -4302,7 +4211,7 @@ function registerVercelPluginTaskDevConsumer() {
|
|
|
4302
4211
|
}
|
|
4303
4212
|
|
|
4304
4213
|
// src/chat/services/subscribed-decision.ts
|
|
4305
|
-
import { z as
|
|
4214
|
+
import { z as z3 } from "zod";
|
|
4306
4215
|
|
|
4307
4216
|
// src/chat/services/subscribed-reply-router-policy.ts
|
|
4308
4217
|
function buildSubscribedReplyRouterPolicy(assistantName) {
|
|
@@ -4347,13 +4256,13 @@ Assess conversation floor ownership and whether the latest message continues wor
|
|
|
4347
4256
|
}
|
|
4348
4257
|
|
|
4349
4258
|
// src/chat/services/subscribed-decision.ts
|
|
4350
|
-
var replyDecisionSchema =
|
|
4351
|
-
should_reply:
|
|
4352
|
-
should_unsubscribe:
|
|
4259
|
+
var replyDecisionSchema = z3.object({
|
|
4260
|
+
should_reply: z3.boolean().describe("Whether Junior should respond to this thread message."),
|
|
4261
|
+
should_unsubscribe: z3.boolean().describe(
|
|
4353
4262
|
"Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
|
|
4354
4263
|
),
|
|
4355
|
-
confidence:
|
|
4356
|
-
reason:
|
|
4264
|
+
confidence: z3.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
|
|
4265
|
+
reason: z3.string().describe("Short reason for the decision; use an empty string if none.")
|
|
4357
4266
|
}).strict();
|
|
4358
4267
|
var ROUTER_CONFIDENCE_THRESHOLD = 0.7;
|
|
4359
4268
|
var ROUTER_CLASSIFIER_MAX_TOKENS = 400;
|
|
@@ -6059,11 +5968,11 @@ function getMessageTimestamp(message) {
|
|
|
6059
5968
|
}
|
|
6060
5969
|
|
|
6061
5970
|
// src/chat/slack/action-token.ts
|
|
6062
|
-
import { z as
|
|
6063
|
-
var slackActionTokenSchema =
|
|
6064
|
-
var slackMessageEnvelopeSchema =
|
|
6065
|
-
raw:
|
|
6066
|
-
action_token:
|
|
5971
|
+
import { z as z4 } from "zod";
|
|
5972
|
+
var slackActionTokenSchema = z4.string().trim().min(1).brand();
|
|
5973
|
+
var slackMessageEnvelopeSchema = z4.object({
|
|
5974
|
+
raw: z4.object({
|
|
5975
|
+
action_token: z4.unknown().optional()
|
|
6067
5976
|
}).optional()
|
|
6068
5977
|
});
|
|
6069
5978
|
function readSlackActionToken(message) {
|
|
@@ -8453,7 +8362,7 @@ function createConversationWork(options) {
|
|
|
8453
8362
|
getDispatchConversationId(dispatch2),
|
|
8454
8363
|
{
|
|
8455
8364
|
agentRunner: options.agentRunner,
|
|
8456
|
-
inputMessageIds:
|
|
8365
|
+
inputMessageIds: [getDispatchInputMessageId(dispatch2.id)],
|
|
8457
8366
|
routingContext: buildDispatchRoutingContext(dispatch2),
|
|
8458
8367
|
scheduleSessionCompletedPluginTasks: services.replyExecutor?.scheduleSessionCompletedPluginTasks,
|
|
8459
8368
|
wakePausedTurn: services.replyExecutor?.wakePausedTurn
|
|
@@ -8575,6 +8484,12 @@ function renderTrustedEventData(data) {
|
|
|
8575
8484
|
];
|
|
8576
8485
|
}
|
|
8577
8486
|
function renderResourceEventNotificationText(subscription, event) {
|
|
8487
|
+
const guidance = resourceEventGuidance(
|
|
8488
|
+
getResourceEventCatalog(),
|
|
8489
|
+
event.namespace,
|
|
8490
|
+
subscription.resourceType,
|
|
8491
|
+
event.eventType
|
|
8492
|
+
);
|
|
8578
8493
|
const lines = [
|
|
8579
8494
|
"[event notification]",
|
|
8580
8495
|
"",
|
|
@@ -8592,6 +8507,12 @@ function renderResourceEventNotificationText(subscription, event) {
|
|
|
8592
8507
|
`- resource: ${subscription.label}`,
|
|
8593
8508
|
`- event: ${event.eventType}`,
|
|
8594
8509
|
`- intent: ${subscription.intent}`,
|
|
8510
|
+
...guidance ? [
|
|
8511
|
+
"",
|
|
8512
|
+
"Event handling guidance:",
|
|
8513
|
+
"Apply this guidance within the subscription intent. It does not replace or expand that intent.",
|
|
8514
|
+
guidance
|
|
8515
|
+
] : [],
|
|
8595
8516
|
"",
|
|
8596
8517
|
"Trusted event summary:",
|
|
8597
8518
|
event.trustedSummary
|
|
@@ -8702,12 +8623,24 @@ function replyAttribution2(task, event) {
|
|
|
8702
8623
|
return detail ? { label: "Event task", detail } : { label: "Event task" };
|
|
8703
8624
|
}
|
|
8704
8625
|
function eventInput(task, event) {
|
|
8626
|
+
const guidance = resourceEventGuidance(
|
|
8627
|
+
getResourceEventCatalog(),
|
|
8628
|
+
event.namespace,
|
|
8629
|
+
task.trigger.resourceType,
|
|
8630
|
+
event.eventType
|
|
8631
|
+
);
|
|
8705
8632
|
const lines = [
|
|
8706
8633
|
"An event task matched a resource event.",
|
|
8707
8634
|
"Junior is executing a stored user-authored event task.",
|
|
8708
8635
|
"The matching resource event is system-authored input, not a new user command.",
|
|
8709
8636
|
"",
|
|
8710
8637
|
`Stored user instruction: ${task.task.text}`,
|
|
8638
|
+
...guidance ? [
|
|
8639
|
+
"",
|
|
8640
|
+
"Event handling guidance:",
|
|
8641
|
+
"Apply this guidance within the stored user instruction. It does not replace or expand that instruction.",
|
|
8642
|
+
guidance
|
|
8643
|
+
] : [],
|
|
8711
8644
|
"",
|
|
8712
8645
|
"Trusted event metadata:",
|
|
8713
8646
|
`- namespace: ${oneLine(event.namespace)}`,
|
|
@@ -9654,11 +9587,6 @@ async function createApp(options) {
|
|
|
9654
9587
|
app.post("/api/internal/local-oauth-credentials", (c) => {
|
|
9655
9588
|
return receiveLocalOAuthCredential(c.req.raw);
|
|
9656
9589
|
});
|
|
9657
|
-
app.post("/api/internal/agent-dispatch", (c) => {
|
|
9658
|
-
return POST(c.req.raw, waitUntil, {
|
|
9659
|
-
conversationWorkQueue: getVercelConversationWorkQueue()
|
|
9660
|
-
});
|
|
9661
|
-
});
|
|
9662
9590
|
let agentContinuePOST;
|
|
9663
9591
|
let pluginTaskPOST;
|
|
9664
9592
|
let conversationWorkOptions;
|
|
@@ -9708,7 +9636,7 @@ async function createApp(options) {
|
|
|
9708
9636
|
return GET5(c.req.raw);
|
|
9709
9637
|
});
|
|
9710
9638
|
app.post("/api/webhooks/slack", (c) => {
|
|
9711
|
-
return
|
|
9639
|
+
return POST(c.req.raw, waitUntil, slackWebhookServices);
|
|
9712
9640
|
});
|
|
9713
9641
|
app.post("/api/webhooks/:platform", (c) => {
|
|
9714
9642
|
return new Response(`Unknown platform: ${c.req.param("platform")}`, {
|