@sentry/junior 0.75.0 → 0.76.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/README.md +1 -1
- package/bin/junior.mjs +4 -66
- package/dist/agent-hooks-ZOE7RIED.js +37 -0
- package/dist/api-reference.d.ts +2 -0
- package/dist/app.js +317 -118
- package/dist/build/virtual-config.d.ts +2 -2
- package/dist/chat/agent-dispatch/runner.d.ts +2 -0
- package/dist/chat/config.d.ts +1 -0
- package/dist/chat/credentials/state-adapter-token-store.d.ts +2 -0
- package/dist/chat/credentials/user-token-store.d.ts +17 -12
- package/dist/chat/db.d.ts +8 -0
- package/dist/chat/mcp/auth-store.d.ts +2 -1
- package/dist/chat/mcp/oauth.d.ts +2 -1
- package/dist/chat/oauth-flow.d.ts +3 -1
- package/dist/chat/pi/client.d.ts +15 -7
- package/dist/chat/plugins/agent-hooks.d.ts +7 -0
- package/dist/chat/plugins/auth/oauth-request.d.ts +11 -7
- package/dist/chat/plugins/model.d.ts +9 -0
- package/dist/chat/plugins/prompt.d.ts +5 -0
- package/dist/chat/plugins/task-callback.d.ts +5 -0
- package/dist/chat/plugins/task-message.d.ts +23 -0
- package/dist/chat/plugins/task-queue.d.ts +5 -0
- package/dist/chat/plugins/task-runner.d.ts +12 -0
- package/dist/chat/plugins/task-signing.d.ts +31 -0
- package/dist/chat/prompt.d.ts +4 -0
- package/dist/chat/requester.d.ts +6 -5
- package/dist/chat/respond-helpers.d.ts +2 -0
- package/dist/chat/respond.d.ts +4 -2
- package/dist/chat/runtime/agent-continue-runner.d.ts +4 -0
- package/dist/chat/runtime/reply-executor.d.ts +5 -1
- package/dist/chat/runtime/slack-resume.d.ts +10 -2
- package/dist/chat/sentry.d.ts +1 -0
- package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -1
- package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
- package/dist/chat/services/subscribed-decision.d.ts +2 -2
- package/dist/chat/services/turn-session-record.d.ts +11 -7
- package/dist/chat/state/turn-session.d.ts +8 -5
- package/dist/chat/tools/agent-tools.d.ts +8 -1
- package/dist/chat/tools/slack/context.d.ts +2 -2
- package/dist/chat/tools/types.d.ts +4 -4
- package/dist/chat/vercel-queue-client.d.ts +3 -0
- package/dist/{chunk-C3AM4Z4J.js → chunk-2ECJXSVQ.js} +5 -5
- package/dist/{chunk-OJODNL2P.js → chunk-4SCWV7TJ.js} +2 -2
- package/dist/chunk-4UO6FK4G.js +64 -0
- package/dist/{chunk-BNJIEFQC.js → chunk-56TBVRJG.js} +2 -2
- package/dist/{chunk-OK4KKR7B.js → chunk-EJN6G5A2.js} +28 -12
- package/dist/{chunk-TQ74BATR.js → chunk-HHDUKWVG.js} +428 -111
- package/dist/{chunk-XJHDZUGD.js → chunk-JBASI5VV.js} +4 -4
- package/dist/chunk-KNFROR7R.js +127 -0
- package/dist/{chunk-VNTLUFTY.js → chunk-KOIMO7S3.js} +126 -87
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/{chunk-NPVUAXUE.js → chunk-NFTMTIP3.js} +303 -33
- package/dist/chunk-NYKJ3KON.js +1082 -0
- package/dist/{chunk-SJHUF3DP.js → chunk-OJ53FYVG.js} +2 -10
- package/dist/{chunk-62FUNJYS.js → chunk-Q6XFTRV5.js} +54 -3
- package/dist/{chunk-UJ7OTHPO.js → chunk-R6Z5XWY3.js} +12 -670
- package/dist/chunk-RV5RYIJW.js +56 -0
- package/dist/{chunk-EE6PJWY4.js → chunk-SG5WAA7H.js} +7 -5
- package/dist/chunk-ST6YNAXG.js +54 -0
- package/dist/{chunk-FCZO7LAR.js → chunk-T77LUIX3.js} +139 -153
- package/dist/{chunk-EIYL7I4S.js → chunk-VALUBQ7R.js} +22 -30
- package/dist/{chunk-OZSPLAQ4.js → chunk-XBBC6W45.js} +1 -1
- package/dist/{chunk-ZNNTSPNF.js → chunk-Y5OFBCBZ.js} +1 -1
- package/dist/{chunk-74HO27II.js → chunk-Z4CIQ3EB.js} +5 -1
- package/dist/{chunk-2RWFUS5F.js → chunk-ZLMBNBUG.js} +101 -44
- package/dist/{chunk-JEELK46E.js → chunk-ZQB37HUX.js} +11 -11
- package/dist/cli/chat.js +52 -23
- package/dist/cli/check.js +7 -7
- package/dist/cli/env.js +4 -53
- package/dist/cli/init.js +6 -1
- package/dist/cli/main.js +84 -0
- package/dist/cli/plugins.js +244 -0
- package/dist/cli/run.js +5 -52
- package/dist/cli/snapshot-warmup.js +9 -9
- package/dist/cli/upgrade.js +167 -48
- package/dist/db-7A7PFRGL.js +17 -0
- package/dist/deployment.d.ts +1 -0
- package/dist/instrumentation.js +14 -18
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +43 -22
- package/dist/plugins-PZMDS7AT.js +15 -0
- package/dist/plugins.d.ts +4 -2
- package/dist/{registry-NLZFIW23.js → registry-OIPAJU2O.js} +6 -6
- package/dist/reporting.js +34 -26
- package/dist/{runner-LUQZ5G67.js → runner-KPLNHDCV.js} +76 -23
- package/dist/sentry-4CP5NNQ5.js +31 -0
- package/dist/validation-SLA6IGF7.js +15 -0
- package/dist/vercel.js +1 -1
- package/package.json +7 -6
- package/dist/agent-hooks-2HEB4C3Q.js +0 -33
- package/dist/chat/conversations/configured.d.ts +0 -7
- package/dist/chat/conversations/state.d.ts +0 -4
- package/dist/chat/plugins/db.d.ts +0 -31
- package/dist/chunk-2KG3PWR4.js +0 -17
- package/dist/chunk-D7NFH5GD.js +0 -570
- package/dist/chunk-MCMROINU.js +0 -12
- package/dist/chunk-WBZ4M5N5.js +0 -59
- package/dist/db-A3ILH67H.js +0 -20
- package/dist/plugins-OMJKLRJ2.js +0 -13
- package/dist/validation-VMCPP3YO.js +0 -15
package/dist/app.js
CHANGED
|
@@ -53,10 +53,12 @@ import {
|
|
|
53
53
|
persistThreadState,
|
|
54
54
|
persistThreadStateById,
|
|
55
55
|
postSlackMessage,
|
|
56
|
+
processPluginTask,
|
|
56
57
|
removeReactionFromMessage,
|
|
57
58
|
renderSlackLegacyAttachmentText,
|
|
58
59
|
resolveBaseUrl,
|
|
59
60
|
resolveSandboxEgressProviderForHost,
|
|
61
|
+
scheduleSessionCompletedPluginTasks,
|
|
60
62
|
setConfigDefaults,
|
|
61
63
|
setSandboxEgressAuthRequiredSignal,
|
|
62
64
|
setSandboxEgressCredentialLease,
|
|
@@ -69,12 +71,41 @@ import {
|
|
|
69
71
|
updateConversationStats,
|
|
70
72
|
uploadFilesToThread,
|
|
71
73
|
upsertConversationMessage
|
|
72
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-HHDUKWVG.js";
|
|
75
|
+
import {
|
|
76
|
+
CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
|
|
77
|
+
CONVERSATION_WORK_STALE_ENQUEUE_MS,
|
|
78
|
+
appendInboundMessage,
|
|
79
|
+
checkInConversationWork,
|
|
80
|
+
clearExpiredConversationLease,
|
|
81
|
+
completeConversationWork,
|
|
82
|
+
drainConversationMailbox,
|
|
83
|
+
getConversation,
|
|
84
|
+
getConversationWorkState,
|
|
85
|
+
listActiveConversationIds,
|
|
86
|
+
markConversationMessagesInjected,
|
|
87
|
+
markConversationWorkEnqueued,
|
|
88
|
+
releaseConversationWork,
|
|
89
|
+
removeActiveConversation,
|
|
90
|
+
requestConversationContinuation,
|
|
91
|
+
requestConversationWork,
|
|
92
|
+
startConversationWork
|
|
93
|
+
} from "./chunk-R6Z5XWY3.js";
|
|
94
|
+
import {
|
|
95
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
96
|
+
coerceThreadConversationState
|
|
97
|
+
} from "./chunk-Z4CIQ3EB.js";
|
|
98
|
+
import "./chunk-JBASI5VV.js";
|
|
73
99
|
import {
|
|
74
100
|
getVercelConversationWorkQueue,
|
|
75
101
|
resolveConversationWorkQueueTopic,
|
|
76
102
|
verifyConversationQueueMessage
|
|
77
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-2ECJXSVQ.js";
|
|
104
|
+
import {
|
|
105
|
+
PLUGIN_TASK_QUEUE_TOPIC,
|
|
106
|
+
createVercelQueueClient,
|
|
107
|
+
verifyPluginTaskQueueMessage
|
|
108
|
+
} from "./chunk-KNFROR7R.js";
|
|
78
109
|
import {
|
|
79
110
|
GET,
|
|
80
111
|
buildSentryConversationUrl,
|
|
@@ -82,7 +113,7 @@ import {
|
|
|
82
113
|
resolveSlackChannelTypeFromMessage,
|
|
83
114
|
resolveSlackConversationContext,
|
|
84
115
|
setConversationTitle
|
|
85
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-ZQB37HUX.js";
|
|
86
117
|
import {
|
|
87
118
|
abandonAgentTurnSessionRecord,
|
|
88
119
|
buildSlackOutputMessage,
|
|
@@ -90,7 +121,6 @@ import {
|
|
|
90
121
|
escapeXml,
|
|
91
122
|
failAgentTurnSessionRecord,
|
|
92
123
|
getAgentTurnSessionRecord,
|
|
93
|
-
getConfiguredConversationStore,
|
|
94
124
|
getInterruptionMarker,
|
|
95
125
|
listAgentTurnSessionSummariesForConversation,
|
|
96
126
|
loadProjection,
|
|
@@ -99,7 +129,17 @@ import {
|
|
|
99
129
|
recordAuthorizationCompleted,
|
|
100
130
|
splitSlackReplyText,
|
|
101
131
|
truncateStatusText
|
|
102
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-KOIMO7S3.js";
|
|
133
|
+
import {
|
|
134
|
+
validatePluginEgressCredentialHooks,
|
|
135
|
+
validatePluginRegistrations
|
|
136
|
+
} from "./chunk-XBBC6W45.js";
|
|
137
|
+
import {
|
|
138
|
+
defineJuniorPlugins,
|
|
139
|
+
pluginCatalogConfigFromEnv,
|
|
140
|
+
pluginCatalogConfigFromPluginSet,
|
|
141
|
+
pluginRuntimeRegistrationsFromPluginSet
|
|
142
|
+
} from "./chunk-SG5WAA7H.js";
|
|
103
143
|
import {
|
|
104
144
|
bindSlackDirectCredentialSubject,
|
|
105
145
|
getPluginRoutes,
|
|
@@ -108,71 +148,32 @@ import {
|
|
|
108
148
|
setPlugins,
|
|
109
149
|
validatePlugins,
|
|
110
150
|
verifySlackDirectCredentialSubject
|
|
111
|
-
} from "./chunk-
|
|
112
|
-
import {
|
|
113
|
-
validatePluginEgressCredentialHooks,
|
|
114
|
-
validatePluginRegistrations
|
|
115
|
-
} from "./chunk-OZSPLAQ4.js";
|
|
116
|
-
import {
|
|
117
|
-
discoverSkills
|
|
118
|
-
} from "./chunk-OJODNL2P.js";
|
|
151
|
+
} from "./chunk-NFTMTIP3.js";
|
|
119
152
|
import {
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
createPluginLogger,
|
|
154
|
+
createPluginState
|
|
155
|
+
} from "./chunk-56TBVRJG.js";
|
|
122
156
|
import {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
} from "./chunk-EE6PJWY4.js";
|
|
157
|
+
getConversationStore,
|
|
158
|
+
getDb
|
|
159
|
+
} from "./chunk-NYKJ3KON.js";
|
|
160
|
+
import "./chunk-G3E7SCME.js";
|
|
128
161
|
import {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
appendInboundMessage,
|
|
133
|
-
checkInConversationWork,
|
|
134
|
-
clearExpiredConversationLease,
|
|
135
|
-
completeConversationWork,
|
|
136
|
-
drainConversationMailbox,
|
|
137
|
-
getConversation,
|
|
138
|
-
getConversationWorkState,
|
|
139
|
-
listActiveConversationIds,
|
|
140
|
-
markConversationMessagesInjected,
|
|
141
|
-
markConversationWorkEnqueued,
|
|
142
|
-
releaseConversationWork,
|
|
143
|
-
removeActiveConversation,
|
|
144
|
-
requestConversationContinuation,
|
|
145
|
-
requestConversationWork,
|
|
146
|
-
startConversationWork
|
|
147
|
-
} from "./chunk-UJ7OTHPO.js";
|
|
162
|
+
ACTIVE_LOCK_TTL_MS,
|
|
163
|
+
getStateAdapter
|
|
164
|
+
} from "./chunk-Y5OFBCBZ.js";
|
|
148
165
|
import {
|
|
149
166
|
createSlackDestination,
|
|
150
167
|
destinationKey,
|
|
151
|
-
parseDestination,
|
|
152
|
-
requireSlackDestination,
|
|
153
|
-
sameDestination
|
|
154
|
-
} from "./chunk-WBZ4M5N5.js";
|
|
155
|
-
import {
|
|
156
|
-
createPluginLogger,
|
|
157
|
-
createPluginState
|
|
158
|
-
} from "./chunk-BNJIEFQC.js";
|
|
159
|
-
import {
|
|
160
168
|
downloadPrivateSlackFile,
|
|
161
169
|
getHeaderString,
|
|
162
170
|
getSlackClient,
|
|
163
171
|
isDmChannel,
|
|
164
|
-
normalizeSlackConversationId
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
} from "./chunk-D7NFH5GD.js";
|
|
170
|
-
import "./chunk-XJHDZUGD.js";
|
|
171
|
-
import "./chunk-G3E7SCME.js";
|
|
172
|
-
import {
|
|
173
|
-
ACTIVE_LOCK_TTL_MS,
|
|
174
|
-
getStateAdapter
|
|
175
|
-
} from "./chunk-ZNNTSPNF.js";
|
|
172
|
+
normalizeSlackConversationId,
|
|
173
|
+
parseDestination,
|
|
174
|
+
requireSlackDestination,
|
|
175
|
+
sameDestination
|
|
176
|
+
} from "./chunk-Q6XFTRV5.js";
|
|
176
177
|
import {
|
|
177
178
|
FUNCTION_TIMEOUT_BUFFER_SECONDS,
|
|
178
179
|
GEN_AI_PROVIDER_NAME,
|
|
@@ -194,7 +195,10 @@ import {
|
|
|
194
195
|
setSlackReactionConfig,
|
|
195
196
|
stripRuntimeTurnContext,
|
|
196
197
|
trimTrailingAssistantMessages
|
|
197
|
-
} from "./chunk-
|
|
198
|
+
} from "./chunk-T77LUIX3.js";
|
|
199
|
+
import {
|
|
200
|
+
discoverSkills
|
|
201
|
+
} from "./chunk-4SCWV7TJ.js";
|
|
198
202
|
import {
|
|
199
203
|
CredentialUnavailableError,
|
|
200
204
|
buildOAuthTokenRequest,
|
|
@@ -205,19 +209,18 @@ import {
|
|
|
205
209
|
isPluginProvider,
|
|
206
210
|
parseOAuthTokenResponse,
|
|
207
211
|
setPluginCatalogConfig
|
|
208
|
-
} from "./chunk-
|
|
209
|
-
import {
|
|
210
|
-
homeDir
|
|
211
|
-
} from "./chunk-Q3XNY442.js";
|
|
212
|
+
} from "./chunk-ZLMBNBUG.js";
|
|
212
213
|
import {
|
|
213
214
|
createRequester,
|
|
214
|
-
createRequesterFromStoredSlackRequester,
|
|
215
215
|
createSlackRequester,
|
|
216
|
+
createSlackResumeRequester,
|
|
216
217
|
isActorUserId,
|
|
217
218
|
parseActorUserId,
|
|
218
219
|
toStoredSlackRequester
|
|
219
|
-
} from "./chunk-
|
|
220
|
-
import
|
|
220
|
+
} from "./chunk-VALUBQ7R.js";
|
|
221
|
+
import {
|
|
222
|
+
homeDir
|
|
223
|
+
} from "./chunk-Q3XNY442.js";
|
|
221
224
|
import {
|
|
222
225
|
buildTurnFailureResponse,
|
|
223
226
|
createChatSdkLogger,
|
|
@@ -234,11 +237,14 @@ import {
|
|
|
234
237
|
toOptionalString,
|
|
235
238
|
withContext,
|
|
236
239
|
withSpan
|
|
237
|
-
} from "./chunk-
|
|
240
|
+
} from "./chunk-EJN6G5A2.js";
|
|
238
241
|
import {
|
|
239
|
-
|
|
240
|
-
} from "./chunk-
|
|
241
|
-
import
|
|
242
|
+
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
|
|
243
|
+
} from "./chunk-OJ53FYVG.js";
|
|
244
|
+
import {
|
|
245
|
+
continueTrace
|
|
246
|
+
} from "./chunk-ST6YNAXG.js";
|
|
247
|
+
import "./chunk-MLKGABMK.js";
|
|
242
248
|
|
|
243
249
|
// src/app.ts
|
|
244
250
|
import { Hono } from "hono";
|
|
@@ -738,11 +744,7 @@ function buildDispatchId(plugin, idempotencyKey) {
|
|
|
738
744
|
return `dispatch_${digest}`;
|
|
739
745
|
}
|
|
740
746
|
function parseDispatchRecord(value) {
|
|
741
|
-
const
|
|
742
|
-
...value,
|
|
743
|
-
source: value.destination
|
|
744
|
-
} : value;
|
|
745
|
-
const parsed = dispatchRecordSchema.safeParse(candidate);
|
|
747
|
+
const parsed = dispatchRecordSchema.safeParse(value);
|
|
746
748
|
return parsed.success ? parsed.data : void 0;
|
|
747
749
|
}
|
|
748
750
|
function getDispatchDestinationLockId(destination) {
|
|
@@ -962,6 +964,7 @@ function canClaimDispatch(record, nowMs) {
|
|
|
962
964
|
async function runAgentDispatchSlice(callback, deps = {}) {
|
|
963
965
|
const generateAssistantReply2 = deps.generateAssistantReply ?? generateAssistantReply;
|
|
964
966
|
const scheduleCallback = deps.scheduleCallback ?? scheduleDispatchCallback;
|
|
967
|
+
const scheduleCompletedTasks = deps.scheduleSessionCompletedPluginTasks ?? scheduleSessionCompletedPluginTasks;
|
|
965
968
|
const nowMs = Date.now();
|
|
966
969
|
const claimedDispatch = await withDispatchLock(callback.id, async (state) => {
|
|
967
970
|
const current = parseDispatchRecord(
|
|
@@ -1159,6 +1162,30 @@ async function runAgentDispatchSlice(callback, deps = {}) {
|
|
|
1159
1162
|
...failure ? { errorMessage: failure } : {},
|
|
1160
1163
|
resultMessageTs
|
|
1161
1164
|
});
|
|
1165
|
+
if (!failure) {
|
|
1166
|
+
try {
|
|
1167
|
+
await scheduleCompletedTasks({
|
|
1168
|
+
conversationId,
|
|
1169
|
+
sessionId: getDispatchTurnId(dispatch.id)
|
|
1170
|
+
});
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
logException(
|
|
1173
|
+
error,
|
|
1174
|
+
"plugin_session_completed_task_schedule_failed",
|
|
1175
|
+
{
|
|
1176
|
+
conversationId,
|
|
1177
|
+
slackThreadId: conversationId,
|
|
1178
|
+
slackChannelId: dispatch.destination.channelId,
|
|
1179
|
+
runId: dispatch.id,
|
|
1180
|
+
actorType: dispatch.actor.type,
|
|
1181
|
+
actorId: dispatch.actor.id,
|
|
1182
|
+
assistantUserName: botConfig.userName
|
|
1183
|
+
},
|
|
1184
|
+
{},
|
|
1185
|
+
"Plugin session.completed task scheduling failed"
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1162
1189
|
} catch (error) {
|
|
1163
1190
|
if (error instanceof AuthorizationFlowDisabledError) {
|
|
1164
1191
|
await markDispatch({
|
|
@@ -1251,7 +1278,7 @@ import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
|
1251
1278
|
|
|
1252
1279
|
// src/chat/task-execution/store.ts
|
|
1253
1280
|
function metadataStore(options) {
|
|
1254
|
-
return options.conversationStore ??
|
|
1281
|
+
return options.conversationStore ?? getConversationStore();
|
|
1255
1282
|
}
|
|
1256
1283
|
function duplicateInboundNudgeIdempotencyKey(message, nowMs) {
|
|
1257
1284
|
return `duplicate:${message.conversationId}:${message.inboundMessageId}:${nowMs}`;
|
|
@@ -1695,12 +1722,11 @@ function bindDispatchCredentialSubject(options) {
|
|
|
1695
1722
|
}
|
|
1696
1723
|
function createHeartbeatContext(args) {
|
|
1697
1724
|
const pluginName = typeof args.plugin === "string" ? args.plugin : args.plugin.manifest.name;
|
|
1698
|
-
const db = typeof args.plugin === "string" ? void 0 : getPluginDbForRegistration(args.plugin);
|
|
1699
1725
|
let dispatchCount = 0;
|
|
1700
1726
|
return {
|
|
1701
1727
|
plugin: { name: pluginName },
|
|
1702
1728
|
nowMs: args.nowMs,
|
|
1703
|
-
|
|
1729
|
+
db: getDb(),
|
|
1704
1730
|
state: createPluginState(pluginName),
|
|
1705
1731
|
log: createPluginLogger(pluginName),
|
|
1706
1732
|
agent: {
|
|
@@ -2708,6 +2734,10 @@ function createResumeReplyContext(args, statusSession) {
|
|
|
2708
2734
|
if (!replyContext) {
|
|
2709
2735
|
throw new TypeError("Slack resume requires a reply context");
|
|
2710
2736
|
}
|
|
2737
|
+
if (!replyContext.source) {
|
|
2738
|
+
throw new TypeError("Slack resume requires a reply context source");
|
|
2739
|
+
}
|
|
2740
|
+
const source = replyContext.source;
|
|
2711
2741
|
if (replyContext.destination.platform !== "slack") {
|
|
2712
2742
|
throw new TypeError("Slack resume requires a Slack destination");
|
|
2713
2743
|
}
|
|
@@ -2716,6 +2746,7 @@ function createResumeReplyContext(args, statusSession) {
|
|
|
2716
2746
|
const persistedChannelConfiguration = replyContext.channelConfiguration ?? (replyContext.configuration ? createReadOnlyConfigService(replyContext.configuration) : void 0);
|
|
2717
2747
|
return {
|
|
2718
2748
|
...replyContext,
|
|
2749
|
+
source,
|
|
2719
2750
|
turnDeadlineAtMs: replyContext.turnDeadlineAtMs ?? requestDeadline?.deadlineAtMs,
|
|
2720
2751
|
correlation: {
|
|
2721
2752
|
...replyContext.correlation,
|
|
@@ -2833,6 +2864,27 @@ async function resumeSlackTurn(args) {
|
|
|
2833
2864
|
});
|
|
2834
2865
|
finalReplyDelivered = true;
|
|
2835
2866
|
await runArgs.onSuccess?.(reply);
|
|
2867
|
+
if (reply.diagnostics.outcome === "success" && replyContext.correlation?.conversationId && replyContext.correlation.turnId) {
|
|
2868
|
+
try {
|
|
2869
|
+
const params = {
|
|
2870
|
+
conversationId: replyContext.correlation.conversationId,
|
|
2871
|
+
sessionId: replyContext.correlation.turnId
|
|
2872
|
+
};
|
|
2873
|
+
if (runArgs.scheduleSessionCompletedPluginTasks) {
|
|
2874
|
+
await runArgs.scheduleSessionCompletedPluginTasks(params);
|
|
2875
|
+
} else {
|
|
2876
|
+
await scheduleSessionCompletedPluginTasks(params);
|
|
2877
|
+
}
|
|
2878
|
+
} catch (scheduleError) {
|
|
2879
|
+
logException(
|
|
2880
|
+
scheduleError,
|
|
2881
|
+
"plugin_session_completed_task_schedule_failed",
|
|
2882
|
+
getResumeLogContext(runArgs, lockKey),
|
|
2883
|
+
{},
|
|
2884
|
+
"Plugin session.completed task scheduling failed"
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2836
2888
|
} catch (error) {
|
|
2837
2889
|
await status.stop();
|
|
2838
2890
|
const onAuthPause = runArgs.onAuthPause;
|
|
@@ -3236,7 +3288,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
3236
3288
|
);
|
|
3237
3289
|
let requester;
|
|
3238
3290
|
try {
|
|
3239
|
-
requester =
|
|
3291
|
+
requester = createSlackResumeRequester({
|
|
3240
3292
|
requester: lockedSessionRecord.requester,
|
|
3241
3293
|
teamId: destination.teamId,
|
|
3242
3294
|
userId: authSession.userId
|
|
@@ -3250,6 +3302,15 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
3250
3302
|
});
|
|
3251
3303
|
return false;
|
|
3252
3304
|
}
|
|
3305
|
+
if (!lockedSessionRecord.source) {
|
|
3306
|
+
await failAgentTurnSessionRecord({
|
|
3307
|
+
conversationId: authSession.conversationId,
|
|
3308
|
+
expectedVersion: lockedSessionRecord.version,
|
|
3309
|
+
sessionId: lockedSessionId,
|
|
3310
|
+
errorMessage: "Stored Slack source missing for MCP OAuth resume"
|
|
3311
|
+
});
|
|
3312
|
+
return false;
|
|
3313
|
+
}
|
|
3253
3314
|
await recordAuthorizationCompleted({
|
|
3254
3315
|
conversationId: authSession.conversationId,
|
|
3255
3316
|
kind: "mcp",
|
|
@@ -3261,15 +3322,17 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
3261
3322
|
}),
|
|
3262
3323
|
ttlMs: THREAD_STATE_TTL_MS
|
|
3263
3324
|
});
|
|
3325
|
+
const lockedMessageTs = getTurnUserSlackMessageTs(lockedUserMessage);
|
|
3264
3326
|
return {
|
|
3265
3327
|
messageText: lockedUserMessage.text,
|
|
3266
|
-
messageTs:
|
|
3328
|
+
messageTs: lockedMessageTs,
|
|
3267
3329
|
replyContext: {
|
|
3268
3330
|
credentialContext: {
|
|
3269
3331
|
actor: { type: "user", userId: requester.userId }
|
|
3270
3332
|
},
|
|
3271
3333
|
requester,
|
|
3272
3334
|
destination,
|
|
3335
|
+
source: lockedSessionRecord.source,
|
|
3273
3336
|
correlation: {
|
|
3274
3337
|
conversationId: authSession.conversationId,
|
|
3275
3338
|
turnId: lockedSessionId,
|
|
@@ -3459,11 +3522,10 @@ function pluginFor(provider) {
|
|
|
3459
3522
|
}
|
|
3460
3523
|
function basePluginContext(plugin) {
|
|
3461
3524
|
const pluginName = plugin.manifest.name;
|
|
3462
|
-
const db = getPluginDbForRegistration(plugin);
|
|
3463
3525
|
return {
|
|
3464
3526
|
plugin: { name: pluginName },
|
|
3465
3527
|
log: createPluginLogger(pluginName),
|
|
3466
|
-
|
|
3528
|
+
db: getDb()
|
|
3467
3529
|
};
|
|
3468
3530
|
}
|
|
3469
3531
|
function parseCredentialResult(value, pluginName) {
|
|
@@ -3572,7 +3634,12 @@ async function issuePluginCredential(input) {
|
|
|
3572
3634
|
plugin.manifest.name,
|
|
3573
3635
|
tokens
|
|
3574
3636
|
);
|
|
3575
|
-
}
|
|
3637
|
+
},
|
|
3638
|
+
withRefresh: async (callback) => await input.userTokenStore.withRefresh(
|
|
3639
|
+
currentUserId,
|
|
3640
|
+
plugin.manifest.name,
|
|
3641
|
+
callback
|
|
3642
|
+
)
|
|
3576
3643
|
}
|
|
3577
3644
|
} : {},
|
|
3578
3645
|
...credentialSubjectUserId ? {
|
|
@@ -3588,7 +3655,12 @@ async function issuePluginCredential(input) {
|
|
|
3588
3655
|
plugin.manifest.name,
|
|
3589
3656
|
tokens
|
|
3590
3657
|
);
|
|
3591
|
-
}
|
|
3658
|
+
},
|
|
3659
|
+
withRefresh: async (callback) => await input.userTokenStore.withRefresh(
|
|
3660
|
+
credentialSubjectUserId,
|
|
3661
|
+
plugin.manifest.name,
|
|
3662
|
+
callback
|
|
3663
|
+
)
|
|
3592
3664
|
}
|
|
3593
3665
|
} : {}
|
|
3594
3666
|
}
|
|
@@ -3908,7 +3980,7 @@ async function persistFailedOAuthReplyState(args) {
|
|
|
3908
3980
|
});
|
|
3909
3981
|
}
|
|
3910
3982
|
async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
3911
|
-
if (!stored.resumeConversationId || !stored.resumeSessionId || !stored.channelId || !stored.destination || !stored.threadTs) {
|
|
3983
|
+
if (!stored.resumeConversationId || !stored.resumeSessionId || !stored.channelId || !stored.destination || !stored.source || !stored.threadTs) {
|
|
3912
3984
|
return false;
|
|
3913
3985
|
}
|
|
3914
3986
|
const destination = requireSlackDestination(
|
|
@@ -4027,7 +4099,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4027
4099
|
);
|
|
4028
4100
|
let requester;
|
|
4029
4101
|
try {
|
|
4030
|
-
requester =
|
|
4102
|
+
requester = createSlackResumeRequester({
|
|
4031
4103
|
requester: lockedSessionRecord.requester,
|
|
4032
4104
|
teamId: destination.teamId,
|
|
4033
4105
|
userId: lockedUserMessage.author.userId
|
|
@@ -4041,6 +4113,15 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4041
4113
|
});
|
|
4042
4114
|
return false;
|
|
4043
4115
|
}
|
|
4116
|
+
if (!lockedSessionRecord.source) {
|
|
4117
|
+
await failAgentTurnSessionRecord({
|
|
4118
|
+
conversationId: stored.resumeConversationId,
|
|
4119
|
+
expectedVersion: lockedSessionRecord.version,
|
|
4120
|
+
sessionId: lockedSessionId,
|
|
4121
|
+
errorMessage: "Stored Slack source missing for OAuth resume"
|
|
4122
|
+
});
|
|
4123
|
+
return false;
|
|
4124
|
+
}
|
|
4044
4125
|
await recordAuthorizationCompleted({
|
|
4045
4126
|
conversationId: stored.resumeConversationId,
|
|
4046
4127
|
kind: "plugin",
|
|
@@ -4052,9 +4133,10 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4052
4133
|
}),
|
|
4053
4134
|
ttlMs: THREAD_STATE_TTL_MS2
|
|
4054
4135
|
});
|
|
4136
|
+
const lockedMessageTs = getTurnUserSlackMessageTs(lockedUserMessage);
|
|
4055
4137
|
return {
|
|
4056
4138
|
messageText: lockedPendingAuth ? lockedUserMessage.text : stored.pendingMessage ?? lockedUserMessage.text,
|
|
4057
|
-
messageTs:
|
|
4139
|
+
messageTs: lockedMessageTs,
|
|
4058
4140
|
replyContext: {
|
|
4059
4141
|
credentialContext: {
|
|
4060
4142
|
actor: {
|
|
@@ -4064,6 +4146,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4064
4146
|
},
|
|
4065
4147
|
requester,
|
|
4066
4148
|
destination,
|
|
4149
|
+
source: lockedSessionRecord.source,
|
|
4067
4150
|
correlation: {
|
|
4068
4151
|
conversationId: stored.resumeConversationId,
|
|
4069
4152
|
turnId: lockedSessionId,
|
|
@@ -4151,7 +4234,8 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4151
4234
|
return true;
|
|
4152
4235
|
}
|
|
4153
4236
|
async function resumePendingOAuthMessage(stored, options) {
|
|
4154
|
-
|
|
4237
|
+
const source = stored.source;
|
|
4238
|
+
if (!stored.pendingMessage || !stored.channelId || !stored.destination || !source || !stored.threadTs) {
|
|
4155
4239
|
return;
|
|
4156
4240
|
}
|
|
4157
4241
|
const threadId = `slack:${stored.channelId}:${stored.threadTs}`;
|
|
@@ -4170,11 +4254,12 @@ async function resumePendingOAuthMessage(stored, options) {
|
|
|
4170
4254
|
destination.teamId,
|
|
4171
4255
|
stored.userId
|
|
4172
4256
|
);
|
|
4257
|
+
const messageTs = getTurnUserSlackMessageTs(latestUserMessage);
|
|
4173
4258
|
await resumeAuthorizedRequest({
|
|
4174
4259
|
messageText: stored.pendingMessage,
|
|
4175
4260
|
channelId: stored.channelId,
|
|
4176
4261
|
threadTs: stored.threadTs,
|
|
4177
|
-
messageTs
|
|
4262
|
+
messageTs,
|
|
4178
4263
|
connectedText: "",
|
|
4179
4264
|
generateReply: options.generateReply,
|
|
4180
4265
|
replyContext: {
|
|
@@ -4183,6 +4268,7 @@ async function resumePendingOAuthMessage(stored, options) {
|
|
|
4183
4268
|
},
|
|
4184
4269
|
requester,
|
|
4185
4270
|
destination: stored.destination,
|
|
4271
|
+
source,
|
|
4186
4272
|
correlation: {
|
|
4187
4273
|
conversationId: threadId,
|
|
4188
4274
|
channelId: stored.channelId,
|
|
@@ -5005,7 +5091,7 @@ function continueSandboxEgressTrace(request, upstreamHost, tracePropagation, cal
|
|
|
5005
5091
|
if (!shouldPropagateSandboxEgressTrace(upstreamHost, tracePropagation) || !sentryTrace && !baggage) {
|
|
5006
5092
|
return run();
|
|
5007
5093
|
}
|
|
5008
|
-
return
|
|
5094
|
+
return continueTrace({ sentryTrace, baggage }, run);
|
|
5009
5095
|
}
|
|
5010
5096
|
function isSandboxEgressForwardedRequest(request) {
|
|
5011
5097
|
return Boolean(
|
|
@@ -6645,7 +6731,6 @@ async function POST2(request, waitUntil, services) {
|
|
|
6645
6731
|
// src/chat/task-execution/vercel-callback.ts
|
|
6646
6732
|
import {
|
|
6647
6733
|
handleCallback,
|
|
6648
|
-
QueueClient,
|
|
6649
6734
|
registerDevConsumer
|
|
6650
6735
|
} from "@vercel/queue";
|
|
6651
6736
|
|
|
@@ -7113,7 +7198,7 @@ function registerVercelConversationWorkDevConsumer(options) {
|
|
|
7113
7198
|
return void 0;
|
|
7114
7199
|
}
|
|
7115
7200
|
return registerDevConsumer({
|
|
7116
|
-
client:
|
|
7201
|
+
client: createVercelQueueClient(),
|
|
7117
7202
|
consumerGroup: CONVERSATION_WORK_DEV_CONSUMER_GROUP,
|
|
7118
7203
|
handler: (message, metadata) => handleConversationQueueMessage(message, metadata, options),
|
|
7119
7204
|
retry: handleConversationQueueRetry,
|
|
@@ -7122,16 +7207,79 @@ function registerVercelConversationWorkDevConsumer(options) {
|
|
|
7122
7207
|
});
|
|
7123
7208
|
}
|
|
7124
7209
|
|
|
7210
|
+
// src/chat/plugins/task-callback.ts
|
|
7211
|
+
import {
|
|
7212
|
+
handleCallback as handleCallback2,
|
|
7213
|
+
registerDevConsumer as registerDevConsumer2
|
|
7214
|
+
} from "@vercel/queue";
|
|
7215
|
+
var PLUGIN_TASK_DEV_CONSUMER_GROUP = "junior_plugin_tasks_dev";
|
|
7216
|
+
var PLUGIN_TASK_MAX_DELIVERIES = 5;
|
|
7217
|
+
function logPluginTaskQueueMessageRejected(reason, metadata) {
|
|
7218
|
+
logWarn(
|
|
7219
|
+
"plugin_task_queue_message_rejected",
|
|
7220
|
+
{},
|
|
7221
|
+
{
|
|
7222
|
+
"app.queue.consumer_group": metadata.consumerGroup,
|
|
7223
|
+
"app.queue.delivery_count": metadata.deliveryCount,
|
|
7224
|
+
"app.queue.message_id": metadata.messageId,
|
|
7225
|
+
"app.queue.reject_reason": reason,
|
|
7226
|
+
"app.queue.topic_name": metadata.topicName
|
|
7227
|
+
},
|
|
7228
|
+
"Plugin task queue message rejected without retry"
|
|
7229
|
+
);
|
|
7230
|
+
}
|
|
7231
|
+
async function handlePluginTaskQueueMessage(message, metadata) {
|
|
7232
|
+
const verification = verifyPluginTaskQueueMessage(message);
|
|
7233
|
+
if (verification.status === "rejected") {
|
|
7234
|
+
logPluginTaskQueueMessageRejected(verification.reason, metadata);
|
|
7235
|
+
return;
|
|
7236
|
+
}
|
|
7237
|
+
if (verification.status === "unavailable") {
|
|
7238
|
+
throw new Error(
|
|
7239
|
+
`Plugin task queue message verification unavailable: ${verification.reason}`
|
|
7240
|
+
);
|
|
7241
|
+
}
|
|
7242
|
+
await runWithTurnRequestDeadline(
|
|
7243
|
+
() => processPluginTask(verification.message)
|
|
7244
|
+
);
|
|
7245
|
+
}
|
|
7246
|
+
function handlePluginTaskQueueRetry(_error, metadata) {
|
|
7247
|
+
if (metadata.deliveryCount >= PLUGIN_TASK_MAX_DELIVERIES) {
|
|
7248
|
+
return { acknowledge: true };
|
|
7249
|
+
}
|
|
7250
|
+
return void 0;
|
|
7251
|
+
}
|
|
7252
|
+
function createVercelPluginTaskCallback() {
|
|
7253
|
+
return handleCallback2(
|
|
7254
|
+
(message, metadata) => handlePluginTaskQueueMessage(message, metadata),
|
|
7255
|
+
{
|
|
7256
|
+
retry: handlePluginTaskQueueRetry
|
|
7257
|
+
}
|
|
7258
|
+
);
|
|
7259
|
+
}
|
|
7260
|
+
function registerVercelPluginTaskDevConsumer() {
|
|
7261
|
+
if (process.env.NODE_ENV !== "development") {
|
|
7262
|
+
return void 0;
|
|
7263
|
+
}
|
|
7264
|
+
return registerDevConsumer2({
|
|
7265
|
+
client: createVercelQueueClient(),
|
|
7266
|
+
consumerGroup: PLUGIN_TASK_DEV_CONSUMER_GROUP,
|
|
7267
|
+
handler: (message, metadata) => handlePluginTaskQueueMessage(message, metadata),
|
|
7268
|
+
retry: handlePluginTaskQueueRetry,
|
|
7269
|
+
topic: PLUGIN_TASK_QUEUE_TOPIC
|
|
7270
|
+
});
|
|
7271
|
+
}
|
|
7272
|
+
|
|
7125
7273
|
// src/chat/services/subscribed-decision.ts
|
|
7126
7274
|
import { z as z2 } from "zod";
|
|
7127
7275
|
var replyDecisionSchema = z2.object({
|
|
7128
7276
|
should_reply: z2.boolean().describe("Whether Junior should respond to this thread message."),
|
|
7129
|
-
should_unsubscribe: z2.boolean().
|
|
7277
|
+
should_unsubscribe: z2.boolean().describe(
|
|
7130
7278
|
"Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
|
|
7131
7279
|
),
|
|
7132
7280
|
confidence: z2.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
|
|
7133
7281
|
reason: z2.string().optional().describe("Short reason for the decision.")
|
|
7134
|
-
});
|
|
7282
|
+
}).strict();
|
|
7135
7283
|
var ROUTER_CONFIDENCE_THRESHOLD = 0.8;
|
|
7136
7284
|
var ROUTER_CLASSIFIER_MAX_TOKENS = 240;
|
|
7137
7285
|
var LEADING_SLACK_MENTION_RE = /^\s*<@([A-Z0-9]+)(?:\|([^>]+))?>[\s,:-]*/i;
|
|
@@ -9059,6 +9207,9 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
9059
9207
|
getAwaitingAgentContinueRequest: overrides.replyExecutor?.getAwaitingAgentContinueRequest ?? getAwaitingAgentContinueRequest,
|
|
9060
9208
|
lookupSlackUser: overrides.replyExecutor?.lookupSlackUser ?? lookupSlackUser,
|
|
9061
9209
|
scheduleAgentContinue: overrides.replyExecutor?.scheduleAgentContinue ?? scheduleAgentContinue,
|
|
9210
|
+
scheduleSessionCompletedPluginTasks: overrides.replyExecutor?.scheduleSessionCompletedPluginTasks ?? (async (params) => {
|
|
9211
|
+
await scheduleSessionCompletedPluginTasks(params);
|
|
9212
|
+
}),
|
|
9062
9213
|
generateThreadTitle: conversationMemory.generateThreadTitle
|
|
9063
9214
|
},
|
|
9064
9215
|
subscribedReplyPolicy: createSubscribedReplyPolicy({
|
|
@@ -9068,6 +9219,9 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
9068
9219
|
};
|
|
9069
9220
|
}
|
|
9070
9221
|
|
|
9222
|
+
// src/chat/runtime/reply-executor.ts
|
|
9223
|
+
import { createSlackSource } from "@sentry/junior-plugin-api";
|
|
9224
|
+
|
|
9071
9225
|
// src/chat/slack/message.ts
|
|
9072
9226
|
function isSlackMessageTs(value) {
|
|
9073
9227
|
return /^\d+(?:\.\d+)?$/.test(value.trim());
|
|
@@ -9277,10 +9431,11 @@ function createReplyToThread(deps) {
|
|
|
9277
9431
|
const threadId = getThreadId(thread, message);
|
|
9278
9432
|
const channelId = getChannelId(thread, message);
|
|
9279
9433
|
const channelName = channelId ? await resolveChannelName(thread) : void 0;
|
|
9434
|
+
const slackChannelType = resolveSlackChannelTypeFromMessage(message);
|
|
9280
9435
|
const slackConversation = resolveSlackConversationContext({
|
|
9281
9436
|
channelId,
|
|
9282
9437
|
channelName,
|
|
9283
|
-
channelType:
|
|
9438
|
+
channelType: slackChannelType
|
|
9284
9439
|
});
|
|
9285
9440
|
const threadTs = getThreadTs(threadId);
|
|
9286
9441
|
const assistantThreadContext = getAssistantThreadContext(message);
|
|
@@ -9290,6 +9445,12 @@ function createReplyToThread(deps) {
|
|
|
9290
9445
|
"Slack reply execution"
|
|
9291
9446
|
);
|
|
9292
9447
|
const teamId = destination.teamId;
|
|
9448
|
+
const source = createSlackSource({
|
|
9449
|
+
channelId: channelId ?? destination.channelId,
|
|
9450
|
+
messageTs,
|
|
9451
|
+
teamId,
|
|
9452
|
+
threadTs
|
|
9453
|
+
});
|
|
9293
9454
|
const runId = getRunId(thread, message);
|
|
9294
9455
|
const conversationId = threadId ?? runId;
|
|
9295
9456
|
await withSpan(
|
|
@@ -9329,12 +9490,12 @@ function createReplyToThread(deps) {
|
|
|
9329
9490
|
)
|
|
9330
9491
|
)
|
|
9331
9492
|
);
|
|
9332
|
-
const
|
|
9493
|
+
const requester = await ensureSlackMessageActorIdentity(
|
|
9333
9494
|
message,
|
|
9334
9495
|
teamId,
|
|
9335
9496
|
deps.services.lookupSlackUser
|
|
9336
9497
|
);
|
|
9337
|
-
const
|
|
9498
|
+
const storedRequester = turnRequester(requester);
|
|
9338
9499
|
const preparedState = options.preparedState ?? await deps.prepareTurnState({
|
|
9339
9500
|
thread,
|
|
9340
9501
|
message,
|
|
@@ -9515,6 +9676,7 @@ function createReplyToThread(deps) {
|
|
|
9515
9676
|
surface: "slack",
|
|
9516
9677
|
requester,
|
|
9517
9678
|
destination,
|
|
9679
|
+
source,
|
|
9518
9680
|
traceId: getActiveTraceId()
|
|
9519
9681
|
}).catch((error) => {
|
|
9520
9682
|
logException(
|
|
@@ -9528,7 +9690,7 @@ function createReplyToThread(deps) {
|
|
|
9528
9690
|
void initConversationContext(conversationId, {
|
|
9529
9691
|
channelName,
|
|
9530
9692
|
originSurface: "slack",
|
|
9531
|
-
originRequester:
|
|
9693
|
+
originRequester: storedRequester,
|
|
9532
9694
|
startedAtMs: turnStartedAtMs
|
|
9533
9695
|
}).catch((error) => {
|
|
9534
9696
|
logException(
|
|
@@ -9578,12 +9740,12 @@ function createReplyToThread(deps) {
|
|
|
9578
9740
|
if (message.author.userId) {
|
|
9579
9741
|
setSentryUser({
|
|
9580
9742
|
id: message.author.userId,
|
|
9581
|
-
...
|
|
9582
|
-
...
|
|
9743
|
+
...requester.userName ? { username: requester.userName } : {},
|
|
9744
|
+
...requester.email ? { email: requester.email } : {}
|
|
9583
9745
|
});
|
|
9584
9746
|
}
|
|
9585
|
-
if (
|
|
9586
|
-
setTags({ slackUserName:
|
|
9747
|
+
if (requester.userName) {
|
|
9748
|
+
setTags({ slackUserName: requester.userName });
|
|
9587
9749
|
}
|
|
9588
9750
|
const turnAttachments = collectTurnAttachments(
|
|
9589
9751
|
message,
|
|
@@ -9763,7 +9925,7 @@ function createReplyToThread(deps) {
|
|
|
9763
9925
|
credentialContext: {
|
|
9764
9926
|
actor: { type: "user", userId: message.author.userId }
|
|
9765
9927
|
},
|
|
9766
|
-
requester
|
|
9928
|
+
requester,
|
|
9767
9929
|
conversationContext: preparedState.conversationContext,
|
|
9768
9930
|
artifactState: preparedState.artifacts,
|
|
9769
9931
|
piMessages,
|
|
@@ -9774,6 +9936,7 @@ function createReplyToThread(deps) {
|
|
|
9774
9936
|
omittedImageAttachmentCount,
|
|
9775
9937
|
userAttachments,
|
|
9776
9938
|
slackConversation,
|
|
9939
|
+
source,
|
|
9777
9940
|
destination,
|
|
9778
9941
|
surface: "slack",
|
|
9779
9942
|
turnDeadlineAtMs: getTurnRequestDeadline()?.deadlineAtMs,
|
|
@@ -9940,6 +10103,7 @@ function createReplyToThread(deps) {
|
|
|
9940
10103
|
state: "completed",
|
|
9941
10104
|
requester,
|
|
9942
10105
|
destination,
|
|
10106
|
+
source,
|
|
9943
10107
|
traceId: getActiveTraceId()
|
|
9944
10108
|
});
|
|
9945
10109
|
}
|
|
@@ -9958,6 +10122,22 @@ function createReplyToThread(deps) {
|
|
|
9958
10122
|
);
|
|
9959
10123
|
}
|
|
9960
10124
|
await options.onTurnCompleted?.();
|
|
10125
|
+
if (reply.diagnostics.outcome === "success" && conversationId) {
|
|
10126
|
+
try {
|
|
10127
|
+
await deps.services.scheduleSessionCompletedPluginTasks({
|
|
10128
|
+
conversationId,
|
|
10129
|
+
sessionId: turnId
|
|
10130
|
+
});
|
|
10131
|
+
} catch (error) {
|
|
10132
|
+
logException(
|
|
10133
|
+
error,
|
|
10134
|
+
"plugin_session_completed_task_schedule_failed",
|
|
10135
|
+
turnTraceContext,
|
|
10136
|
+
{},
|
|
10137
|
+
"Plugin session.completed task scheduling failed"
|
|
10138
|
+
);
|
|
10139
|
+
}
|
|
10140
|
+
}
|
|
9961
10141
|
} catch (error) {
|
|
9962
10142
|
if (isCooperativeTurnYieldError(error)) {
|
|
9963
10143
|
shouldPersistFailureState = false;
|
|
@@ -10093,6 +10273,7 @@ function createReplyToThread(deps) {
|
|
|
10093
10273
|
state: "failed",
|
|
10094
10274
|
requester,
|
|
10095
10275
|
destination,
|
|
10276
|
+
source,
|
|
10096
10277
|
traceId: getActiveTraceId()
|
|
10097
10278
|
});
|
|
10098
10279
|
const sessionRecord = await getAgentTurnSessionRecord(
|
|
@@ -10642,6 +10823,7 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
10642
10823
|
threadTs: thread.threadTs,
|
|
10643
10824
|
lockKey: payload.conversationId,
|
|
10644
10825
|
generateReply: options.generateReply,
|
|
10826
|
+
scheduleSessionCompletedPluginTasks: options.scheduleSessionCompletedPluginTasks,
|
|
10645
10827
|
beforeStart: async () => {
|
|
10646
10828
|
let sessionRecord;
|
|
10647
10829
|
try {
|
|
@@ -10678,11 +10860,20 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
10678
10860
|
payload.destination,
|
|
10679
10861
|
"Slack continuation"
|
|
10680
10862
|
);
|
|
10681
|
-
const requester =
|
|
10863
|
+
const requester = createSlackResumeRequester({
|
|
10682
10864
|
requester: activeSessionRecord.requester,
|
|
10683
10865
|
teamId: destination.teamId,
|
|
10684
10866
|
userId: userMessage2.author.userId
|
|
10685
10867
|
});
|
|
10868
|
+
if (!activeSessionRecord.source) {
|
|
10869
|
+
await failAgentTurnSessionRecord({
|
|
10870
|
+
conversationId: payload.conversationId,
|
|
10871
|
+
expectedVersion: activeSessionRecord.version,
|
|
10872
|
+
sessionId: payload.sessionId,
|
|
10873
|
+
errorMessage: "Stored Slack source missing for continuation"
|
|
10874
|
+
});
|
|
10875
|
+
return false;
|
|
10876
|
+
}
|
|
10686
10877
|
return {
|
|
10687
10878
|
messageText: userMessage2.text,
|
|
10688
10879
|
messageTs: getTurnUserSlackMessageTs(userMessage2),
|
|
@@ -10695,6 +10886,7 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
10695
10886
|
},
|
|
10696
10887
|
requester,
|
|
10697
10888
|
destination: payload.destination,
|
|
10889
|
+
source: activeSessionRecord.source,
|
|
10698
10890
|
correlation: {
|
|
10699
10891
|
conversationId: payload.conversationId,
|
|
10700
10892
|
turnId: payload.sessionId,
|
|
@@ -10878,7 +11070,7 @@ function getProductionSlackAdapter() {
|
|
|
10878
11070
|
return productionSlackAdapter;
|
|
10879
11071
|
}
|
|
10880
11072
|
function getProductionConversationStore() {
|
|
10881
|
-
return
|
|
11073
|
+
return getConversationStore();
|
|
10882
11074
|
}
|
|
10883
11075
|
function createProductionSlackWebhookServices(options) {
|
|
10884
11076
|
const conversationStore = getProductionConversationStore();
|
|
@@ -10910,7 +11102,8 @@ function createProductionConversationWorkOptions(options) {
|
|
|
10910
11102
|
generateReply: withSandboxTracePropagation(
|
|
10911
11103
|
generateAssistantReply,
|
|
10912
11104
|
options?.services?.sandbox?.tracePropagation
|
|
10913
|
-
)
|
|
11105
|
+
),
|
|
11106
|
+
scheduleSessionCompletedPluginTasks: options?.services?.replyExecutor?.scheduleSessionCompletedPluginTasks
|
|
10914
11107
|
}),
|
|
10915
11108
|
runtime
|
|
10916
11109
|
})
|
|
@@ -10938,7 +11131,7 @@ async function resolveVirtualConfig() {
|
|
|
10938
11131
|
return {
|
|
10939
11132
|
pluginSet: mod.pluginSet,
|
|
10940
11133
|
plugins: mod.plugins,
|
|
10941
|
-
|
|
11134
|
+
pluginRuntimeRegistrations: mod.pluginRuntimeRegistrations ?? []
|
|
10942
11135
|
};
|
|
10943
11136
|
} catch (error) {
|
|
10944
11137
|
if (!isMissingVirtualConfig(error)) {
|
|
@@ -10980,22 +11173,22 @@ function validateBuildIncludesPluginPackages(pluginConfig, virtualConfig) {
|
|
|
10980
11173
|
`createApp() registered plugin package(s) not bundled by juniorNitro(): ${missing.join(", ")}. Point juniorNitro({ plugins: "./plugins" }) at the runtime plugin module or pass the same defineJuniorPlugins(...) set to juniorNitro({ plugins }) and createApp({ plugins }).`
|
|
10981
11174
|
);
|
|
10982
11175
|
}
|
|
10983
|
-
function
|
|
10984
|
-
const
|
|
10985
|
-
if (
|
|
11176
|
+
function validateBuildIncludesPluginRuntimeRegistrations(runtimeRegistrations, virtualConfig) {
|
|
11177
|
+
const bundledRuntimeRegistrations = virtualConfig?.pluginRuntimeRegistrations ?? [];
|
|
11178
|
+
if (bundledRuntimeRegistrations.length === 0) {
|
|
10986
11179
|
return;
|
|
10987
11180
|
}
|
|
10988
11181
|
const registered = new Set(
|
|
10989
|
-
|
|
11182
|
+
runtimeRegistrations.map((plugin) => plugin.manifest.name)
|
|
10990
11183
|
);
|
|
10991
|
-
const missing =
|
|
11184
|
+
const missing = bundledRuntimeRegistrations.filter(
|
|
10992
11185
|
(pluginName) => !registered.has(pluginName)
|
|
10993
11186
|
);
|
|
10994
11187
|
if (missing.length === 0) {
|
|
10995
11188
|
return;
|
|
10996
11189
|
}
|
|
10997
11190
|
throw new Error(
|
|
10998
|
-
`createApp() is missing plugin registration(s) with runtime
|
|
11191
|
+
`createApp() is missing plugin registration(s) with runtime code bundled by juniorNitro(): ${missing.join(", ")}. Pass a runtime-safe plugin module to juniorNitro({ plugins: "./plugins" }) or pass the same defineJuniorPlugins(...) set to createApp({ plugins }).`
|
|
10999
11192
|
);
|
|
11000
11193
|
}
|
|
11001
11194
|
function mountPluginRoutes(app, routes) {
|
|
@@ -11015,14 +11208,14 @@ function mountPluginRoutes(app, routes) {
|
|
|
11015
11208
|
async function createApp(options) {
|
|
11016
11209
|
const virtualConfig = await resolveVirtualConfig();
|
|
11017
11210
|
const configuredPlugins = options?.plugins ?? virtualConfig?.pluginSet;
|
|
11018
|
-
const plugins =
|
|
11211
|
+
const plugins = pluginRuntimeRegistrationsFromPluginSet(configuredPlugins);
|
|
11019
11212
|
const pluginConfig = configuredPlugins ? pluginCatalogConfigFromPluginSet(configuredPlugins) : virtualConfig?.plugins ?? pluginCatalogConfigFromEnv();
|
|
11020
11213
|
if (configuredPlugins) {
|
|
11021
11214
|
validateBuildIncludesPluginPackages(pluginConfig, virtualConfig);
|
|
11022
11215
|
}
|
|
11023
|
-
|
|
11216
|
+
validateBuildIncludesPluginRuntimeRegistrations(plugins, virtualConfig);
|
|
11024
11217
|
validatePlugins(plugins);
|
|
11025
|
-
|
|
11218
|
+
getDb();
|
|
11026
11219
|
const shouldValidatePluginCatalog = hasConfiguredPluginCatalog(pluginConfig) || Boolean(configuredPlugins?.registrations.length) || Boolean(Object.keys(options?.configDefaults ?? {}).length);
|
|
11027
11220
|
const previousPluginCatalogConfig = setPluginCatalogConfig(pluginConfig);
|
|
11028
11221
|
const previousPlugins = setPlugins(plugins);
|
|
@@ -11097,6 +11290,7 @@ async function createApp(options) {
|
|
|
11097
11290
|
});
|
|
11098
11291
|
});
|
|
11099
11292
|
let agentContinuePOST;
|
|
11293
|
+
let pluginTaskPOST;
|
|
11100
11294
|
let conversationWorkOptions;
|
|
11101
11295
|
const getConversationWorkOptions = () => {
|
|
11102
11296
|
conversationWorkOptions ??= options?.conversationWork ?? createProductionConversationWorkOptions({
|
|
@@ -11106,6 +11300,7 @@ async function createApp(options) {
|
|
|
11106
11300
|
};
|
|
11107
11301
|
if (process.env.NODE_ENV === "development") {
|
|
11108
11302
|
registerVercelConversationWorkDevConsumer(getConversationWorkOptions());
|
|
11303
|
+
registerVercelPluginTaskDevConsumer();
|
|
11109
11304
|
}
|
|
11110
11305
|
app.post("/api/internal/agent/continue", (c) => {
|
|
11111
11306
|
agentContinuePOST ??= createVercelConversationWorkCallback(
|
|
@@ -11113,6 +11308,10 @@ async function createApp(options) {
|
|
|
11113
11308
|
);
|
|
11114
11309
|
return agentContinuePOST(c.req.raw);
|
|
11115
11310
|
});
|
|
11311
|
+
app.post(JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, (c) => {
|
|
11312
|
+
pluginTaskPOST ??= createVercelPluginTaskCallback();
|
|
11313
|
+
return pluginTaskPOST(c.req.raw);
|
|
11314
|
+
});
|
|
11116
11315
|
app.get("/api/internal/heartbeat", (c) => {
|
|
11117
11316
|
return GET2(c.req.raw, waitUntil);
|
|
11118
11317
|
});
|