@sentry/junior 0.109.0 → 0.111.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-FHHVLNPA.js → agent-hooks-QQ2IWKOP.js} +12 -13
- package/dist/api/conversations/access.d.ts +9 -0
- package/dist/api/conversations/aggregate.d.ts +12 -1
- package/dist/api/conversations/archive.d.ts +3 -5
- package/dist/api/conversations/detail.d.ts +156 -7
- package/dist/api/conversations/events.d.ts +1 -1
- package/dist/api/conversations/list.d.ts +57 -6
- package/dist/api/conversations/projection.d.ts +6 -7
- package/dist/api/conversations/reporting.d.ts +10 -4
- package/dist/api/conversations/routes.d.ts +2 -1
- package/dist/api/conversations/shared.d.ts +1 -1
- package/dist/api/conversations/stats.d.ts +37 -6
- package/dist/api/conversations/stats.query.d.ts +1 -1
- package/dist/api/conversations/usage.d.ts +9 -0
- package/dist/api/http.d.ts +7 -0
- package/dist/api/locations/detail.d.ts +102 -6
- package/dist/api/locations/list.d.ts +43 -5
- package/dist/api/locations/query.d.ts +4 -2
- package/dist/api/locations/routes.d.ts +2 -1
- package/dist/api/people/list.d.ts +28 -6
- package/dist/api/people/list.query.d.ts +1 -1
- package/dist/api/people/profile.d.ts +96 -7
- package/dist/api/people/profile.query.d.ts +4 -2
- package/dist/api/people/routes.d.ts +2 -1
- package/dist/api/people/shared.d.ts +1219 -2
- package/dist/api/route.d.ts +18 -4
- package/dist/api/schema/common.d.ts +6 -0
- package/dist/api/{conversations/schema.d.ts → schema/conversation.d.ts} +31 -3
- package/dist/api/{locations/schema.d.ts → schema/location.d.ts} +5 -0
- package/dist/api/{people/schema.d.ts → schema/person.d.ts} +37 -45
- package/dist/api/schema.d.ts +8 -22
- package/dist/api/schema.js +10 -2
- package/dist/api.d.ts +5 -1
- package/dist/api.js +767 -384
- package/dist/app.js +591 -447
- package/dist/build/virtual-config.d.ts +2 -0
- package/dist/catalog-runtime-D22W6QEJ.js +16 -0
- package/dist/chat/agent/request.d.ts +3 -6
- package/dist/chat/agent/resume.d.ts +11 -12
- package/dist/chat/agent/sandbox.d.ts +36 -11
- package/dist/chat/agent/tools.d.ts +5 -8
- package/dist/chat/config.d.ts +8 -1
- package/dist/chat/conversations/history.d.ts +3 -0
- package/dist/chat/conversations/sql/privacy.d.ts +3 -15
- package/dist/chat/pi/messages.d.ts +2 -2
- package/dist/chat/pi/sdk.d.ts +1 -1
- package/dist/chat/pi/sql-model-usage.d.ts +4 -1
- package/dist/chat/plugins/agent-hooks.d.ts +2 -2
- package/dist/chat/runtime/agent-continue-runner.d.ts +7 -3
- package/dist/chat/runtime/slack-runtime.d.ts +1 -2
- package/dist/chat/runtime/thread-state.d.ts +3 -7
- package/dist/chat/runtime/turn-preparation.d.ts +2 -2
- package/dist/chat/sandbox/command-result.d.ts +91 -0
- package/dist/chat/sandbox/errors.d.ts +3 -1
- package/dist/chat/sandbox/ref.d.ts +5 -0
- package/dist/chat/sandbox/sandbox.d.ts +19 -46
- package/dist/chat/sandbox/session.d.ts +16 -20
- package/dist/chat/sandbox/skill-sync.d.ts +2 -2
- package/dist/chat/sandbox/workspace.d.ts +14 -12
- package/dist/chat/services/auth-pause.d.ts +4 -0
- package/dist/chat/services/context-compaction.d.ts +1 -0
- package/dist/chat/services/turn-result.d.ts +3 -4
- package/dist/chat/task-execution/queue-signing.d.ts +10 -8
- package/dist/chat/task-execution/queue.d.ts +9 -7
- package/dist/chat/task-execution/slack-work.d.ts +9 -7
- package/dist/chat/task-execution/state.d.ts +75 -22
- package/dist/chat/task-execution/store.d.ts +34 -3
- package/dist/chat/task-execution/worker.d.ts +0 -1
- package/dist/chat/tool-support/normalize-result.d.ts +2 -2
- package/dist/chat/tool-support/pi-tool-adapter.d.ts +2 -2
- package/dist/chat/tool-support/structured-result.d.ts +1 -2
- package/dist/chat/tools/sandbox/file-uploads.d.ts +1 -1
- package/dist/chat/{runtime → tools/sandbox}/generated-artifacts.d.ts +3 -3
- package/dist/chat/tools/types.d.ts +1 -1
- package/dist/chat/tools/web/fetch-content.d.ts +5 -0
- package/dist/chat/tools/web/image-generate.d.ts +2 -1
- package/dist/chat/tools/web/search.d.ts +1 -1
- package/dist/{chunk-CEA3A3UA.js → chunk-2ZTTXTSZ.js} +24 -1
- package/dist/{chunk-IVVGFRQQ.js → chunk-42WRQLJ6.js} +10 -38
- package/dist/{chunk-O3JMSZLI.js → chunk-6Y5L4BOM.js} +3 -5
- package/dist/{chunk-HO5NT6OE.js → chunk-B45FPP2A.js} +306 -31
- package/dist/{chunk-WHMOBKT7.js → chunk-BTRNMS6A.js} +2 -2
- package/dist/{chunk-PLB7MRCQ.js → chunk-C4MZ3GP5.js} +1 -1
- package/dist/{chunk-HHVY4SMP.js → chunk-FPK7XY3F.js} +98 -92
- package/dist/{chunk-RGX4V75M.js → chunk-IFAHK54X.js} +3 -3
- package/dist/{chunk-ISMWX44P.js → chunk-J7APPQIJ.js} +2 -2
- package/dist/{chunk-TMBRFULF.js → chunk-JQFJO5WH.js} +7 -1
- package/dist/{chunk-FWJRXN4F.js → chunk-L6JPKANW.js} +3 -139
- package/dist/{chunk-7Q6WCISF.js → chunk-MIAKQNYX.js} +43 -31
- package/dist/chunk-MPVES2IC.js +44 -0
- package/dist/{chunk-JNAVF45E.js → chunk-NQLWOTY4.js} +47 -19
- package/dist/{chunk-IXKSQGIO.js → chunk-OOLU34J4.js} +8860 -9137
- package/dist/{chunk-OUHNWH46.js → chunk-PYKKM4MM.js} +1 -1
- package/dist/{chunk-MXW4GL53.js → chunk-PZELBSHC.js} +8 -9
- package/dist/{chunk-QY636HZU.js → chunk-QQIVLZW4.js} +96 -17
- package/dist/{chunk-72OMGPDS.js → chunk-SL3ZKNLQ.js} +19 -18
- package/dist/{chunk-3SXUV423.js → chunk-WSRBFHPX.js} +1 -1
- package/dist/{chunk-TT6GMXNA.js → chunk-XQAYFRWT.js} +2 -2
- package/dist/{chunk-MGUMR35T.js → chunk-Z2W4SJZ7.js} +1 -1
- package/dist/{chunk-OCD3OZRK.js → chunk-Z4G3WCP3.js} +1 -1
- package/dist/{chunk-FENLIFJD.js → chunk-ZRZ4SVWG.js} +69 -10
- package/dist/cli/chat.js +23 -24
- package/dist/cli/check.js +8 -8
- package/dist/cli/plugins.js +15 -16
- package/dist/cli/snapshot-warmup.js +11 -11
- package/dist/cli/upgrade.js +9 -9
- package/dist/db/schema/conversations.d.ts +17 -0
- package/dist/db/schema.d.ts +17 -0
- package/dist/{db-V3NU72O2.js → db-WXQOQESG.js} +8 -9
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +15 -10
- package/dist/reporting-schema.d.ts +46 -0
- package/dist/{runner-JYBCQBLK.js → runner-4QY4XH4B.js} +23 -33
- package/dist/{skills-U6MDAST7.js → skills-P5MU4EBX.js} +8 -8
- package/dist/{validation-72N3JVRU.js → validation-PQF5OP6T.js} +8 -8
- package/dist/version.js +1 -1
- package/migrations/0007_thick_sugar_man.sql +23 -0
- package/migrations/meta/0007_snapshot.json +1013 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/dist/catalog-runtime-DMGJSLV2.js +0 -16
- package/dist/chunk-OB42YVAE.js +0 -16
- package/dist/chunk-SYAQIR5Z.js +0 -53
package/dist/app.js
CHANGED
|
@@ -6,21 +6,23 @@ import {
|
|
|
6
6
|
processPluginTask,
|
|
7
7
|
requireTurnFailureEventId,
|
|
8
8
|
scheduleSessionCompletedPluginTasks
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PZELBSHC.js";
|
|
10
10
|
import {
|
|
11
11
|
GET,
|
|
12
12
|
buildSentryConversationUrl,
|
|
13
13
|
conversationVisibilityFromSlackChannelType,
|
|
14
|
-
resolveRootVisibility,
|
|
15
14
|
resolveSlackChannelTypeFromMessage,
|
|
16
15
|
resolveSlackConversationContext
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-L6JPKANW.js";
|
|
17
|
+
import "./chunk-2ZTTXTSZ.js";
|
|
19
18
|
import {
|
|
19
|
+
ConversationQueueMessageRejectedError,
|
|
20
|
+
conversationQueueMessageSchema,
|
|
20
21
|
getVercelConversationWorkQueue,
|
|
22
|
+
isConversationQueueMessageRejectedError,
|
|
21
23
|
resolveConversationWorkQueueTopic,
|
|
22
24
|
verifyConversationQueueMessage
|
|
23
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-MIAKQNYX.js";
|
|
24
26
|
import {
|
|
25
27
|
PLUGIN_TASK_QUEUE_TOPIC,
|
|
26
28
|
createVercelQueueClient,
|
|
@@ -29,7 +31,7 @@ import {
|
|
|
29
31
|
import {
|
|
30
32
|
validatePluginEgressCredentialHooks,
|
|
31
33
|
validatePluginRegistrations
|
|
32
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-Z2W4SJZ7.js";
|
|
33
35
|
import {
|
|
34
36
|
defineJuniorPlugins,
|
|
35
37
|
pluginCatalogConfigFromEnv,
|
|
@@ -82,7 +84,7 @@ import {
|
|
|
82
84
|
splitSlackReplyText,
|
|
83
85
|
startOAuthFlow,
|
|
84
86
|
truncateStatusText
|
|
85
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-OOLU34J4.js";
|
|
86
88
|
import {
|
|
87
89
|
ConversationTurnBoundaryError,
|
|
88
90
|
CooperativeTurnYieldError,
|
|
@@ -141,8 +143,8 @@ import {
|
|
|
141
143
|
turnHasReply,
|
|
142
144
|
updateConversationStats,
|
|
143
145
|
upsertConversationMessage
|
|
144
|
-
} from "./chunk-
|
|
145
|
-
import "./chunk-
|
|
146
|
+
} from "./chunk-SL3ZKNLQ.js";
|
|
147
|
+
import "./chunk-B45FPP2A.js";
|
|
146
148
|
import "./chunk-MU6HHZEN.js";
|
|
147
149
|
import "./chunk-PDO5BLNM.js";
|
|
148
150
|
import "./chunk-UIE3R5XU.js";
|
|
@@ -161,12 +163,12 @@ import {
|
|
|
161
163
|
validatePlugins,
|
|
162
164
|
verifyScheduledTaskCredentialSubject,
|
|
163
165
|
verifySlackDirectCredentialSubject
|
|
164
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-QQIVLZW4.js";
|
|
165
167
|
import {
|
|
166
168
|
acquireActiveLock,
|
|
167
169
|
getDefaultRedisStateAdapterFor,
|
|
168
170
|
getStateAdapter
|
|
169
|
-
} from "./chunk-
|
|
171
|
+
} from "./chunk-PYKKM4MM.js";
|
|
170
172
|
import {
|
|
171
173
|
SlackActionError,
|
|
172
174
|
downloadPrivateSlackFile,
|
|
@@ -177,20 +179,25 @@ import {
|
|
|
177
179
|
normalizeSlackConversationId,
|
|
178
180
|
runWithSlackInstallationToken,
|
|
179
181
|
runWithWorkspaceTeamId
|
|
180
|
-
} from "./chunk-
|
|
182
|
+
} from "./chunk-IFAHK54X.js";
|
|
181
183
|
import {
|
|
182
184
|
contextProvenance,
|
|
185
|
+
createSlackDestination,
|
|
186
|
+
destinationKey,
|
|
183
187
|
getConversationEventStore,
|
|
184
188
|
getConversationStore,
|
|
185
189
|
getDb,
|
|
186
190
|
getSqlExecutor,
|
|
187
191
|
instructionProvenanceFor,
|
|
192
|
+
parseDestination,
|
|
193
|
+
requireSlackDestination,
|
|
194
|
+
sameDestination,
|
|
188
195
|
withConversationEventLock
|
|
189
|
-
} from "./chunk-
|
|
196
|
+
} from "./chunk-ZRZ4SVWG.js";
|
|
190
197
|
import {
|
|
191
198
|
juniorConversationEvents,
|
|
192
199
|
juniorConversations
|
|
193
|
-
} from "./chunk-
|
|
200
|
+
} from "./chunk-JQFJO5WH.js";
|
|
194
201
|
import {
|
|
195
202
|
sleep
|
|
196
203
|
} from "./chunk-4ZNGQH7C.js";
|
|
@@ -199,6 +206,7 @@ import {
|
|
|
199
206
|
botConfig,
|
|
200
207
|
completeObject,
|
|
201
208
|
completeText,
|
|
209
|
+
configureFunctionMaxDurationSeconds,
|
|
202
210
|
escapeXml,
|
|
203
211
|
getChatConfig,
|
|
204
212
|
getRuntimeMetadata,
|
|
@@ -214,7 +222,7 @@ import {
|
|
|
214
222
|
standardModelId,
|
|
215
223
|
stripRuntimeTurnContext,
|
|
216
224
|
trimTrailingAssistantMessages
|
|
217
|
-
} from "./chunk-
|
|
225
|
+
} from "./chunk-NQLWOTY4.js";
|
|
218
226
|
import {
|
|
219
227
|
juniorDestinations
|
|
220
228
|
} from "./chunk-VFUK3X5B.js";
|
|
@@ -223,26 +231,19 @@ import {
|
|
|
223
231
|
readSlackRawMessageContext,
|
|
224
232
|
resolveSlackChannelIdFromMessage,
|
|
225
233
|
resolveSlackChannelIdFromThreadId
|
|
226
|
-
} from "./chunk-
|
|
227
|
-
import {
|
|
228
|
-
createSlackDestination,
|
|
229
|
-
destinationKey,
|
|
230
|
-
parseDestination,
|
|
231
|
-
requireSlackDestination,
|
|
232
|
-
sameDestination
|
|
233
|
-
} from "./chunk-SYAQIR5Z.js";
|
|
234
|
+
} from "./chunk-6Y5L4BOM.js";
|
|
234
235
|
import {
|
|
235
236
|
discoverSkills
|
|
236
|
-
} from "./chunk-
|
|
237
|
+
} from "./chunk-BTRNMS6A.js";
|
|
237
238
|
import {
|
|
238
239
|
pluginCatalogRuntime
|
|
239
|
-
} from "./chunk-
|
|
240
|
+
} from "./chunk-WSRBFHPX.js";
|
|
240
241
|
import {
|
|
241
242
|
buildOAuthTokenRequest,
|
|
242
243
|
credentialSubjectSchema,
|
|
243
244
|
hasRequiredOAuthScope,
|
|
244
245
|
parseOAuthTokenResponse
|
|
245
|
-
} from "./chunk-
|
|
246
|
+
} from "./chunk-XQAYFRWT.js";
|
|
246
247
|
import {
|
|
247
248
|
createActor,
|
|
248
249
|
createSlackActor,
|
|
@@ -251,7 +252,7 @@ import {
|
|
|
251
252
|
isUserActor,
|
|
252
253
|
parseActorUserId,
|
|
253
254
|
parseStoredSlackActor
|
|
254
|
-
} from "./chunk-
|
|
255
|
+
} from "./chunk-C4MZ3GP5.js";
|
|
255
256
|
import {
|
|
256
257
|
buildTurnFailureResponse,
|
|
257
258
|
createChatSdkLogger,
|
|
@@ -267,12 +268,14 @@ import {
|
|
|
267
268
|
setTags,
|
|
268
269
|
withContext,
|
|
269
270
|
withSpan
|
|
270
|
-
} from "./chunk-
|
|
271
|
+
} from "./chunk-J7APPQIJ.js";
|
|
271
272
|
import {
|
|
272
273
|
isRecord,
|
|
274
|
+
parseSlackChannelId,
|
|
275
|
+
parseSlackMessageTs,
|
|
273
276
|
toOptionalNumber,
|
|
274
277
|
toOptionalString
|
|
275
|
-
} from "./chunk-
|
|
278
|
+
} from "./chunk-42WRQLJ6.js";
|
|
276
279
|
import {
|
|
277
280
|
continueTrace
|
|
278
281
|
} from "./chunk-6GWA276C.js";
|
|
@@ -281,13 +284,11 @@ import {
|
|
|
281
284
|
homeDir
|
|
282
285
|
} from "./chunk-3V7OFJZC.js";
|
|
283
286
|
import {
|
|
284
|
-
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
|
|
285
|
-
|
|
286
|
-
parseSlackMessageTs
|
|
287
|
-
} from "./chunk-IVVGFRQQ.js";
|
|
287
|
+
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
|
|
288
|
+
} from "./chunk-MPVES2IC.js";
|
|
288
289
|
import {
|
|
289
290
|
JUNIOR_VERSION
|
|
290
|
-
} from "./chunk-
|
|
291
|
+
} from "./chunk-Z4G3WCP3.js";
|
|
291
292
|
import "./chunk-MLKGABMK.js";
|
|
292
293
|
|
|
293
294
|
// src/app.ts
|
|
@@ -823,8 +824,7 @@ async function persistRuntimePatch(args) {
|
|
|
823
824
|
await persistThreadStateById(args.threadId, {
|
|
824
825
|
artifacts: args.artifacts,
|
|
825
826
|
conversation: args.conversation,
|
|
826
|
-
|
|
827
|
-
sandboxDependencyProfileHash: args.sandboxDependencyProfileHash
|
|
827
|
+
sandboxRef: args.sandboxRef
|
|
828
828
|
});
|
|
829
829
|
}
|
|
830
830
|
async function markDispatch(args) {
|
|
@@ -946,8 +946,7 @@ async function runAgentDispatchSlice(callback, deps) {
|
|
|
946
946
|
return;
|
|
947
947
|
}
|
|
948
948
|
let artifacts = coerceThreadArtifactsState(persisted);
|
|
949
|
-
let
|
|
950
|
-
let sandboxDependencyProfileHash = typeof persisted.app_sandbox_dependency_profile_hash === "string" ? persisted.app_sandbox_dependency_profile_hash : void 0;
|
|
949
|
+
let sandboxRef = getPersistedSandboxState(persisted);
|
|
951
950
|
const channelConfiguration = getChannelConfigurationServiceById(
|
|
952
951
|
dispatch.destination.channelId
|
|
953
952
|
);
|
|
@@ -1052,24 +1051,19 @@ async function runAgentDispatchSlice(callback, deps) {
|
|
|
1052
1051
|
},
|
|
1053
1052
|
state: {
|
|
1054
1053
|
artifactState: artifacts,
|
|
1055
|
-
|
|
1056
|
-
sandboxId,
|
|
1057
|
-
sandboxDependencyProfileHash
|
|
1058
|
-
}
|
|
1054
|
+
sandboxRef
|
|
1059
1055
|
},
|
|
1060
1056
|
delivery: {
|
|
1061
1057
|
onAssistantMessage: deliverAssistantMessage
|
|
1062
1058
|
},
|
|
1063
1059
|
durability: {
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
sandboxDependencyProfileHash = sandbox.sandboxDependencyProfileHash;
|
|
1060
|
+
onSandboxRefChanged: async (nextSandboxRef) => {
|
|
1061
|
+
sandboxRef = nextSandboxRef;
|
|
1067
1062
|
await persistRuntimePatch({
|
|
1068
1063
|
threadId: conversationId,
|
|
1069
1064
|
conversation,
|
|
1070
1065
|
artifacts,
|
|
1071
|
-
|
|
1072
|
-
sandboxDependencyProfileHash
|
|
1066
|
+
sandboxRef
|
|
1073
1067
|
});
|
|
1074
1068
|
},
|
|
1075
1069
|
onArtifactStateUpdated: async (nextArtifacts2) => {
|
|
@@ -1078,8 +1072,7 @@ async function runAgentDispatchSlice(callback, deps) {
|
|
|
1078
1072
|
threadId: conversationId,
|
|
1079
1073
|
conversation,
|
|
1080
1074
|
artifacts,
|
|
1081
|
-
|
|
1082
|
-
sandboxDependencyProfileHash
|
|
1075
|
+
sandboxRef
|
|
1083
1076
|
});
|
|
1084
1077
|
}
|
|
1085
1078
|
}
|
|
@@ -1141,8 +1134,7 @@ async function runAgentDispatchSlice(callback, deps) {
|
|
|
1141
1134
|
threadId: conversationId,
|
|
1142
1135
|
conversation,
|
|
1143
1136
|
artifacts: nextArtifacts,
|
|
1144
|
-
|
|
1145
|
-
sandboxDependencyProfileHash: reply.sandboxDependencyProfileHash ?? sandboxDependencyProfileHash
|
|
1137
|
+
sandboxRef: reply.sandboxRef ?? sandboxRef
|
|
1146
1138
|
});
|
|
1147
1139
|
});
|
|
1148
1140
|
statePersisted = true;
|
|
@@ -1313,8 +1305,10 @@ import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
|
1313
1305
|
|
|
1314
1306
|
// src/chat/task-execution/state.ts
|
|
1315
1307
|
import { randomUUID } from "crypto";
|
|
1308
|
+
import { destinationSchema as destinationSchema2 } from "@sentry/junior-plugin-api";
|
|
1309
|
+
import { z as z2 } from "zod";
|
|
1316
1310
|
var CONVERSATION_PREFIX = "junior:conversation";
|
|
1317
|
-
var CONVERSATION_SCHEMA_VERSION =
|
|
1311
|
+
var CONVERSATION_SCHEMA_VERSION = 2;
|
|
1318
1312
|
var CONVERSATION_ACTIVITY_INDEX_MAX_LENGTH = 1e4;
|
|
1319
1313
|
var CONVERSATION_INDEX_LOCK_TTL_MS = 1e4;
|
|
1320
1314
|
var CONVERSATION_INDEX_LOCK_WAIT_MS = 2e3;
|
|
@@ -1345,6 +1339,36 @@ var CONVERSATION_WORK_LEASE_TTL_MS = 9e4;
|
|
|
1345
1339
|
var CONVERSATION_WORK_CHECK_IN_INTERVAL_MS = 15e3;
|
|
1346
1340
|
var CONVERSATION_WORK_STALE_ENQUEUE_MS = 6e4;
|
|
1347
1341
|
var CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS = 5;
|
|
1342
|
+
var inboundMessageSourceSchema = z2.enum([
|
|
1343
|
+
"api",
|
|
1344
|
+
"internal",
|
|
1345
|
+
"local",
|
|
1346
|
+
"plugin",
|
|
1347
|
+
"resource_event",
|
|
1348
|
+
"scheduler",
|
|
1349
|
+
"slack"
|
|
1350
|
+
]);
|
|
1351
|
+
var agentInputSchema = z2.object({
|
|
1352
|
+
attachments: z2.array(z2.unknown()).optional(),
|
|
1353
|
+
authorId: z2.string().min(1).optional(),
|
|
1354
|
+
metadata: z2.record(z2.string(), z2.unknown()).optional(),
|
|
1355
|
+
text: z2.string()
|
|
1356
|
+
}).strict().refine((input) => input.text.trim() || input.attachments?.length, {
|
|
1357
|
+
message: "agent input requires text or attachments"
|
|
1358
|
+
});
|
|
1359
|
+
var inboundMessageDeliverySchema = z2.enum(["defer", "interrupt"]);
|
|
1360
|
+
var inboundMessageSchema = z2.object({
|
|
1361
|
+
attemptCount: z2.number().finite().optional(),
|
|
1362
|
+
conversationId: z2.string().refine((value) => value.trim().length > 0),
|
|
1363
|
+
createdAtMs: z2.number().finite(),
|
|
1364
|
+
delivery: inboundMessageDeliverySchema,
|
|
1365
|
+
destination: destinationSchema2,
|
|
1366
|
+
inboundMessageId: z2.string().refine((value) => value.trim().length > 0),
|
|
1367
|
+
injectedAtMs: z2.number().finite().optional(),
|
|
1368
|
+
input: agentInputSchema,
|
|
1369
|
+
receivedAtMs: z2.number().finite(),
|
|
1370
|
+
source: inboundMessageSourceSchema
|
|
1371
|
+
}).strict();
|
|
1348
1372
|
function conversationKey(conversationId) {
|
|
1349
1373
|
return `${CONVERSATION_PREFIX}:${conversationId}`;
|
|
1350
1374
|
}
|
|
@@ -1364,10 +1388,16 @@ function inputHasAttachments(input) {
|
|
|
1364
1388
|
return Array.isArray(input.attachments) && input.attachments.length > 0;
|
|
1365
1389
|
}
|
|
1366
1390
|
function upgradedPendingMessage(stored, duplicate) {
|
|
1367
|
-
|
|
1391
|
+
const promotesInterrupt = stored.delivery === "defer" && duplicate.delivery === "interrupt";
|
|
1392
|
+
const delivery = promotesInterrupt ? "interrupt" : stored.delivery;
|
|
1393
|
+
const input = promotesInterrupt ? {
|
|
1394
|
+
...duplicate.input,
|
|
1395
|
+
...inputHasAttachments(duplicate.input) || !inputHasAttachments(stored.input) ? {} : { attachments: stored.input.attachments }
|
|
1396
|
+
} : inputHasAttachments(duplicate.input) && !inputHasAttachments(stored.input) ? duplicate.input : stored.input;
|
|
1397
|
+
if (input === stored.input && delivery === stored.delivery) {
|
|
1368
1398
|
return stored;
|
|
1369
1399
|
}
|
|
1370
|
-
return { ...stored,
|
|
1400
|
+
return { ...stored, delivery, input };
|
|
1371
1401
|
}
|
|
1372
1402
|
function compareIndexDescending(left, right) {
|
|
1373
1403
|
return right.score - left.score || right.conversationId.localeCompare(left.conversationId);
|
|
@@ -1379,10 +1409,8 @@ function uniqueStrings(values) {
|
|
|
1379
1409
|
return [...new Set(values)];
|
|
1380
1410
|
}
|
|
1381
1411
|
function normalizeSource(value) {
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
}
|
|
1385
|
-
return void 0;
|
|
1412
|
+
const parsed = inboundMessageSourceSchema.safeParse(value);
|
|
1413
|
+
return parsed.success ? parsed.data : void 0;
|
|
1386
1414
|
}
|
|
1387
1415
|
function normalizeExecutionStatus(value) {
|
|
1388
1416
|
if (value === "awaiting_resume" || value === "failed" || value === "idle" || value === "pending" || value === "running") {
|
|
@@ -1390,53 +1418,13 @@ function normalizeExecutionStatus(value) {
|
|
|
1390
1418
|
}
|
|
1391
1419
|
return void 0;
|
|
1392
1420
|
}
|
|
1393
|
-
function
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
if (!isRecord(value)) {
|
|
1401
|
-
return void 0;
|
|
1402
|
-
}
|
|
1403
|
-
const text = typeof value.text === "string" ? value.text : void 0;
|
|
1404
|
-
const attachments = Array.isArray(value.attachments) ? [...value.attachments] : void 0;
|
|
1405
|
-
if (text === void 0 || !text.trim() && !attachments?.length) {
|
|
1406
|
-
return void 0;
|
|
1407
|
-
}
|
|
1408
|
-
return {
|
|
1409
|
-
text,
|
|
1410
|
-
authorId: toOptionalString(value.authorId),
|
|
1411
|
-
attachments,
|
|
1412
|
-
metadata: normalizeMetadata2(value.metadata)
|
|
1413
|
-
};
|
|
1414
|
-
}
|
|
1415
|
-
function normalizeMessage(value) {
|
|
1416
|
-
if (!isRecord(value)) {
|
|
1417
|
-
return void 0;
|
|
1418
|
-
}
|
|
1419
|
-
const conversationId = toOptionalString(value.conversationId);
|
|
1420
|
-
const inboundMessageId = toOptionalString(value.inboundMessageId);
|
|
1421
|
-
const source = normalizeSource(value.source);
|
|
1422
|
-
const destination = parseDestination(value.destination);
|
|
1423
|
-
const createdAtMs = toOptionalNumber(value.createdAtMs);
|
|
1424
|
-
const receivedAtMs = toOptionalNumber(value.receivedAtMs);
|
|
1425
|
-
const input = normalizeInput(value.input);
|
|
1426
|
-
if (!conversationId || !destination || !inboundMessageId || !source || typeof createdAtMs !== "number" || typeof receivedAtMs !== "number" || !input) {
|
|
1427
|
-
return void 0;
|
|
1428
|
-
}
|
|
1429
|
-
return {
|
|
1430
|
-
conversationId,
|
|
1431
|
-
destination,
|
|
1432
|
-
inboundMessageId,
|
|
1433
|
-
source,
|
|
1434
|
-
createdAtMs,
|
|
1435
|
-
receivedAtMs,
|
|
1436
|
-
input,
|
|
1437
|
-
injectedAtMs: toOptionalNumber(value.injectedAtMs),
|
|
1438
|
-
attemptCount: toOptionalNumber(value.attemptCount)
|
|
1439
|
-
};
|
|
1421
|
+
function normalizeMessage(value, schemaVersion) {
|
|
1422
|
+
const candidate = schemaVersion === 1 && isRecord(value) && value.delivery === void 0 ? {
|
|
1423
|
+
...value,
|
|
1424
|
+
delivery: "defer"
|
|
1425
|
+
} : value;
|
|
1426
|
+
const parsed = inboundMessageSchema.safeParse(candidate);
|
|
1427
|
+
return parsed.success ? parsed.data : void 0;
|
|
1440
1428
|
}
|
|
1441
1429
|
function isFinalAttempt(message) {
|
|
1442
1430
|
return (message.attemptCount ?? 0) >= CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS - 1;
|
|
@@ -1462,7 +1450,7 @@ function normalizeLease(value) {
|
|
|
1462
1450
|
expiresAtMs
|
|
1463
1451
|
};
|
|
1464
1452
|
}
|
|
1465
|
-
function normalizeExecution(conversationId, value) {
|
|
1453
|
+
function normalizeExecution(conversationId, value, schemaVersion) {
|
|
1466
1454
|
if (!isRecord(value)) {
|
|
1467
1455
|
return void 0;
|
|
1468
1456
|
}
|
|
@@ -1470,7 +1458,20 @@ function normalizeExecution(conversationId, value) {
|
|
|
1470
1458
|
if (!status) {
|
|
1471
1459
|
return void 0;
|
|
1472
1460
|
}
|
|
1473
|
-
const pendingMessages2 =
|
|
1461
|
+
const pendingMessages2 = [];
|
|
1462
|
+
if (Array.isArray(value.pendingMessages)) {
|
|
1463
|
+
for (const rawMessage of value.pendingMessages) {
|
|
1464
|
+
const message = normalizeMessage(rawMessage, schemaVersion);
|
|
1465
|
+
if (!message || message.conversationId !== conversationId) {
|
|
1466
|
+
return void 0;
|
|
1467
|
+
}
|
|
1468
|
+
if (message.injectedAtMs !== void 0) {
|
|
1469
|
+
continue;
|
|
1470
|
+
}
|
|
1471
|
+
pendingMessages2.push(message);
|
|
1472
|
+
}
|
|
1473
|
+
pendingMessages2.sort(compareMessages);
|
|
1474
|
+
}
|
|
1474
1475
|
const inboundMessageIds = Array.isArray(value.inboundMessageIds) ? uniqueStrings(
|
|
1475
1476
|
value.inboundMessageIds.map((id) => typeof id === "string" ? id : void 0).filter((id) => Boolean(id))
|
|
1476
1477
|
) : [];
|
|
@@ -1492,14 +1493,19 @@ function normalizeExecution(conversationId, value) {
|
|
|
1492
1493
|
};
|
|
1493
1494
|
}
|
|
1494
1495
|
function normalizeConversation(conversationId, value) {
|
|
1495
|
-
if (!isRecord(value) || value.schemaVersion !== CONVERSATION_SCHEMA_VERSION) {
|
|
1496
|
+
if (!isRecord(value) || value.schemaVersion !== 1 && value.schemaVersion !== CONVERSATION_SCHEMA_VERSION) {
|
|
1496
1497
|
return void 0;
|
|
1497
1498
|
}
|
|
1499
|
+
const schemaVersion = value.schemaVersion;
|
|
1498
1500
|
const storedConversationId = toOptionalString(value.conversationId);
|
|
1499
1501
|
const createdAtMs = toOptionalNumber(value.createdAtMs);
|
|
1500
1502
|
const lastActivityAtMs = toOptionalNumber(value.lastActivityAtMs);
|
|
1501
1503
|
const updatedAtMs = toOptionalNumber(value.updatedAtMs);
|
|
1502
|
-
const execution = normalizeExecution(
|
|
1504
|
+
const execution = normalizeExecution(
|
|
1505
|
+
conversationId,
|
|
1506
|
+
value.execution,
|
|
1507
|
+
schemaVersion
|
|
1508
|
+
);
|
|
1503
1509
|
const destination = value.destination === void 0 ? void 0 : parseDestination(value.destination);
|
|
1504
1510
|
if (storedConversationId !== conversationId || typeof createdAtMs !== "number" || typeof lastActivityAtMs !== "number" || typeof updatedAtMs !== "number" || !execution || value.destination !== void 0 && !destination) {
|
|
1505
1511
|
return void 0;
|
|
@@ -2107,7 +2113,7 @@ async function startConversationWork(args) {
|
|
|
2107
2113
|
{
|
|
2108
2114
|
...current.execution,
|
|
2109
2115
|
lease,
|
|
2110
|
-
status: "running",
|
|
2116
|
+
status: current.execution.status === "awaiting_resume" ? "awaiting_resume" : "running",
|
|
2111
2117
|
runId: current.execution.runId ?? randomUUID(),
|
|
2112
2118
|
lastEnqueuedAtMs: void 0
|
|
2113
2119
|
},
|
|
@@ -2159,22 +2165,25 @@ async function drainConversationMailbox(args) {
|
|
|
2159
2165
|
return pendingMessages(current);
|
|
2160
2166
|
});
|
|
2161
2167
|
if (pending.length === 0) {
|
|
2162
|
-
return [];
|
|
2168
|
+
return { changed: false, messages: [] };
|
|
2163
2169
|
}
|
|
2164
|
-
const
|
|
2170
|
+
const result = await args.handle(pending);
|
|
2165
2171
|
const pendingIds = new Set(
|
|
2166
2172
|
pending.map((message) => message.inboundMessageId)
|
|
2167
2173
|
);
|
|
2168
|
-
|
|
2174
|
+
const acknowledgedIds = new Set(
|
|
2175
|
+
result ?? pending.map((message) => message.inboundMessageId)
|
|
2176
|
+
);
|
|
2177
|
+
for (const inboundMessageId of acknowledgedIds) {
|
|
2169
2178
|
if (!pendingIds.has(inboundMessageId)) {
|
|
2170
2179
|
throw new Error(
|
|
2171
|
-
`Conversation mailbox
|
|
2180
|
+
`Conversation mailbox drain result is not pending for ${args.conversationId}`
|
|
2172
2181
|
);
|
|
2173
2182
|
}
|
|
2174
2183
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2184
|
+
if (acknowledgedIds.size === 0) {
|
|
2185
|
+
return { changed: false, messages: [] };
|
|
2186
|
+
}
|
|
2178
2187
|
await withConversationMutation(args, async (state, lock) => {
|
|
2179
2188
|
const current = await readConversation(state, args.conversationId);
|
|
2180
2189
|
if (!current || current.execution.lease?.token !== args.leaseToken) {
|
|
@@ -2183,7 +2192,7 @@ async function drainConversationMailbox(args) {
|
|
|
2183
2192
|
);
|
|
2184
2193
|
}
|
|
2185
2194
|
const pendingMessages2 = current.execution.pendingMessages.filter(
|
|
2186
|
-
(message) => !
|
|
2195
|
+
(message) => !acknowledgedIds.has(message.inboundMessageId)
|
|
2187
2196
|
);
|
|
2188
2197
|
await writeConversation(
|
|
2189
2198
|
state,
|
|
@@ -2199,7 +2208,12 @@ async function drainConversationMailbox(args) {
|
|
|
2199
2208
|
)
|
|
2200
2209
|
);
|
|
2201
2210
|
});
|
|
2202
|
-
return
|
|
2211
|
+
return {
|
|
2212
|
+
changed: true,
|
|
2213
|
+
messages: pending.filter(
|
|
2214
|
+
(message) => acknowledgedIds.has(message.inboundMessageId)
|
|
2215
|
+
)
|
|
2216
|
+
};
|
|
2203
2217
|
}
|
|
2204
2218
|
async function ackMessages(args) {
|
|
2205
2219
|
const nowMs = args.nowMs ?? now();
|
|
@@ -2260,6 +2274,28 @@ async function requestConversationContinuation(args) {
|
|
|
2260
2274
|
return true;
|
|
2261
2275
|
});
|
|
2262
2276
|
}
|
|
2277
|
+
async function beginConversationResume(args) {
|
|
2278
|
+
const nowMs = args.nowMs ?? now();
|
|
2279
|
+
return await withConversationMutation(args, async (state, lock) => {
|
|
2280
|
+
const current = await readConversation(state, args.conversationId);
|
|
2281
|
+
if (!current || current.execution.lease?.token !== args.leaseToken || current.execution.status !== "awaiting_resume") {
|
|
2282
|
+
return false;
|
|
2283
|
+
}
|
|
2284
|
+
await writeConversation(
|
|
2285
|
+
state,
|
|
2286
|
+
lock,
|
|
2287
|
+
withExecutionUpdate(
|
|
2288
|
+
current,
|
|
2289
|
+
{
|
|
2290
|
+
...current.execution,
|
|
2291
|
+
status: "running"
|
|
2292
|
+
},
|
|
2293
|
+
nowMs
|
|
2294
|
+
)
|
|
2295
|
+
);
|
|
2296
|
+
return true;
|
|
2297
|
+
});
|
|
2298
|
+
}
|
|
2263
2299
|
async function releaseConversationWork(args) {
|
|
2264
2300
|
const nowMs = args.nowMs ?? now();
|
|
2265
2301
|
return await withConversationMutation(args, async (state, lock) => {
|
|
@@ -2301,7 +2337,7 @@ async function completeConversationWork(args) {
|
|
|
2301
2337
|
{
|
|
2302
2338
|
...current.execution,
|
|
2303
2339
|
lease: void 0,
|
|
2304
|
-
status:
|
|
2340
|
+
status: needsRun ? "awaiting_resume" : hasPending ? "pending" : "idle",
|
|
2305
2341
|
runId: runnable ? current.execution.runId : void 0
|
|
2306
2342
|
},
|
|
2307
2343
|
nowMs
|
|
@@ -2410,7 +2446,7 @@ async function clearExpiredConversationLease(args) {
|
|
|
2410
2446
|
{
|
|
2411
2447
|
...current.execution,
|
|
2412
2448
|
lease: void 0,
|
|
2413
|
-
status: "
|
|
2449
|
+
status: "awaiting_resume"
|
|
2414
2450
|
},
|
|
2415
2451
|
nowMs
|
|
2416
2452
|
)
|
|
@@ -2501,13 +2537,15 @@ async function ensureConversationWake(args) {
|
|
|
2501
2537
|
if (!conversation.destination) {
|
|
2502
2538
|
return { status: "no_work" };
|
|
2503
2539
|
}
|
|
2540
|
+
if (args.replaceExistingWake !== true && conversation.execution.lease && conversation.execution.lease.expiresAtMs > nowMs) {
|
|
2541
|
+
return { status: "lease_active" };
|
|
2542
|
+
}
|
|
2504
2543
|
if (args.replaceExistingWake !== true && hasRecentEnqueueMarker(conversation, nowMs)) {
|
|
2505
2544
|
return { status: "already_enqueued" };
|
|
2506
2545
|
}
|
|
2507
2546
|
const queueResult = await args.queue.send(
|
|
2508
2547
|
{
|
|
2509
|
-
conversationId: args.conversationId
|
|
2510
|
-
destination: conversation.destination
|
|
2548
|
+
conversationId: args.conversationId
|
|
2511
2549
|
},
|
|
2512
2550
|
{
|
|
2513
2551
|
delayMs: args.delayMs,
|
|
@@ -2613,10 +2651,10 @@ async function checkInConversationWork2(args) {
|
|
|
2613
2651
|
}
|
|
2614
2652
|
async function drainConversationMailbox2(args) {
|
|
2615
2653
|
const result = await drainConversationMailbox(args);
|
|
2616
|
-
if (result.
|
|
2654
|
+
if (result.changed) {
|
|
2617
2655
|
await recordExecutionMetadata(args);
|
|
2618
2656
|
}
|
|
2619
|
-
return result;
|
|
2657
|
+
return result.messages;
|
|
2620
2658
|
}
|
|
2621
2659
|
async function ackMessages2(args) {
|
|
2622
2660
|
const result = await ackMessages(args);
|
|
@@ -2628,6 +2666,13 @@ async function requestConversationContinuation2(args) {
|
|
|
2628
2666
|
await recordExecutionMetadata(args);
|
|
2629
2667
|
return result;
|
|
2630
2668
|
}
|
|
2669
|
+
async function beginConversationResume2(args) {
|
|
2670
|
+
const result = await beginConversationResume(args);
|
|
2671
|
+
if (result) {
|
|
2672
|
+
await recordExecutionMetadata(args);
|
|
2673
|
+
}
|
|
2674
|
+
return result;
|
|
2675
|
+
}
|
|
2631
2676
|
async function releaseConversationWork2(args) {
|
|
2632
2677
|
const result = await releaseConversationWork(args);
|
|
2633
2678
|
await recordExecutionMetadata(args);
|
|
@@ -3184,7 +3229,47 @@ async function GET2(request, waitUntil, options = {}) {
|
|
|
3184
3229
|
import { timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
3185
3230
|
|
|
3186
3231
|
// src/chat/conversations/sql/purge.ts
|
|
3187
|
-
import { and, asc, eq, inArray, isNull, sql } from "drizzle-orm";
|
|
3232
|
+
import { and, asc, eq as eq2, inArray, isNull, sql } from "drizzle-orm";
|
|
3233
|
+
|
|
3234
|
+
// src/chat/conversations/sql/privacy.ts
|
|
3235
|
+
import { eq } from "drizzle-orm";
|
|
3236
|
+
import { alias } from "drizzle-orm/pg-core";
|
|
3237
|
+
var privacyRoot = alias(juniorConversations, "privacy_root");
|
|
3238
|
+
async function readRootCandidate(executor, conversationId) {
|
|
3239
|
+
const rows = await executor.db().select({
|
|
3240
|
+
requestedConversationId: juniorConversations.conversationId,
|
|
3241
|
+
requestedParentConversationId: juniorConversations.parentConversationId,
|
|
3242
|
+
requestedRootConversationId: juniorConversations.rootConversationId,
|
|
3243
|
+
rootConversationId: privacyRoot.conversationId,
|
|
3244
|
+
rootDestinationId: privacyRoot.destinationId,
|
|
3245
|
+
rootParentConversationId: privacyRoot.parentConversationId,
|
|
3246
|
+
rootRootConversationId: privacyRoot.rootConversationId
|
|
3247
|
+
}).from(juniorConversations).leftJoin(
|
|
3248
|
+
privacyRoot,
|
|
3249
|
+
eq(privacyRoot.conversationId, juniorConversations.rootConversationId)
|
|
3250
|
+
).where(eq(juniorConversations.conversationId, conversationId));
|
|
3251
|
+
const row = rows[0];
|
|
3252
|
+
return row?.requestedRootConversationId !== null && (row?.requestedParentConversationId !== null || row?.requestedRootConversationId === row?.requestedConversationId) && row?.rootConversationId === row.requestedRootConversationId && row.rootRootConversationId === row.rootConversationId && row.rootParentConversationId === null && row.rootDestinationId !== null ? {
|
|
3253
|
+
destinationId: row.rootDestinationId,
|
|
3254
|
+
rootConversationId: row.rootConversationId
|
|
3255
|
+
} : void 0;
|
|
3256
|
+
}
|
|
3257
|
+
async function readCandidateVisibility(executor, candidate) {
|
|
3258
|
+
const destinations = await executor.db().select({ visibility: juniorDestinations.visibility }).from(juniorDestinations).where(eq(juniorDestinations.id, candidate.destinationId)).for("share");
|
|
3259
|
+
return {
|
|
3260
|
+
rootConversationId: candidate.rootConversationId,
|
|
3261
|
+
visibility: destinations[0]?.visibility ?? null
|
|
3262
|
+
};
|
|
3263
|
+
}
|
|
3264
|
+
async function resolveRootVisibility(executor, conversationId) {
|
|
3265
|
+
const candidate = await readRootCandidate(executor, conversationId);
|
|
3266
|
+
if (!candidate) {
|
|
3267
|
+
return { rootConversationId: conversationId, visibility: null };
|
|
3268
|
+
}
|
|
3269
|
+
return readCandidateVisibility(executor, candidate);
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
// src/chat/conversations/sql/purge.ts
|
|
3188
3273
|
async function discoverConversationTree(executor, root) {
|
|
3189
3274
|
const all = /* @__PURE__ */ new Map([
|
|
3190
3275
|
[root.conversationId, root]
|
|
@@ -3253,7 +3338,7 @@ async function selectExpiredRoots(executor, args) {
|
|
|
3253
3338
|
visibility: juniorDestinations.visibility
|
|
3254
3339
|
}).from(juniorConversations).leftJoin(
|
|
3255
3340
|
juniorDestinations,
|
|
3256
|
-
|
|
3341
|
+
eq2(juniorDestinations.id, juniorConversations.destinationId)
|
|
3257
3342
|
).where(
|
|
3258
3343
|
and(
|
|
3259
3344
|
isNull(juniorConversations.parentConversationId),
|
|
@@ -3274,7 +3359,7 @@ async function purgeConversationTree(executor, args) {
|
|
|
3274
3359
|
const initialRoots = await executor.db().select({
|
|
3275
3360
|
conversationId: juniorConversations.conversationId,
|
|
3276
3361
|
parentConversationId: juniorConversations.parentConversationId
|
|
3277
|
-
}).from(juniorConversations).where(
|
|
3362
|
+
}).from(juniorConversations).where(eq2(juniorConversations.conversationId, args.rootConversationId));
|
|
3278
3363
|
const initialRoot = initialRoots[0];
|
|
3279
3364
|
if (!initialRoot || args.retention && initialRoot.parentConversationId !== null) {
|
|
3280
3365
|
return { purged: false, conversations: 0 };
|
|
@@ -3296,14 +3381,14 @@ async function purgeConversationTree(executor, args) {
|
|
|
3296
3381
|
destinationId: juniorConversations.destinationId,
|
|
3297
3382
|
parentConversationId: juniorConversations.parentConversationId
|
|
3298
3383
|
}).from(juniorConversations).where(
|
|
3299
|
-
|
|
3384
|
+
eq2(juniorConversations.conversationId, args.rootConversationId)
|
|
3300
3385
|
).for("update");
|
|
3301
3386
|
const root = roots[0];
|
|
3302
3387
|
if (!root || args.retention && root.parentConversationId !== null) {
|
|
3303
3388
|
return { purged: false, conversations: 0 };
|
|
3304
3389
|
}
|
|
3305
3390
|
const resolvedScrubMetadata = args.scrubMetadataFromRootVisibility ? (await resolveRootVisibility(executor, args.rootConversationId)).visibility !== "public" : args.scrubMetadata;
|
|
3306
|
-
const destinations = root.destinationId ? await executor.db().select({ visibility: juniorDestinations.visibility }).from(juniorDestinations).where(
|
|
3391
|
+
const destinations = root.destinationId ? await executor.db().select({ visibility: juniorDestinations.visibility }).from(juniorDestinations).where(eq2(juniorDestinations.id, root.destinationId)).for("share") : [];
|
|
3307
3392
|
const isPublic = destinations[0]?.visibility === "public";
|
|
3308
3393
|
const ids = tree.map((conversation) => conversation.conversationId);
|
|
3309
3394
|
if (args.retention) {
|
|
@@ -4274,12 +4359,11 @@ function createResumeReplyContext(args, statusSession, delivery) {
|
|
|
4274
4359
|
delivery,
|
|
4275
4360
|
durability: {
|
|
4276
4361
|
...replyContext.durability,
|
|
4277
|
-
|
|
4362
|
+
onSandboxRefChanged: async (sandboxRef) => {
|
|
4278
4363
|
await persistThreadStateById(threadId, {
|
|
4279
|
-
|
|
4280
|
-
sandboxDependencyProfileHash: sandbox.sandboxDependencyProfileHash
|
|
4364
|
+
sandboxRef
|
|
4281
4365
|
});
|
|
4282
|
-
await replyContext.durability?.
|
|
4366
|
+
await replyContext.durability?.onSandboxRefChanged?.(sandboxRef);
|
|
4283
4367
|
},
|
|
4284
4368
|
onArtifactStateUpdated: async (artifacts) => {
|
|
4285
4369
|
await persistThreadStateById(threadId, { artifacts });
|
|
@@ -5028,7 +5112,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
5028
5112
|
state: {
|
|
5029
5113
|
artifactState: lockedArtifacts,
|
|
5030
5114
|
pendingAuth: lockedPendingAuth,
|
|
5031
|
-
|
|
5115
|
+
sandboxRef: getPersistedSandboxState(lockedState)
|
|
5032
5116
|
},
|
|
5033
5117
|
durability: {
|
|
5034
5118
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
@@ -5626,7 +5710,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
5626
5710
|
state: {
|
|
5627
5711
|
artifactState: lockedArtifacts,
|
|
5628
5712
|
pendingAuth: lockedPendingAuth,
|
|
5629
|
-
|
|
5713
|
+
sandboxRef: getPersistedSandboxState(lockedState)
|
|
5630
5714
|
},
|
|
5631
5715
|
durability: {
|
|
5632
5716
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
@@ -6263,7 +6347,7 @@ import {
|
|
|
6263
6347
|
Message,
|
|
6264
6348
|
ThreadImpl
|
|
6265
6349
|
} from "chat";
|
|
6266
|
-
import { z as
|
|
6350
|
+
import { z as z4 } from "zod";
|
|
6267
6351
|
|
|
6268
6352
|
// src/chat/ingress/message-router.ts
|
|
6269
6353
|
function normalizeIncomingSlackThreadId(threadId, message) {
|
|
@@ -6434,14 +6518,14 @@ async function ensureSlackMessageActorIdentity(message, teamId, lookupSlackUser2
|
|
|
6434
6518
|
}
|
|
6435
6519
|
|
|
6436
6520
|
// src/chat/slack/user.ts
|
|
6437
|
-
import { z as
|
|
6438
|
-
var slackUserInfoSchema =
|
|
6439
|
-
ok:
|
|
6440
|
-
user:
|
|
6441
|
-
name:
|
|
6442
|
-
profile:
|
|
6443
|
-
email:
|
|
6444
|
-
real_name:
|
|
6521
|
+
import { z as z3 } from "zod";
|
|
6522
|
+
var slackUserInfoSchema = z3.object({
|
|
6523
|
+
ok: z3.literal(true),
|
|
6524
|
+
user: z3.object({
|
|
6525
|
+
name: z3.string().nullish(),
|
|
6526
|
+
profile: z3.object({
|
|
6527
|
+
email: z3.string().nullish(),
|
|
6528
|
+
real_name: z3.string().nullish()
|
|
6445
6529
|
}).optional()
|
|
6446
6530
|
})
|
|
6447
6531
|
});
|
|
@@ -6529,14 +6613,14 @@ async function lookupSlackUser(teamId, userId) {
|
|
|
6529
6613
|
}
|
|
6530
6614
|
|
|
6531
6615
|
// src/chat/task-execution/slack-work.ts
|
|
6532
|
-
var slackConversationRouteSchema =
|
|
6533
|
-
var serializedDateSchema =
|
|
6534
|
-
var mdastPointSchema =
|
|
6535
|
-
column:
|
|
6536
|
-
line:
|
|
6537
|
-
offset:
|
|
6616
|
+
var slackConversationRouteSchema = z4.enum(["mention", "subscribed"]);
|
|
6617
|
+
var serializedDateSchema = z4.iso.datetime();
|
|
6618
|
+
var mdastPointSchema = z4.object({
|
|
6619
|
+
column: z4.number().int().positive(),
|
|
6620
|
+
line: z4.number().int().positive(),
|
|
6621
|
+
offset: z4.number().int().nonnegative().optional()
|
|
6538
6622
|
}).strict();
|
|
6539
|
-
var mdastPositionSchema =
|
|
6623
|
+
var mdastPositionSchema = z4.object({
|
|
6540
6624
|
end: mdastPointSchema,
|
|
6541
6625
|
start: mdastPointSchema
|
|
6542
6626
|
}).strict();
|
|
@@ -6648,7 +6732,7 @@ function isFormattedContentNode(value) {
|
|
|
6648
6732
|
return false;
|
|
6649
6733
|
}
|
|
6650
6734
|
}
|
|
6651
|
-
var formattedContentSchema =
|
|
6735
|
+
var formattedContentSchema = z4.custom(
|
|
6652
6736
|
(value) => {
|
|
6653
6737
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
6654
6738
|
return false;
|
|
@@ -6658,79 +6742,79 @@ var formattedContentSchema = z3.custom(
|
|
|
6658
6742
|
},
|
|
6659
6743
|
"must be a valid formatted-content root"
|
|
6660
6744
|
);
|
|
6661
|
-
var serializedMessageSchema =
|
|
6662
|
-
_type:
|
|
6663
|
-
attachments:
|
|
6664
|
-
|
|
6665
|
-
type:
|
|
6666
|
-
url:
|
|
6667
|
-
name:
|
|
6668
|
-
mimeType:
|
|
6669
|
-
size:
|
|
6670
|
-
width:
|
|
6671
|
-
height:
|
|
6672
|
-
fetchMetadata:
|
|
6745
|
+
var serializedMessageSchema = z4.object({
|
|
6746
|
+
_type: z4.literal("chat:Message"),
|
|
6747
|
+
attachments: z4.array(
|
|
6748
|
+
z4.object({
|
|
6749
|
+
type: z4.enum(["image", "file", "video", "audio"]),
|
|
6750
|
+
url: z4.string().optional(),
|
|
6751
|
+
name: z4.string().optional(),
|
|
6752
|
+
mimeType: z4.string().optional(),
|
|
6753
|
+
size: z4.number().finite().optional(),
|
|
6754
|
+
width: z4.number().finite().optional(),
|
|
6755
|
+
height: z4.number().finite().optional(),
|
|
6756
|
+
fetchMetadata: z4.record(z4.string(), z4.string()).optional()
|
|
6673
6757
|
}).strict()
|
|
6674
6758
|
),
|
|
6675
|
-
author:
|
|
6676
|
-
userId:
|
|
6677
|
-
userName:
|
|
6678
|
-
fullName:
|
|
6679
|
-
isBot:
|
|
6680
|
-
isMe:
|
|
6759
|
+
author: z4.object({
|
|
6760
|
+
userId: z4.string(),
|
|
6761
|
+
userName: z4.string(),
|
|
6762
|
+
fullName: z4.string(),
|
|
6763
|
+
isBot: z4.union([z4.boolean(), z4.literal("unknown")]),
|
|
6764
|
+
isMe: z4.boolean()
|
|
6681
6765
|
}).strict(),
|
|
6682
6766
|
formatted: formattedContentSchema,
|
|
6683
|
-
id:
|
|
6684
|
-
isMention:
|
|
6685
|
-
links:
|
|
6686
|
-
|
|
6687
|
-
url:
|
|
6688
|
-
title:
|
|
6689
|
-
description:
|
|
6690
|
-
imageUrl:
|
|
6691
|
-
siteName:
|
|
6767
|
+
id: z4.string().min(1),
|
|
6768
|
+
isMention: z4.boolean().optional(),
|
|
6769
|
+
links: z4.array(
|
|
6770
|
+
z4.object({
|
|
6771
|
+
url: z4.string(),
|
|
6772
|
+
title: z4.string().optional(),
|
|
6773
|
+
description: z4.string().optional(),
|
|
6774
|
+
imageUrl: z4.string().optional(),
|
|
6775
|
+
siteName: z4.string().optional()
|
|
6692
6776
|
}).strict()
|
|
6693
6777
|
).optional(),
|
|
6694
|
-
metadata:
|
|
6778
|
+
metadata: z4.object({
|
|
6695
6779
|
dateSent: serializedDateSchema,
|
|
6696
|
-
edited:
|
|
6780
|
+
edited: z4.boolean(),
|
|
6697
6781
|
editedAt: serializedDateSchema.optional()
|
|
6698
6782
|
}).strict(),
|
|
6699
|
-
raw:
|
|
6700
|
-
text:
|
|
6701
|
-
threadId:
|
|
6783
|
+
raw: z4.unknown(),
|
|
6784
|
+
text: z4.string(),
|
|
6785
|
+
threadId: z4.string().min(1)
|
|
6702
6786
|
}).strict();
|
|
6703
|
-
var serializedThreadSchema =
|
|
6704
|
-
_type:
|
|
6705
|
-
adapterName:
|
|
6706
|
-
channelId:
|
|
6707
|
-
channelVisibility:
|
|
6787
|
+
var serializedThreadSchema = z4.object({
|
|
6788
|
+
_type: z4.literal("chat:Thread"),
|
|
6789
|
+
adapterName: z4.literal("slack"),
|
|
6790
|
+
channelId: z4.string().min(1),
|
|
6791
|
+
channelVisibility: z4.enum(["private", "workspace", "external", "unknown"]).optional(),
|
|
6708
6792
|
currentMessage: serializedMessageSchema.optional(),
|
|
6709
|
-
id:
|
|
6710
|
-
isDM:
|
|
6793
|
+
id: z4.string().min(1),
|
|
6794
|
+
isDM: z4.boolean()
|
|
6711
6795
|
}).strict();
|
|
6712
|
-
var slackInstallationSchema =
|
|
6713
|
-
enterpriseId:
|
|
6714
|
-
isEnterpriseInstall:
|
|
6715
|
-
teamId:
|
|
6796
|
+
var slackInstallationSchema = z4.object({
|
|
6797
|
+
enterpriseId: z4.string().optional(),
|
|
6798
|
+
isEnterpriseInstall: z4.boolean().optional(),
|
|
6799
|
+
teamId: z4.string().optional()
|
|
6716
6800
|
}).strict();
|
|
6717
|
-
var slackConversationMessageMetadataBaseSchema =
|
|
6801
|
+
var slackConversationMessageMetadataBaseSchema = z4.object({
|
|
6718
6802
|
installation: slackInstallationSchema.optional(),
|
|
6719
6803
|
message: serializedMessageSchema,
|
|
6720
|
-
platform:
|
|
6804
|
+
platform: z4.literal("slack"),
|
|
6721
6805
|
route: slackConversationRouteSchema,
|
|
6722
6806
|
thread: serializedThreadSchema
|
|
6723
6807
|
});
|
|
6724
|
-
var slackConversationMessageMetadataSchema =
|
|
6808
|
+
var slackConversationMessageMetadataSchema = z4.union([
|
|
6725
6809
|
slackConversationMessageMetadataBaseSchema.strict(),
|
|
6726
6810
|
slackConversationMessageMetadataBaseSchema.extend({
|
|
6727
|
-
kind:
|
|
6728
|
-
resourceEvent:
|
|
6729
|
-
eventKey:
|
|
6730
|
-
eventType:
|
|
6731
|
-
provider:
|
|
6732
|
-
resourceRef:
|
|
6733
|
-
subscriptionId:
|
|
6811
|
+
kind: z4.literal("resource_event"),
|
|
6812
|
+
resourceEvent: z4.object({
|
|
6813
|
+
eventKey: z4.string(),
|
|
6814
|
+
eventType: z4.string(),
|
|
6815
|
+
provider: z4.string(),
|
|
6816
|
+
resourceRef: z4.string(),
|
|
6817
|
+
subscriptionId: z4.string()
|
|
6734
6818
|
}).strict()
|
|
6735
6819
|
}).strict()
|
|
6736
6820
|
]);
|
|
@@ -6820,6 +6904,7 @@ function createSlackResourceEventInboundMessage(input) {
|
|
|
6820
6904
|
createdAtMs: input.event.occurredAtMs,
|
|
6821
6905
|
destination,
|
|
6822
6906
|
inboundMessageId: `resource-event:${input.subscription.id}:${input.event.eventKey}`,
|
|
6907
|
+
delivery: "defer",
|
|
6823
6908
|
source: "resource_event",
|
|
6824
6909
|
receivedAtMs: Date.now(),
|
|
6825
6910
|
input: {
|
|
@@ -6864,10 +6949,6 @@ function routeForRecords(records) {
|
|
|
6864
6949
|
return metadata.route === "mention";
|
|
6865
6950
|
}) ? "mention" : "subscribed";
|
|
6866
6951
|
}
|
|
6867
|
-
function isSlackAssistantThreadUserMessage(message) {
|
|
6868
|
-
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
6869
|
-
return raw?.channel_type === "im" && typeof raw.thread_ts === "string" && raw.thread_ts.trim().length > 0;
|
|
6870
|
-
}
|
|
6871
6952
|
function isResourceEventNotificationMessage(message) {
|
|
6872
6953
|
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
6873
6954
|
return raw?.event_type === "resource_event";
|
|
@@ -6962,7 +7043,9 @@ function createSlackConversationWorker(options) {
|
|
|
6962
7043
|
installation: { teamId: destination.teamId },
|
|
6963
7044
|
state,
|
|
6964
7045
|
task: async () => {
|
|
6965
|
-
await options.resumeAwaitingContinuation(context.conversationId
|
|
7046
|
+
await options.resumeAwaitingContinuation(context.conversationId, {
|
|
7047
|
+
shouldYield: context.shouldYield
|
|
7048
|
+
});
|
|
6966
7049
|
}
|
|
6967
7050
|
});
|
|
6968
7051
|
return { status: "completed" };
|
|
@@ -7030,21 +7113,12 @@ function createSlackConversationWorker(options) {
|
|
|
7030
7113
|
};
|
|
7031
7114
|
const drainSteeringMessages = async (accept) => {
|
|
7032
7115
|
await context.attempt.drain(async (pendingRecords) => {
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
if (!metadata) {
|
|
7036
|
-
throw new Error(
|
|
7037
|
-
"Conversation mailbox record is not Slack metadata"
|
|
7038
|
-
);
|
|
7039
|
-
}
|
|
7040
|
-
const message = restoreMessage({ adapter, record });
|
|
7041
|
-
return {
|
|
7042
|
-
activeRequest: metadata.route === "mention" || isSlackAssistantThreadUserMessage(message),
|
|
7116
|
+
return await accept(
|
|
7117
|
+
pendingRecords.map((record) => ({
|
|
7043
7118
|
inboundMessageId: record.inboundMessageId,
|
|
7044
|
-
message
|
|
7045
|
-
}
|
|
7046
|
-
|
|
7047
|
-
return await accept(messages2);
|
|
7119
|
+
message: restoreMessage({ adapter, record })
|
|
7120
|
+
}))
|
|
7121
|
+
);
|
|
7048
7122
|
});
|
|
7049
7123
|
};
|
|
7050
7124
|
try {
|
|
@@ -7057,16 +7131,20 @@ function createSlackConversationWorker(options) {
|
|
|
7057
7131
|
isFinalAttempt: context.attempt.isFinalAttempt,
|
|
7058
7132
|
shouldYield: context.shouldYield
|
|
7059
7133
|
});
|
|
7060
|
-
|
|
7134
|
+
} else {
|
|
7135
|
+
await options.runtime.handleSubscribedMessage(
|
|
7136
|
+
thread,
|
|
7137
|
+
latestMessage,
|
|
7138
|
+
{
|
|
7139
|
+
destination: context.destination,
|
|
7140
|
+
messageContext,
|
|
7141
|
+
drainSteeringMessages,
|
|
7142
|
+
ack,
|
|
7143
|
+
isFinalAttempt: context.attempt.isFinalAttempt,
|
|
7144
|
+
shouldYield: context.shouldYield
|
|
7145
|
+
}
|
|
7146
|
+
);
|
|
7061
7147
|
}
|
|
7062
|
-
await options.runtime.handleSubscribedMessage(thread, latestMessage, {
|
|
7063
|
-
destination: context.destination,
|
|
7064
|
-
messageContext,
|
|
7065
|
-
drainSteeringMessages,
|
|
7066
|
-
ack,
|
|
7067
|
-
isFinalAttempt: context.attempt.isFinalAttempt,
|
|
7068
|
-
shouldYield: context.shouldYield
|
|
7069
|
-
});
|
|
7070
7148
|
} catch (error) {
|
|
7071
7149
|
if (isTurnInputDeferredError(error)) {
|
|
7072
7150
|
return { status: "deferred" };
|
|
@@ -7105,6 +7183,7 @@ function buildSlackInboundMessage(args) {
|
|
|
7105
7183
|
args.conversationId,
|
|
7106
7184
|
args.message.id
|
|
7107
7185
|
].join(":"),
|
|
7186
|
+
delivery: args.message.isMention ? "interrupt" : "defer",
|
|
7108
7187
|
source: "slack",
|
|
7109
7188
|
createdAtMs: args.message.metadata.dateSent.getTime(),
|
|
7110
7189
|
receivedAtMs: args.receivedAtMs,
|
|
@@ -7894,32 +7973,26 @@ import {
|
|
|
7894
7973
|
registerDevConsumer
|
|
7895
7974
|
} from "@vercel/queue";
|
|
7896
7975
|
|
|
7897
|
-
// src/chat/task-execution/queue.ts
|
|
7898
|
-
var ConversationQueueMessageRejectedError = class extends Error {
|
|
7899
|
-
conversationId;
|
|
7900
|
-
reason;
|
|
7901
|
-
constructor(reason, message, options = {}) {
|
|
7902
|
-
super(message);
|
|
7903
|
-
this.name = "ConversationQueueMessageRejectedError";
|
|
7904
|
-
this.reason = reason;
|
|
7905
|
-
this.conversationId = options.conversationId;
|
|
7906
|
-
}
|
|
7907
|
-
};
|
|
7908
|
-
function isConversationQueueMessageRejectedError(error) {
|
|
7909
|
-
return error instanceof ConversationQueueMessageRejectedError;
|
|
7910
|
-
}
|
|
7911
|
-
|
|
7912
7976
|
// src/chat/task-execution/worker.ts
|
|
7913
7977
|
var CONVERSATION_WORK_DEFER_DELAY_MS = 15e3;
|
|
7914
|
-
var CONVERSATION_WORK_SOFT_YIELD_AFTER_MS = 24e4;
|
|
7915
7978
|
function now3(options) {
|
|
7916
7979
|
return options.nowMs?.() ?? Date.now();
|
|
7917
7980
|
}
|
|
7981
|
+
function selectAttemptMessages(work) {
|
|
7982
|
+
const messages = work.messages;
|
|
7983
|
+
const interrupts = messages.filter(
|
|
7984
|
+
(message) => message.delivery === "interrupt"
|
|
7985
|
+
);
|
|
7986
|
+
if (interrupts.length > 0) {
|
|
7987
|
+
return interrupts;
|
|
7988
|
+
}
|
|
7989
|
+
return work.execution.status === "awaiting_resume" ? [] : messages;
|
|
7990
|
+
}
|
|
7918
7991
|
function nudgeIdempotencyKey(reason, conversationId, nowMs) {
|
|
7919
7992
|
return `${reason}:${conversationId}:${nowMs}`;
|
|
7920
7993
|
}
|
|
7921
7994
|
async function requestLostLeaseRecovery(args) {
|
|
7922
|
-
const
|
|
7995
|
+
const resumeRequested = await requestConversationContinuation2({
|
|
7923
7996
|
conversationId: args.conversationId,
|
|
7924
7997
|
destination: args.destination,
|
|
7925
7998
|
leaseToken: args.leaseToken,
|
|
@@ -7927,7 +8000,7 @@ async function requestLostLeaseRecovery(args) {
|
|
|
7927
8000
|
nowMs: args.nowMs,
|
|
7928
8001
|
state: args.options.state
|
|
7929
8002
|
});
|
|
7930
|
-
if (!
|
|
8003
|
+
if (!resumeRequested) {
|
|
7931
8004
|
return;
|
|
7932
8005
|
}
|
|
7933
8006
|
const released = await releaseConversationWork2({
|
|
@@ -8045,10 +8118,10 @@ async function processConversationWork(message, options) {
|
|
|
8045
8118
|
}
|
|
8046
8119
|
return { status: "no_work" };
|
|
8047
8120
|
}
|
|
8048
|
-
if (!initial.destination
|
|
8121
|
+
if (!initial.destination) {
|
|
8049
8122
|
throw new ConversationQueueMessageRejectedError(
|
|
8050
|
-
"
|
|
8051
|
-
`Conversation work
|
|
8123
|
+
"invalid_record",
|
|
8124
|
+
`Conversation work is missing destination context for ${conversationId}`,
|
|
8052
8125
|
{ conversationId }
|
|
8053
8126
|
);
|
|
8054
8127
|
}
|
|
@@ -8091,15 +8164,8 @@ async function processConversationWork(message, options) {
|
|
|
8091
8164
|
return { status: "active" };
|
|
8092
8165
|
}
|
|
8093
8166
|
const startedAtMs = now3(options);
|
|
8094
|
-
const softYieldDeadlineMs = startedAtMs + (options.softYieldAfterMs ??
|
|
8095
|
-
|
|
8096
|
-
conversationId,
|
|
8097
|
-
state: options.state
|
|
8098
|
-
});
|
|
8099
|
-
const attemptMessages = leasedWork?.messages ?? initial.messages;
|
|
8100
|
-
const attemptMessageIds = attemptMessages.map(
|
|
8101
|
-
(message2) => message2.inboundMessageId
|
|
8102
|
-
);
|
|
8167
|
+
const softYieldDeadlineMs = startedAtMs + (options.softYieldAfterMs ?? getChatConfig().conversationWorkSoftYieldAfterMs);
|
|
8168
|
+
let attemptMessageIds = [];
|
|
8103
8169
|
let leaseLost = false;
|
|
8104
8170
|
const markLeaseLost = () => {
|
|
8105
8171
|
leaseLost = true;
|
|
@@ -8119,166 +8185,246 @@ async function processConversationWork(message, options) {
|
|
|
8119
8185
|
},
|
|
8120
8186
|
"Conversation work lease acquired"
|
|
8121
8187
|
);
|
|
8122
|
-
const
|
|
8188
|
+
const drain = (handle) => drainConversationMailbox2({
|
|
8123
8189
|
conversationId,
|
|
8124
8190
|
leaseToken: lease.leaseToken,
|
|
8125
8191
|
conversationStore: options.conversationStore,
|
|
8126
|
-
handle
|
|
8192
|
+
handle: async (messages) => {
|
|
8193
|
+
const candidates = messages.filter(
|
|
8194
|
+
(message2) => message2.delivery === "interrupt"
|
|
8195
|
+
);
|
|
8196
|
+
if (candidates.length === 0) {
|
|
8197
|
+
return [];
|
|
8198
|
+
}
|
|
8199
|
+
return await handle(candidates) ?? candidates.map((message2) => message2.inboundMessageId);
|
|
8200
|
+
},
|
|
8127
8201
|
nowMs: now3(options),
|
|
8128
8202
|
state: options.state
|
|
8129
8203
|
});
|
|
8130
|
-
const
|
|
8131
|
-
|
|
8204
|
+
const shouldYield = () => leaseLost || now3(options) >= softYieldDeadlineMs;
|
|
8205
|
+
const checkIn = async () => {
|
|
8206
|
+
const checkedIn = await checkInConversationWork2({
|
|
8132
8207
|
conversationId,
|
|
8133
|
-
inboundMessageIds: attemptMessageIds,
|
|
8134
8208
|
leaseToken: lease.leaseToken,
|
|
8135
8209
|
conversationStore: options.conversationStore,
|
|
8136
8210
|
nowMs: now3(options),
|
|
8137
8211
|
state: options.state
|
|
8138
8212
|
});
|
|
8139
|
-
if (!
|
|
8213
|
+
if (!checkedIn) {
|
|
8140
8214
|
markLeaseLost();
|
|
8141
|
-
throw new Error(
|
|
8142
|
-
`Conversation work lease lost before inbox ack for ${conversationId}`
|
|
8143
|
-
);
|
|
8144
8215
|
}
|
|
8216
|
+
return checkedIn;
|
|
8145
8217
|
};
|
|
8146
|
-
const
|
|
8147
|
-
|
|
8148
|
-
|
|
8218
|
+
const yieldWork = async () => {
|
|
8219
|
+
const yieldNowMs = now3(options);
|
|
8220
|
+
await ensureConversationWake({
|
|
8149
8221
|
conversationId,
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
}
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
state: options.state
|
|
8167
|
-
});
|
|
8168
|
-
if (!checkedIn) {
|
|
8169
|
-
markLeaseLost();
|
|
8170
|
-
}
|
|
8171
|
-
return checkedIn;
|
|
8222
|
+
conversationStore: options.conversationStore,
|
|
8223
|
+
idempotencyKey: nudgeIdempotencyKey("yield", conversationId, yieldNowMs),
|
|
8224
|
+
nowMs: yieldNowMs,
|
|
8225
|
+
queue: options.queue,
|
|
8226
|
+
replaceExistingWake: true,
|
|
8227
|
+
state: options.state
|
|
8228
|
+
});
|
|
8229
|
+
const released = await releaseConversationWork2({
|
|
8230
|
+
conversationId,
|
|
8231
|
+
leaseToken: lease.leaseToken,
|
|
8232
|
+
conversationStore: options.conversationStore,
|
|
8233
|
+
nowMs: yieldNowMs,
|
|
8234
|
+
state: options.state
|
|
8235
|
+
});
|
|
8236
|
+
if (!released) {
|
|
8237
|
+
return { status: "lost_lease" };
|
|
8172
8238
|
}
|
|
8239
|
+
logInfo(
|
|
8240
|
+
"conversation_work_cooperative_yield",
|
|
8241
|
+
{ conversationId },
|
|
8242
|
+
{
|
|
8243
|
+
"app.worker.elapsed_ms": now3(options) - startedAtMs,
|
|
8244
|
+
"app.worker.soft_yield_deadline_ms": softYieldDeadlineMs
|
|
8245
|
+
},
|
|
8246
|
+
"Conversation work yielded cooperatively"
|
|
8247
|
+
);
|
|
8248
|
+
return { status: "yielded" };
|
|
8173
8249
|
};
|
|
8174
8250
|
try {
|
|
8175
|
-
|
|
8176
|
-
|
|
8177
|
-
|
|
8251
|
+
let hasRun = false;
|
|
8252
|
+
while (true) {
|
|
8253
|
+
attemptMessageIds = [];
|
|
8254
|
+
const leasedWork = await getConversationWorkState2({
|
|
8178
8255
|
conversationId,
|
|
8179
|
-
destination,
|
|
8180
|
-
leaseToken: lease.leaseToken,
|
|
8181
|
-
nowMs: now3(options),
|
|
8182
|
-
options
|
|
8183
|
-
});
|
|
8184
|
-
return { status: "lost_lease" };
|
|
8185
|
-
}
|
|
8186
|
-
if (leaseLost) {
|
|
8187
|
-
await requestLostLeaseRecovery({
|
|
8188
|
-
conversationId,
|
|
8189
|
-
destination,
|
|
8190
|
-
leaseToken: lease.leaseToken,
|
|
8191
|
-
nowMs: now3(options),
|
|
8192
|
-
options
|
|
8193
|
-
});
|
|
8194
|
-
return { status: "lost_lease" };
|
|
8195
|
-
}
|
|
8196
|
-
if (result.status === "yielded") {
|
|
8197
|
-
const yieldNowMs = now3(options);
|
|
8198
|
-
const continuationMarked = await requestConversationContinuation2({
|
|
8199
|
-
conversationId,
|
|
8200
|
-
destination,
|
|
8201
|
-
leaseToken: lease.leaseToken,
|
|
8202
|
-
conversationStore: options.conversationStore,
|
|
8203
|
-
nowMs: yieldNowMs,
|
|
8204
8256
|
state: options.state
|
|
8205
8257
|
});
|
|
8206
|
-
if (!
|
|
8258
|
+
if (!leasedWork || leasedWork.lease?.leaseToken !== lease.leaseToken || leaseLost) {
|
|
8259
|
+
markLeaseLost();
|
|
8260
|
+
await requestLostLeaseRecovery({
|
|
8261
|
+
conversationId,
|
|
8262
|
+
destination,
|
|
8263
|
+
leaseToken: lease.leaseToken,
|
|
8264
|
+
nowMs: now3(options),
|
|
8265
|
+
options
|
|
8266
|
+
});
|
|
8207
8267
|
return { status: "lost_lease" };
|
|
8208
8268
|
}
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8269
|
+
const resumePending = leasedWork.execution.status === "awaiting_resume";
|
|
8270
|
+
const attemptMessages = selectAttemptMessages(leasedWork);
|
|
8271
|
+
if (hasRun && shouldYield()) {
|
|
8272
|
+
if (resumePending) {
|
|
8273
|
+
return await yieldWork();
|
|
8274
|
+
}
|
|
8275
|
+
break;
|
|
8276
|
+
}
|
|
8277
|
+
if (resumePending && attemptMessages.length === 0) {
|
|
8278
|
+
const resumeStarted = await beginConversationResume2({
|
|
8214
8279
|
conversationId,
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
},
|
|
8235
|
-
"Conversation work yielded cooperatively"
|
|
8280
|
+
leaseToken: lease.leaseToken,
|
|
8281
|
+
conversationStore: options.conversationStore,
|
|
8282
|
+
nowMs: now3(options),
|
|
8283
|
+
state: options.state
|
|
8284
|
+
});
|
|
8285
|
+
if (!resumeStarted) {
|
|
8286
|
+
markLeaseLost();
|
|
8287
|
+
await requestLostLeaseRecovery({
|
|
8288
|
+
conversationId,
|
|
8289
|
+
destination,
|
|
8290
|
+
leaseToken: lease.leaseToken,
|
|
8291
|
+
nowMs: now3(options),
|
|
8292
|
+
options
|
|
8293
|
+
});
|
|
8294
|
+
return { status: "lost_lease" };
|
|
8295
|
+
}
|
|
8296
|
+
}
|
|
8297
|
+
attemptMessageIds = attemptMessages.map(
|
|
8298
|
+
(message2) => message2.inboundMessageId
|
|
8236
8299
|
);
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8300
|
+
const ack = async () => {
|
|
8301
|
+
const acknowledged = await ackMessages2({
|
|
8302
|
+
conversationId,
|
|
8303
|
+
inboundMessageIds: attemptMessageIds,
|
|
8304
|
+
leaseToken: lease.leaseToken,
|
|
8305
|
+
conversationStore: options.conversationStore,
|
|
8306
|
+
nowMs: now3(options),
|
|
8307
|
+
state: options.state
|
|
8308
|
+
});
|
|
8309
|
+
if (!acknowledged) {
|
|
8310
|
+
markLeaseLost();
|
|
8311
|
+
throw new Error(
|
|
8312
|
+
`Conversation work lease lost before inbox ack for ${conversationId}`
|
|
8313
|
+
);
|
|
8314
|
+
}
|
|
8315
|
+
};
|
|
8316
|
+
const workerContext = {
|
|
8317
|
+
attempt: {
|
|
8318
|
+
ack,
|
|
8319
|
+
conversationId,
|
|
8320
|
+
destination,
|
|
8321
|
+
drain,
|
|
8322
|
+
isFinalAttempt: attemptMessages.some(
|
|
8323
|
+
(message2) => isFinalAttempt(message2)
|
|
8324
|
+
),
|
|
8325
|
+
messages: attemptMessages
|
|
8326
|
+
},
|
|
8242
8327
|
conversationId,
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8328
|
+
destination,
|
|
8329
|
+
shouldYield,
|
|
8330
|
+
checkIn
|
|
8331
|
+
};
|
|
8332
|
+
const result = await options.run(workerContext);
|
|
8333
|
+
hasRun = true;
|
|
8334
|
+
if (result.status === "lost_lease") {
|
|
8335
|
+
await requestLostLeaseRecovery({
|
|
8336
|
+
conversationId,
|
|
8337
|
+
destination,
|
|
8338
|
+
leaseToken: lease.leaseToken,
|
|
8339
|
+
nowMs: now3(options),
|
|
8340
|
+
options
|
|
8341
|
+
});
|
|
8249
8342
|
return { status: "lost_lease" };
|
|
8250
8343
|
}
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
conversationStore: options.conversationStore,
|
|
8254
|
-
idempotencyKey: nudgeIdempotencyKey(
|
|
8255
|
-
"deferred",
|
|
8344
|
+
if (leaseLost) {
|
|
8345
|
+
await requestLostLeaseRecovery({
|
|
8256
8346
|
conversationId,
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
const failure = await recordFailedDeliveryAttempt({
|
|
8267
|
-
conversationId,
|
|
8268
|
-
leaseToken: lease.leaseToken,
|
|
8269
|
-
nowMs: now3(options),
|
|
8270
|
-
messageIds: attemptMessageIds,
|
|
8271
|
-
options
|
|
8272
|
-
});
|
|
8273
|
-
if (isTerminalFailure(failure)) {
|
|
8274
|
-
await deadLetterAttempt2({
|
|
8347
|
+
destination,
|
|
8348
|
+
leaseToken: lease.leaseToken,
|
|
8349
|
+
nowMs: now3(options),
|
|
8350
|
+
options
|
|
8351
|
+
});
|
|
8352
|
+
return { status: "lost_lease" };
|
|
8353
|
+
}
|
|
8354
|
+
if (result.status === "yielded") {
|
|
8355
|
+
const resumeRequested = await requestConversationContinuation2({
|
|
8275
8356
|
conversationId,
|
|
8357
|
+
destination,
|
|
8276
8358
|
leaseToken: lease.leaseToken,
|
|
8277
8359
|
conversationStore: options.conversationStore,
|
|
8278
8360
|
nowMs: now3(options),
|
|
8279
8361
|
state: options.state
|
|
8280
8362
|
});
|
|
8281
|
-
|
|
8363
|
+
if (!resumeRequested) {
|
|
8364
|
+
return { status: "lost_lease" };
|
|
8365
|
+
}
|
|
8366
|
+
return await yieldWork();
|
|
8367
|
+
}
|
|
8368
|
+
if (result.status === "deferred") {
|
|
8369
|
+
const deferredNowMs = now3(options);
|
|
8370
|
+
const released = await releaseConversationWork2({
|
|
8371
|
+
conversationId,
|
|
8372
|
+
leaseToken: lease.leaseToken,
|
|
8373
|
+
conversationStore: options.conversationStore,
|
|
8374
|
+
nowMs: deferredNowMs,
|
|
8375
|
+
state: options.state
|
|
8376
|
+
});
|
|
8377
|
+
if (!released) {
|
|
8378
|
+
return { status: "lost_lease" };
|
|
8379
|
+
}
|
|
8380
|
+
const wake = await ensureConversationWake({
|
|
8381
|
+
conversationId,
|
|
8382
|
+
conversationStore: options.conversationStore,
|
|
8383
|
+
idempotencyKey: nudgeIdempotencyKey(
|
|
8384
|
+
"deferred",
|
|
8385
|
+
conversationId,
|
|
8386
|
+
deferredNowMs
|
|
8387
|
+
),
|
|
8388
|
+
nowMs: deferredNowMs,
|
|
8389
|
+
queue: options.queue,
|
|
8390
|
+
state: options.state
|
|
8391
|
+
});
|
|
8392
|
+
return wake.status === "enqueued" ? { status: "pending_requeued" } : { status: "completed" };
|
|
8393
|
+
}
|
|
8394
|
+
if (attemptMessageIds.length > 0) {
|
|
8395
|
+
const failure = await recordFailedDeliveryAttempt({
|
|
8396
|
+
conversationId,
|
|
8397
|
+
leaseToken: lease.leaseToken,
|
|
8398
|
+
nowMs: now3(options),
|
|
8399
|
+
messageIds: attemptMessageIds,
|
|
8400
|
+
options
|
|
8401
|
+
});
|
|
8402
|
+
if (isTerminalFailure(failure)) {
|
|
8403
|
+
await deadLetterAttempt2({
|
|
8404
|
+
conversationId,
|
|
8405
|
+
leaseToken: lease.leaseToken,
|
|
8406
|
+
conversationStore: options.conversationStore,
|
|
8407
|
+
nowMs: now3(options),
|
|
8408
|
+
state: options.state
|
|
8409
|
+
});
|
|
8410
|
+
return { status: "failed" };
|
|
8411
|
+
}
|
|
8412
|
+
if (failure.status === "lost_lease") {
|
|
8413
|
+
return { status: "lost_lease" };
|
|
8414
|
+
}
|
|
8415
|
+
if (failure.status === "recorded") {
|
|
8416
|
+
break;
|
|
8417
|
+
}
|
|
8418
|
+
}
|
|
8419
|
+
const next = await getConversationWorkState2({
|
|
8420
|
+
conversationId,
|
|
8421
|
+
state: options.state
|
|
8422
|
+
});
|
|
8423
|
+
if (!next || next.lease?.leaseToken !== lease.leaseToken) {
|
|
8424
|
+
return { status: "lost_lease" };
|
|
8425
|
+
}
|
|
8426
|
+
if (next.execution.status !== "awaiting_resume" && countPendingConversationMessages(next) === 0) {
|
|
8427
|
+
break;
|
|
8282
8428
|
}
|
|
8283
8429
|
}
|
|
8284
8430
|
const completion = await completeConversationWork2({
|
|
@@ -8336,7 +8482,7 @@ async function processConversationWork(message, options) {
|
|
|
8336
8482
|
state: options.state
|
|
8337
8483
|
});
|
|
8338
8484
|
} else {
|
|
8339
|
-
const
|
|
8485
|
+
const resumeRequested = await requestConversationContinuation2({
|
|
8340
8486
|
conversationId,
|
|
8341
8487
|
destination,
|
|
8342
8488
|
leaseToken: lease.leaseToken,
|
|
@@ -8344,7 +8490,7 @@ async function processConversationWork(message, options) {
|
|
|
8344
8490
|
nowMs: errorNowMs,
|
|
8345
8491
|
state: options.state
|
|
8346
8492
|
});
|
|
8347
|
-
if (
|
|
8493
|
+
if (resumeRequested) {
|
|
8348
8494
|
await ensureConversationWake({
|
|
8349
8495
|
conversationId,
|
|
8350
8496
|
conversationStore: options.conversationStore,
|
|
@@ -8355,6 +8501,7 @@ async function processConversationWork(message, options) {
|
|
|
8355
8501
|
),
|
|
8356
8502
|
nowMs: errorNowMs,
|
|
8357
8503
|
queue: options.queue,
|
|
8504
|
+
replaceExistingWake: true,
|
|
8358
8505
|
state: options.state
|
|
8359
8506
|
});
|
|
8360
8507
|
}
|
|
@@ -8400,18 +8547,11 @@ async function processConversationWork(message, options) {
|
|
|
8400
8547
|
var CONVERSATION_WORK_VISIBILITY_TIMEOUT_BUFFER_SECONDS = 30;
|
|
8401
8548
|
var CONVERSATION_WORK_DEV_CONSUMER_GROUP = "junior_conversation_work_dev";
|
|
8402
8549
|
function parseConversationQueueMessage(message) {
|
|
8403
|
-
const
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
if (!message || typeof message !== "object" || typeof message.conversationId !== "string" || !message.conversationId.trim() || !destination) {
|
|
8407
|
-
throw new Error(
|
|
8408
|
-
"Conversation queue message is missing destination context"
|
|
8409
|
-
);
|
|
8550
|
+
const parsed = conversationQueueMessageSchema.safeParse(message);
|
|
8551
|
+
if (!parsed.success) {
|
|
8552
|
+
throw new Error("Conversation queue message is malformed");
|
|
8410
8553
|
}
|
|
8411
|
-
return
|
|
8412
|
-
conversationId: message.conversationId,
|
|
8413
|
-
destination
|
|
8414
|
-
};
|
|
8554
|
+
return parsed.data;
|
|
8415
8555
|
}
|
|
8416
8556
|
function resolveConversationWorkVisibilityTimeoutSeconds(functionMaxDurationSeconds = getChatConfig().functionMaxDurationSeconds) {
|
|
8417
8557
|
return functionMaxDurationSeconds + CONVERSATION_WORK_VISIBILITY_TIMEOUT_BUFFER_SECONDS;
|
|
@@ -8563,14 +8703,14 @@ function registerVercelPluginTaskDevConsumer() {
|
|
|
8563
8703
|
}
|
|
8564
8704
|
|
|
8565
8705
|
// src/chat/services/subscribed-decision.ts
|
|
8566
|
-
import { z as
|
|
8567
|
-
var replyDecisionSchema =
|
|
8568
|
-
should_reply:
|
|
8569
|
-
should_unsubscribe:
|
|
8706
|
+
import { z as z5 } from "zod";
|
|
8707
|
+
var replyDecisionSchema = z5.object({
|
|
8708
|
+
should_reply: z5.boolean().describe("Whether Junior should respond to this thread message."),
|
|
8709
|
+
should_unsubscribe: z5.boolean().describe(
|
|
8570
8710
|
"Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
|
|
8571
8711
|
),
|
|
8572
|
-
confidence:
|
|
8573
|
-
reason:
|
|
8712
|
+
confidence: z5.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
|
|
8713
|
+
reason: z5.string().describe("Short reason for the decision; use an empty string if none.")
|
|
8574
8714
|
}).strict();
|
|
8575
8715
|
var ROUTER_CONFIDENCE_THRESHOLD = 0.8;
|
|
8576
8716
|
var ROUTER_CLASSIFIER_MAX_TOKENS = 240;
|
|
@@ -8944,12 +9084,14 @@ function createAcceptedSteeringDrain(hooks, options) {
|
|
|
8944
9084
|
await hooks.drainSteeringMessages(async (messages) => {
|
|
8945
9085
|
const selection = await options.selectMessages(messages, context);
|
|
8946
9086
|
await options.onSkipped?.(selection.skipped);
|
|
8947
|
-
const interrupted = selection.accepted.
|
|
9087
|
+
const interrupted = selection.accepted.map(
|
|
9088
|
+
(accepted) => accepted.message
|
|
9089
|
+
);
|
|
8948
9090
|
await accept(getQueuedMessagesFromSlackMessages(interrupted, options));
|
|
8949
9091
|
interruptedMessages = interrupted;
|
|
8950
9092
|
await options.onAcceptedForProcessing?.(interrupted);
|
|
8951
9093
|
return [
|
|
8952
|
-
...selection.accepted.
|
|
9094
|
+
...selection.accepted.map((accepted) => accepted.inboundMessageId),
|
|
8953
9095
|
...selection.skipped.map((skipped) => skipped.inboundMessageId)
|
|
8954
9096
|
];
|
|
8955
9097
|
});
|
|
@@ -9083,19 +9225,17 @@ function createSlackTurnRuntime(deps) {
|
|
|
9083
9225
|
rawText: appendSlackLegacyAttachmentText(message.text, message.raw),
|
|
9084
9226
|
userText: appendSlackLegacyAttachmentText(strippedUserText, message.raw)
|
|
9085
9227
|
};
|
|
9086
|
-
const isActiveRequest = candidate.activeRequest || Boolean(message.isMention);
|
|
9087
9228
|
const decision = await deps.decideSubscribedReply({
|
|
9088
9229
|
rawText: text.rawText,
|
|
9089
9230
|
text: text.userText,
|
|
9090
9231
|
conversationContext,
|
|
9091
9232
|
hasAttachments: message.attachments.length > 0 || legacyAttachmentText !== "",
|
|
9092
|
-
isExplicitMention:
|
|
9233
|
+
isExplicitMention: true,
|
|
9093
9234
|
context
|
|
9094
9235
|
});
|
|
9095
9236
|
return {
|
|
9096
9237
|
context,
|
|
9097
9238
|
decision,
|
|
9098
|
-
mode: isActiveRequest ? "interrupt" : "defer",
|
|
9099
9239
|
text
|
|
9100
9240
|
};
|
|
9101
9241
|
};
|
|
@@ -9149,7 +9289,6 @@ function createSlackTurnRuntime(deps) {
|
|
|
9149
9289
|
context: decision.context,
|
|
9150
9290
|
decision: decision.decision,
|
|
9151
9291
|
inboundMessageId: candidate.inboundMessageId,
|
|
9152
|
-
mode: decision.mode,
|
|
9153
9292
|
message: candidate.message,
|
|
9154
9293
|
text: decision.text
|
|
9155
9294
|
});
|
|
@@ -9171,8 +9310,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
9171
9310
|
return {
|
|
9172
9311
|
accepted: selected.filter((message) => message.decision.shouldReply).map((message) => ({
|
|
9173
9312
|
inboundMessageId: message.inboundMessageId,
|
|
9174
|
-
message: message.message
|
|
9175
|
-
mode: message.mode
|
|
9313
|
+
message: message.message
|
|
9176
9314
|
})),
|
|
9177
9315
|
skipped: selected.filter((message) => !message.decision.shouldReply)
|
|
9178
9316
|
};
|
|
@@ -10337,11 +10475,11 @@ function getSlackMessageTs(message) {
|
|
|
10337
10475
|
}
|
|
10338
10476
|
|
|
10339
10477
|
// src/chat/slack/action-token.ts
|
|
10340
|
-
import { z as
|
|
10341
|
-
var slackActionTokenSchema =
|
|
10342
|
-
var slackMessageEnvelopeSchema =
|
|
10343
|
-
raw:
|
|
10344
|
-
action_token:
|
|
10478
|
+
import { z as z6 } from "zod";
|
|
10479
|
+
var slackActionTokenSchema = z6.string().trim().min(1).brand();
|
|
10480
|
+
var slackMessageEnvelopeSchema = z6.object({
|
|
10481
|
+
raw: z6.object({
|
|
10482
|
+
action_token: z6.unknown().optional()
|
|
10345
10483
|
}).optional()
|
|
10346
10484
|
});
|
|
10347
10485
|
function readSlackActionToken(message) {
|
|
@@ -11336,10 +11474,7 @@ function createReplyToThread(deps) {
|
|
|
11336
11474
|
state: {
|
|
11337
11475
|
artifactState: preparedState.artifacts,
|
|
11338
11476
|
pendingAuth: preparedState.conversation.processing.pendingAuth,
|
|
11339
|
-
|
|
11340
|
-
sandboxId: preparedState.sandboxId,
|
|
11341
|
-
sandboxDependencyProfileHash: preparedState.sandboxDependencyProfileHash
|
|
11342
|
-
}
|
|
11477
|
+
sandboxRef: preparedState.sandboxRef
|
|
11343
11478
|
},
|
|
11344
11479
|
observers: {
|
|
11345
11480
|
onStatus: (nextStatus) => status.update(nextStatus),
|
|
@@ -11352,10 +11487,9 @@ function createReplyToThread(deps) {
|
|
|
11352
11487
|
onInputCommitted: options.ack,
|
|
11353
11488
|
drainSteeringMessages,
|
|
11354
11489
|
shouldYield: options.shouldYield,
|
|
11355
|
-
|
|
11490
|
+
onSandboxRefChanged: async (sandboxRef) => {
|
|
11356
11491
|
await persistThreadState(thread, {
|
|
11357
|
-
|
|
11358
|
-
sandboxDependencyProfileHash: sandbox.sandboxDependencyProfileHash
|
|
11492
|
+
sandboxRef
|
|
11359
11493
|
});
|
|
11360
11494
|
},
|
|
11361
11495
|
onArtifactStateUpdated: async (artifacts) => {
|
|
@@ -11915,12 +12049,7 @@ async function seedConversationBackfill(thread, conversation, currentTurn) {
|
|
|
11915
12049
|
function createPrepareTurnState(deps) {
|
|
11916
12050
|
return async function prepareTurnState(args) {
|
|
11917
12051
|
const existingState = await args.thread.state;
|
|
11918
|
-
const
|
|
11919
|
-
existingState.app_sandbox_id
|
|
11920
|
-
) : void 0;
|
|
11921
|
-
const existingSandboxDependencyProfileHash = existingState ? toOptionalString(
|
|
11922
|
-
existingState.app_sandbox_dependency_profile_hash
|
|
11923
|
-
) : void 0;
|
|
12052
|
+
const sandboxRef = getPersistedSandboxState(existingState ?? {});
|
|
11924
12053
|
const artifacts = coerceThreadArtifactsState(existingState);
|
|
11925
12054
|
const conversation = coerceThreadConversationState(existingState);
|
|
11926
12055
|
const conversationId = args.context.threadId ?? args.context.runId;
|
|
@@ -11989,8 +12118,7 @@ function createPrepareTurnState(deps) {
|
|
|
11989
12118
|
configuration,
|
|
11990
12119
|
channelConfiguration,
|
|
11991
12120
|
conversation,
|
|
11992
|
-
|
|
11993
|
-
sandboxDependencyProfileHash: existingSandboxDependencyProfileHash,
|
|
12121
|
+
sandboxRef,
|
|
11994
12122
|
conversationContext,
|
|
11995
12123
|
userMessageAlreadyReplied,
|
|
11996
12124
|
userMessageId
|
|
@@ -12298,7 +12426,7 @@ async function failUnresumableContinuation(args) {
|
|
|
12298
12426
|
errorMessage: args.errorMessage
|
|
12299
12427
|
});
|
|
12300
12428
|
}
|
|
12301
|
-
async function continueSlackAgentRun(payload, options) {
|
|
12429
|
+
async function continueSlackAgentRun(payload, options, runOptions = {}) {
|
|
12302
12430
|
const thread = parseSlackThreadId(payload.conversationId);
|
|
12303
12431
|
if (!thread) {
|
|
12304
12432
|
throw new Error(
|
|
@@ -12351,7 +12479,7 @@ async function continueSlackAgentRun(payload, options) {
|
|
|
12351
12479
|
const conversationContext = buildConversationContext(conversation, {
|
|
12352
12480
|
excludeMessageId: userMessage.id
|
|
12353
12481
|
});
|
|
12354
|
-
const
|
|
12482
|
+
const sandboxRef = getPersistedSandboxState(currentState);
|
|
12355
12483
|
const destination = requireSlackDestination(
|
|
12356
12484
|
payload.destination,
|
|
12357
12485
|
"Slack continuation"
|
|
@@ -12423,9 +12551,10 @@ async function continueSlackAgentRun(payload, options) {
|
|
|
12423
12551
|
state: {
|
|
12424
12552
|
artifactState: artifacts,
|
|
12425
12553
|
pendingAuth: conversation.processing.pendingAuth,
|
|
12426
|
-
|
|
12554
|
+
sandboxRef
|
|
12427
12555
|
},
|
|
12428
12556
|
durability: {
|
|
12557
|
+
shouldYield: runOptions.shouldYield,
|
|
12429
12558
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
12430
12559
|
conversation.processing.pendingAuth = nextPendingAuth;
|
|
12431
12560
|
await persistThreadStateById(payload.conversationId, {
|
|
@@ -12588,7 +12717,11 @@ async function recoverStrandedRunningSession(args) {
|
|
|
12588
12717
|
});
|
|
12589
12718
|
return false;
|
|
12590
12719
|
}
|
|
12591
|
-
if (await continueSlackAgentRunWithLockRetry(
|
|
12720
|
+
if (await continueSlackAgentRunWithLockRetry(
|
|
12721
|
+
request,
|
|
12722
|
+
args.options,
|
|
12723
|
+
args.runOptions
|
|
12724
|
+
)) {
|
|
12592
12725
|
return true;
|
|
12593
12726
|
}
|
|
12594
12727
|
await failUnresumableContinuation({
|
|
@@ -12599,13 +12732,14 @@ async function recoverStrandedRunningSession(args) {
|
|
|
12599
12732
|
});
|
|
12600
12733
|
return false;
|
|
12601
12734
|
}
|
|
12602
|
-
async function resumeAwaitingSlackContinuation(conversationId, options) {
|
|
12735
|
+
async function resumeAwaitingSlackContinuation(conversationId, options, runOptions = {}) {
|
|
12603
12736
|
const summaries = await listAgentTurnSessionSummariesForConversation(conversationId);
|
|
12604
12737
|
const newest = summaries[0];
|
|
12605
12738
|
if (newest?.state === "running") {
|
|
12606
12739
|
return await recoverStrandedRunningSession({
|
|
12607
12740
|
conversationId,
|
|
12608
12741
|
options,
|
|
12742
|
+
runOptions,
|
|
12609
12743
|
summary: newest
|
|
12610
12744
|
});
|
|
12611
12745
|
}
|
|
@@ -12625,7 +12759,7 @@ async function resumeAwaitingSlackContinuation(conversationId, options) {
|
|
|
12625
12759
|
});
|
|
12626
12760
|
continue;
|
|
12627
12761
|
}
|
|
12628
|
-
if (await continueSlackAgentRunWithLockRetry(request, options)) {
|
|
12762
|
+
if (await continueSlackAgentRunWithLockRetry(request, options, runOptions)) {
|
|
12629
12763
|
return true;
|
|
12630
12764
|
}
|
|
12631
12765
|
await failUnresumableContinuation({
|
|
@@ -12637,14 +12771,14 @@ async function resumeAwaitingSlackContinuation(conversationId, options) {
|
|
|
12637
12771
|
}
|
|
12638
12772
|
return false;
|
|
12639
12773
|
}
|
|
12640
|
-
async function continueSlackAgentRunWithLockRetry(payload, options) {
|
|
12774
|
+
async function continueSlackAgentRunWithLockRetry(payload, options, runOptions = {}) {
|
|
12641
12775
|
const scheduleAgentContinue2 = options.scheduleAgentContinue ?? scheduleAgentContinue;
|
|
12642
12776
|
for (const [attempt, delayMs] of [
|
|
12643
12777
|
...AGENT_CONTINUE_LOCK_RETRY_DELAYS_MS,
|
|
12644
12778
|
void 0
|
|
12645
12779
|
].entries()) {
|
|
12646
12780
|
try {
|
|
12647
|
-
return await continueSlackAgentRun(payload, options);
|
|
12781
|
+
return await continueSlackAgentRun(payload, options, runOptions);
|
|
12648
12782
|
} catch (error) {
|
|
12649
12783
|
if (!(error instanceof ResumeTurnBusyError)) {
|
|
12650
12784
|
throw error;
|
|
@@ -12739,10 +12873,14 @@ function createProductionConversationWorkOptions(options) {
|
|
|
12739
12873
|
run: createSlackConversationWorker({
|
|
12740
12874
|
getSlackAdapter: getProductionSlackAdapter,
|
|
12741
12875
|
conversationStore,
|
|
12742
|
-
resumeAwaitingContinuation: async (conversationId) => await resumeAwaitingSlackContinuation(
|
|
12743
|
-
|
|
12744
|
-
|
|
12745
|
-
|
|
12876
|
+
resumeAwaitingContinuation: async (conversationId, runOptions) => await resumeAwaitingSlackContinuation(
|
|
12877
|
+
conversationId,
|
|
12878
|
+
{
|
|
12879
|
+
agentRunner,
|
|
12880
|
+
scheduleSessionCompletedPluginTasks: services.replyExecutor?.scheduleSessionCompletedPluginTasks
|
|
12881
|
+
},
|
|
12882
|
+
runOptions
|
|
12883
|
+
),
|
|
12746
12884
|
runtime
|
|
12747
12885
|
})
|
|
12748
12886
|
};
|
|
@@ -12872,6 +13010,7 @@ async function resolveVirtualConfig() {
|
|
|
12872
13010
|
const mod = await import("#junior/config");
|
|
12873
13011
|
return {
|
|
12874
13012
|
createDashboardApp: mod.createDashboardApp,
|
|
13013
|
+
functionMaxDurationSeconds: mod.functionMaxDurationSeconds,
|
|
12875
13014
|
dashboard: mod.dashboard,
|
|
12876
13015
|
pluginSet: mod.pluginSet,
|
|
12877
13016
|
plugins: mod.plugins,
|
|
@@ -13125,6 +13264,11 @@ function mountRoutes(app, routes) {
|
|
|
13125
13264
|
}
|
|
13126
13265
|
async function createApp(options) {
|
|
13127
13266
|
const virtualConfig = await resolveVirtualConfig();
|
|
13267
|
+
if (virtualConfig?.functionMaxDurationSeconds !== void 0) {
|
|
13268
|
+
configureFunctionMaxDurationSeconds(
|
|
13269
|
+
virtualConfig.functionMaxDurationSeconds
|
|
13270
|
+
);
|
|
13271
|
+
}
|
|
13128
13272
|
const dashboard = options?.dashboard ?? virtualConfig?.dashboard;
|
|
13129
13273
|
const configuredPlugins = options?.plugins ?? virtualConfig?.pluginSet;
|
|
13130
13274
|
const plugins = pluginRuntimeRegistrationsFromPluginSet(configuredPlugins);
|