@sentry/junior 0.75.0 → 0.76.1
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 +364 -135
- 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/slack/footer.d.ts +1 -1
- 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-FFGXUXMD.js} +435 -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-7Z4D6AKV.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 +8 -7
- 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-FFGXUXMD.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";
|
|
151
|
+
} from "./chunk-NFTMTIP3.js";
|
|
116
152
|
import {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
coerceThreadConversationState
|
|
121
|
-
} from "./chunk-74HO27II.js";
|
|
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: {
|
|
@@ -2608,13 +2634,23 @@ function resolveReplyTimeoutMs(explicitTimeoutMs) {
|
|
|
2608
2634
|
const parsed = Number.parseInt(raw, 10);
|
|
2609
2635
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
2610
2636
|
}
|
|
2611
|
-
async function postSlackMessageBestEffort(channelId, threadTs, text) {
|
|
2637
|
+
async function postSlackMessageBestEffort(channelId, threadTs, text, footer) {
|
|
2612
2638
|
try {
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2639
|
+
if (footer) {
|
|
2640
|
+
await postSlackApiReplyPosts({
|
|
2641
|
+
channelId,
|
|
2642
|
+
threadTs,
|
|
2643
|
+
posts: [
|
|
2644
|
+
{
|
|
2645
|
+
text,
|
|
2646
|
+
stage: "thread_reply"
|
|
2647
|
+
}
|
|
2648
|
+
],
|
|
2649
|
+
footer
|
|
2650
|
+
});
|
|
2651
|
+
return;
|
|
2652
|
+
}
|
|
2653
|
+
await postSlackMessage({ channelId, threadTs, text });
|
|
2618
2654
|
} catch {
|
|
2619
2655
|
}
|
|
2620
2656
|
}
|
|
@@ -2665,6 +2701,9 @@ function getResumeLogContext(args, lockKey) {
|
|
|
2665
2701
|
modelId: botConfig.modelId
|
|
2666
2702
|
};
|
|
2667
2703
|
}
|
|
2704
|
+
function getResumeConversationId(args, lockKey) {
|
|
2705
|
+
return args.replyContext?.correlation?.conversationId ?? lockKey;
|
|
2706
|
+
}
|
|
2668
2707
|
async function postResumeFailureReply(args) {
|
|
2669
2708
|
try {
|
|
2670
2709
|
await postSlackMessage({
|
|
@@ -2708,6 +2747,10 @@ function createResumeReplyContext(args, statusSession) {
|
|
|
2708
2747
|
if (!replyContext) {
|
|
2709
2748
|
throw new TypeError("Slack resume requires a reply context");
|
|
2710
2749
|
}
|
|
2750
|
+
if (!replyContext.source) {
|
|
2751
|
+
throw new TypeError("Slack resume requires a reply context source");
|
|
2752
|
+
}
|
|
2753
|
+
const source = replyContext.source;
|
|
2711
2754
|
if (replyContext.destination.platform !== "slack") {
|
|
2712
2755
|
throw new TypeError("Slack resume requires a Slack destination");
|
|
2713
2756
|
}
|
|
@@ -2716,6 +2759,7 @@ function createResumeReplyContext(args, statusSession) {
|
|
|
2716
2759
|
const persistedChannelConfiguration = replyContext.channelConfiguration ?? (replyContext.configuration ? createReadOnlyConfigService(replyContext.configuration) : void 0);
|
|
2717
2760
|
return {
|
|
2718
2761
|
...replyContext,
|
|
2762
|
+
source,
|
|
2719
2763
|
turnDeadlineAtMs: replyContext.turnDeadlineAtMs ?? requestDeadline?.deadlineAtMs,
|
|
2720
2764
|
correlation: {
|
|
2721
2765
|
...replyContext.correlation,
|
|
@@ -2822,7 +2866,7 @@ async function resumeSlackTurn(args) {
|
|
|
2822
2866
|
});
|
|
2823
2867
|
await status.stop();
|
|
2824
2868
|
const footer = buildSlackReplyFooter({
|
|
2825
|
-
conversationId: runArgs
|
|
2869
|
+
conversationId: getResumeConversationId(runArgs, lockKey)
|
|
2826
2870
|
});
|
|
2827
2871
|
await postSlackApiReplyPosts({
|
|
2828
2872
|
channelId: runArgs.channelId,
|
|
@@ -2833,6 +2877,27 @@ async function resumeSlackTurn(args) {
|
|
|
2833
2877
|
});
|
|
2834
2878
|
finalReplyDelivered = true;
|
|
2835
2879
|
await runArgs.onSuccess?.(reply);
|
|
2880
|
+
if (reply.diagnostics.outcome === "success" && replyContext.correlation?.conversationId && replyContext.correlation.turnId) {
|
|
2881
|
+
try {
|
|
2882
|
+
const params = {
|
|
2883
|
+
conversationId: replyContext.correlation.conversationId,
|
|
2884
|
+
sessionId: replyContext.correlation.turnId
|
|
2885
|
+
};
|
|
2886
|
+
if (runArgs.scheduleSessionCompletedPluginTasks) {
|
|
2887
|
+
await runArgs.scheduleSessionCompletedPluginTasks(params);
|
|
2888
|
+
} else {
|
|
2889
|
+
await scheduleSessionCompletedPluginTasks(params);
|
|
2890
|
+
}
|
|
2891
|
+
} catch (scheduleError) {
|
|
2892
|
+
logException(
|
|
2893
|
+
scheduleError,
|
|
2894
|
+
"plugin_session_completed_task_schedule_failed",
|
|
2895
|
+
getResumeLogContext(runArgs, lockKey),
|
|
2896
|
+
{},
|
|
2897
|
+
"Plugin session.completed task scheduling failed"
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2836
2901
|
} catch (error) {
|
|
2837
2902
|
await status.stop();
|
|
2838
2903
|
const onAuthPause = runArgs.onAuthPause;
|
|
@@ -2898,13 +2963,17 @@ async function resumeSlackTurn(args) {
|
|
|
2898
2963
|
try {
|
|
2899
2964
|
await deferredPauseHandler();
|
|
2900
2965
|
if (deferredPauseKind === "auth" && deferredAuthInfo) {
|
|
2966
|
+
const footer = buildSlackReplyFooter({
|
|
2967
|
+
conversationId: getResumeConversationId(runArgs, lockKey)
|
|
2968
|
+
});
|
|
2901
2969
|
await postSlackMessageBestEffort(
|
|
2902
2970
|
runArgs.channelId,
|
|
2903
2971
|
runArgs.threadTs,
|
|
2904
2972
|
buildAuthPauseResponse(
|
|
2905
2973
|
deferredAuthInfo.requesterId,
|
|
2906
2974
|
deferredAuthInfo.providerDisplayName
|
|
2907
|
-
)
|
|
2975
|
+
),
|
|
2976
|
+
footer
|
|
2908
2977
|
);
|
|
2909
2978
|
}
|
|
2910
2979
|
return true;
|
|
@@ -3236,7 +3305,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
3236
3305
|
);
|
|
3237
3306
|
let requester;
|
|
3238
3307
|
try {
|
|
3239
|
-
requester =
|
|
3308
|
+
requester = createSlackResumeRequester({
|
|
3240
3309
|
requester: lockedSessionRecord.requester,
|
|
3241
3310
|
teamId: destination.teamId,
|
|
3242
3311
|
userId: authSession.userId
|
|
@@ -3250,6 +3319,15 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
3250
3319
|
});
|
|
3251
3320
|
return false;
|
|
3252
3321
|
}
|
|
3322
|
+
if (!lockedSessionRecord.source) {
|
|
3323
|
+
await failAgentTurnSessionRecord({
|
|
3324
|
+
conversationId: authSession.conversationId,
|
|
3325
|
+
expectedVersion: lockedSessionRecord.version,
|
|
3326
|
+
sessionId: lockedSessionId,
|
|
3327
|
+
errorMessage: "Stored Slack source missing for MCP OAuth resume"
|
|
3328
|
+
});
|
|
3329
|
+
return false;
|
|
3330
|
+
}
|
|
3253
3331
|
await recordAuthorizationCompleted({
|
|
3254
3332
|
conversationId: authSession.conversationId,
|
|
3255
3333
|
kind: "mcp",
|
|
@@ -3261,15 +3339,17 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
3261
3339
|
}),
|
|
3262
3340
|
ttlMs: THREAD_STATE_TTL_MS
|
|
3263
3341
|
});
|
|
3342
|
+
const lockedMessageTs = getTurnUserSlackMessageTs(lockedUserMessage);
|
|
3264
3343
|
return {
|
|
3265
3344
|
messageText: lockedUserMessage.text,
|
|
3266
|
-
messageTs:
|
|
3345
|
+
messageTs: lockedMessageTs,
|
|
3267
3346
|
replyContext: {
|
|
3268
3347
|
credentialContext: {
|
|
3269
3348
|
actor: { type: "user", userId: requester.userId }
|
|
3270
3349
|
},
|
|
3271
3350
|
requester,
|
|
3272
3351
|
destination,
|
|
3352
|
+
source: lockedSessionRecord.source,
|
|
3273
3353
|
correlation: {
|
|
3274
3354
|
conversationId: authSession.conversationId,
|
|
3275
3355
|
turnId: lockedSessionId,
|
|
@@ -3459,11 +3539,10 @@ function pluginFor(provider) {
|
|
|
3459
3539
|
}
|
|
3460
3540
|
function basePluginContext(plugin) {
|
|
3461
3541
|
const pluginName = plugin.manifest.name;
|
|
3462
|
-
const db = getPluginDbForRegistration(plugin);
|
|
3463
3542
|
return {
|
|
3464
3543
|
plugin: { name: pluginName },
|
|
3465
3544
|
log: createPluginLogger(pluginName),
|
|
3466
|
-
|
|
3545
|
+
db: getDb()
|
|
3467
3546
|
};
|
|
3468
3547
|
}
|
|
3469
3548
|
function parseCredentialResult(value, pluginName) {
|
|
@@ -3572,7 +3651,12 @@ async function issuePluginCredential(input) {
|
|
|
3572
3651
|
plugin.manifest.name,
|
|
3573
3652
|
tokens
|
|
3574
3653
|
);
|
|
3575
|
-
}
|
|
3654
|
+
},
|
|
3655
|
+
withRefresh: async (callback) => await input.userTokenStore.withRefresh(
|
|
3656
|
+
currentUserId,
|
|
3657
|
+
plugin.manifest.name,
|
|
3658
|
+
callback
|
|
3659
|
+
)
|
|
3576
3660
|
}
|
|
3577
3661
|
} : {},
|
|
3578
3662
|
...credentialSubjectUserId ? {
|
|
@@ -3588,7 +3672,12 @@ async function issuePluginCredential(input) {
|
|
|
3588
3672
|
plugin.manifest.name,
|
|
3589
3673
|
tokens
|
|
3590
3674
|
);
|
|
3591
|
-
}
|
|
3675
|
+
},
|
|
3676
|
+
withRefresh: async (callback) => await input.userTokenStore.withRefresh(
|
|
3677
|
+
credentialSubjectUserId,
|
|
3678
|
+
plugin.manifest.name,
|
|
3679
|
+
callback
|
|
3680
|
+
)
|
|
3592
3681
|
}
|
|
3593
3682
|
} : {}
|
|
3594
3683
|
}
|
|
@@ -3908,7 +3997,7 @@ async function persistFailedOAuthReplyState(args) {
|
|
|
3908
3997
|
});
|
|
3909
3998
|
}
|
|
3910
3999
|
async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
3911
|
-
if (!stored.resumeConversationId || !stored.resumeSessionId || !stored.channelId || !stored.destination || !stored.threadTs) {
|
|
4000
|
+
if (!stored.resumeConversationId || !stored.resumeSessionId || !stored.channelId || !stored.destination || !stored.source || !stored.threadTs) {
|
|
3912
4001
|
return false;
|
|
3913
4002
|
}
|
|
3914
4003
|
const destination = requireSlackDestination(
|
|
@@ -4027,7 +4116,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4027
4116
|
);
|
|
4028
4117
|
let requester;
|
|
4029
4118
|
try {
|
|
4030
|
-
requester =
|
|
4119
|
+
requester = createSlackResumeRequester({
|
|
4031
4120
|
requester: lockedSessionRecord.requester,
|
|
4032
4121
|
teamId: destination.teamId,
|
|
4033
4122
|
userId: lockedUserMessage.author.userId
|
|
@@ -4041,6 +4130,15 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4041
4130
|
});
|
|
4042
4131
|
return false;
|
|
4043
4132
|
}
|
|
4133
|
+
if (!lockedSessionRecord.source) {
|
|
4134
|
+
await failAgentTurnSessionRecord({
|
|
4135
|
+
conversationId: stored.resumeConversationId,
|
|
4136
|
+
expectedVersion: lockedSessionRecord.version,
|
|
4137
|
+
sessionId: lockedSessionId,
|
|
4138
|
+
errorMessage: "Stored Slack source missing for OAuth resume"
|
|
4139
|
+
});
|
|
4140
|
+
return false;
|
|
4141
|
+
}
|
|
4044
4142
|
await recordAuthorizationCompleted({
|
|
4045
4143
|
conversationId: stored.resumeConversationId,
|
|
4046
4144
|
kind: "plugin",
|
|
@@ -4052,9 +4150,10 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4052
4150
|
}),
|
|
4053
4151
|
ttlMs: THREAD_STATE_TTL_MS2
|
|
4054
4152
|
});
|
|
4153
|
+
const lockedMessageTs = getTurnUserSlackMessageTs(lockedUserMessage);
|
|
4055
4154
|
return {
|
|
4056
4155
|
messageText: lockedPendingAuth ? lockedUserMessage.text : stored.pendingMessage ?? lockedUserMessage.text,
|
|
4057
|
-
messageTs:
|
|
4156
|
+
messageTs: lockedMessageTs,
|
|
4058
4157
|
replyContext: {
|
|
4059
4158
|
credentialContext: {
|
|
4060
4159
|
actor: {
|
|
@@ -4064,6 +4163,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4064
4163
|
},
|
|
4065
4164
|
requester,
|
|
4066
4165
|
destination,
|
|
4166
|
+
source: lockedSessionRecord.source,
|
|
4067
4167
|
correlation: {
|
|
4068
4168
|
conversationId: stored.resumeConversationId,
|
|
4069
4169
|
turnId: lockedSessionId,
|
|
@@ -4151,7 +4251,8 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4151
4251
|
return true;
|
|
4152
4252
|
}
|
|
4153
4253
|
async function resumePendingOAuthMessage(stored, options) {
|
|
4154
|
-
|
|
4254
|
+
const source = stored.source;
|
|
4255
|
+
if (!stored.pendingMessage || !stored.channelId || !stored.destination || !source || !stored.threadTs) {
|
|
4155
4256
|
return;
|
|
4156
4257
|
}
|
|
4157
4258
|
const threadId = `slack:${stored.channelId}:${stored.threadTs}`;
|
|
@@ -4170,11 +4271,12 @@ async function resumePendingOAuthMessage(stored, options) {
|
|
|
4170
4271
|
destination.teamId,
|
|
4171
4272
|
stored.userId
|
|
4172
4273
|
);
|
|
4274
|
+
const messageTs = getTurnUserSlackMessageTs(latestUserMessage);
|
|
4173
4275
|
await resumeAuthorizedRequest({
|
|
4174
4276
|
messageText: stored.pendingMessage,
|
|
4175
4277
|
channelId: stored.channelId,
|
|
4176
4278
|
threadTs: stored.threadTs,
|
|
4177
|
-
messageTs
|
|
4279
|
+
messageTs,
|
|
4178
4280
|
connectedText: "",
|
|
4179
4281
|
generateReply: options.generateReply,
|
|
4180
4282
|
replyContext: {
|
|
@@ -4183,6 +4285,7 @@ async function resumePendingOAuthMessage(stored, options) {
|
|
|
4183
4285
|
},
|
|
4184
4286
|
requester,
|
|
4185
4287
|
destination: stored.destination,
|
|
4288
|
+
source,
|
|
4186
4289
|
correlation: {
|
|
4187
4290
|
conversationId: threadId,
|
|
4188
4291
|
channelId: stored.channelId,
|
|
@@ -5005,7 +5108,7 @@ function continueSandboxEgressTrace(request, upstreamHost, tracePropagation, cal
|
|
|
5005
5108
|
if (!shouldPropagateSandboxEgressTrace(upstreamHost, tracePropagation) || !sentryTrace && !baggage) {
|
|
5006
5109
|
return run();
|
|
5007
5110
|
}
|
|
5008
|
-
return
|
|
5111
|
+
return continueTrace({ sentryTrace, baggage }, run);
|
|
5009
5112
|
}
|
|
5010
5113
|
function isSandboxEgressForwardedRequest(request) {
|
|
5011
5114
|
return Boolean(
|
|
@@ -6645,7 +6748,6 @@ async function POST2(request, waitUntil, services) {
|
|
|
6645
6748
|
// src/chat/task-execution/vercel-callback.ts
|
|
6646
6749
|
import {
|
|
6647
6750
|
handleCallback,
|
|
6648
|
-
QueueClient,
|
|
6649
6751
|
registerDevConsumer
|
|
6650
6752
|
} from "@vercel/queue";
|
|
6651
6753
|
|
|
@@ -7113,7 +7215,7 @@ function registerVercelConversationWorkDevConsumer(options) {
|
|
|
7113
7215
|
return void 0;
|
|
7114
7216
|
}
|
|
7115
7217
|
return registerDevConsumer({
|
|
7116
|
-
client:
|
|
7218
|
+
client: createVercelQueueClient(),
|
|
7117
7219
|
consumerGroup: CONVERSATION_WORK_DEV_CONSUMER_GROUP,
|
|
7118
7220
|
handler: (message, metadata) => handleConversationQueueMessage(message, metadata, options),
|
|
7119
7221
|
retry: handleConversationQueueRetry,
|
|
@@ -7122,16 +7224,79 @@ function registerVercelConversationWorkDevConsumer(options) {
|
|
|
7122
7224
|
});
|
|
7123
7225
|
}
|
|
7124
7226
|
|
|
7227
|
+
// src/chat/plugins/task-callback.ts
|
|
7228
|
+
import {
|
|
7229
|
+
handleCallback as handleCallback2,
|
|
7230
|
+
registerDevConsumer as registerDevConsumer2
|
|
7231
|
+
} from "@vercel/queue";
|
|
7232
|
+
var PLUGIN_TASK_DEV_CONSUMER_GROUP = "junior_plugin_tasks_dev";
|
|
7233
|
+
var PLUGIN_TASK_MAX_DELIVERIES = 5;
|
|
7234
|
+
function logPluginTaskQueueMessageRejected(reason, metadata) {
|
|
7235
|
+
logWarn(
|
|
7236
|
+
"plugin_task_queue_message_rejected",
|
|
7237
|
+
{},
|
|
7238
|
+
{
|
|
7239
|
+
"app.queue.consumer_group": metadata.consumerGroup,
|
|
7240
|
+
"app.queue.delivery_count": metadata.deliveryCount,
|
|
7241
|
+
"app.queue.message_id": metadata.messageId,
|
|
7242
|
+
"app.queue.reject_reason": reason,
|
|
7243
|
+
"app.queue.topic_name": metadata.topicName
|
|
7244
|
+
},
|
|
7245
|
+
"Plugin task queue message rejected without retry"
|
|
7246
|
+
);
|
|
7247
|
+
}
|
|
7248
|
+
async function handlePluginTaskQueueMessage(message, metadata) {
|
|
7249
|
+
const verification = verifyPluginTaskQueueMessage(message);
|
|
7250
|
+
if (verification.status === "rejected") {
|
|
7251
|
+
logPluginTaskQueueMessageRejected(verification.reason, metadata);
|
|
7252
|
+
return;
|
|
7253
|
+
}
|
|
7254
|
+
if (verification.status === "unavailable") {
|
|
7255
|
+
throw new Error(
|
|
7256
|
+
`Plugin task queue message verification unavailable: ${verification.reason}`
|
|
7257
|
+
);
|
|
7258
|
+
}
|
|
7259
|
+
await runWithTurnRequestDeadline(
|
|
7260
|
+
() => processPluginTask(verification.message)
|
|
7261
|
+
);
|
|
7262
|
+
}
|
|
7263
|
+
function handlePluginTaskQueueRetry(_error, metadata) {
|
|
7264
|
+
if (metadata.deliveryCount >= PLUGIN_TASK_MAX_DELIVERIES) {
|
|
7265
|
+
return { acknowledge: true };
|
|
7266
|
+
}
|
|
7267
|
+
return void 0;
|
|
7268
|
+
}
|
|
7269
|
+
function createVercelPluginTaskCallback() {
|
|
7270
|
+
return handleCallback2(
|
|
7271
|
+
(message, metadata) => handlePluginTaskQueueMessage(message, metadata),
|
|
7272
|
+
{
|
|
7273
|
+
retry: handlePluginTaskQueueRetry
|
|
7274
|
+
}
|
|
7275
|
+
);
|
|
7276
|
+
}
|
|
7277
|
+
function registerVercelPluginTaskDevConsumer() {
|
|
7278
|
+
if (process.env.NODE_ENV !== "development") {
|
|
7279
|
+
return void 0;
|
|
7280
|
+
}
|
|
7281
|
+
return registerDevConsumer2({
|
|
7282
|
+
client: createVercelQueueClient(),
|
|
7283
|
+
consumerGroup: PLUGIN_TASK_DEV_CONSUMER_GROUP,
|
|
7284
|
+
handler: (message, metadata) => handlePluginTaskQueueMessage(message, metadata),
|
|
7285
|
+
retry: handlePluginTaskQueueRetry,
|
|
7286
|
+
topic: PLUGIN_TASK_QUEUE_TOPIC
|
|
7287
|
+
});
|
|
7288
|
+
}
|
|
7289
|
+
|
|
7125
7290
|
// src/chat/services/subscribed-decision.ts
|
|
7126
7291
|
import { z as z2 } from "zod";
|
|
7127
7292
|
var replyDecisionSchema = z2.object({
|
|
7128
7293
|
should_reply: z2.boolean().describe("Whether Junior should respond to this thread message."),
|
|
7129
|
-
should_unsubscribe: z2.boolean().
|
|
7294
|
+
should_unsubscribe: z2.boolean().describe(
|
|
7130
7295
|
"Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
|
|
7131
7296
|
),
|
|
7132
7297
|
confidence: z2.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
|
|
7133
7298
|
reason: z2.string().optional().describe("Short reason for the decision.")
|
|
7134
|
-
});
|
|
7299
|
+
}).strict();
|
|
7135
7300
|
var ROUTER_CONFIDENCE_THRESHOLD = 0.8;
|
|
7136
7301
|
var ROUTER_CLASSIFIER_MAX_TOKENS = 240;
|
|
7137
7302
|
var LEADING_SLACK_MENTION_RE = /^\s*<@([A-Z0-9]+)(?:\|([^>]+))?>[\s,:-]*/i;
|
|
@@ -9059,6 +9224,9 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
9059
9224
|
getAwaitingAgentContinueRequest: overrides.replyExecutor?.getAwaitingAgentContinueRequest ?? getAwaitingAgentContinueRequest,
|
|
9060
9225
|
lookupSlackUser: overrides.replyExecutor?.lookupSlackUser ?? lookupSlackUser,
|
|
9061
9226
|
scheduleAgentContinue: overrides.replyExecutor?.scheduleAgentContinue ?? scheduleAgentContinue,
|
|
9227
|
+
scheduleSessionCompletedPluginTasks: overrides.replyExecutor?.scheduleSessionCompletedPluginTasks ?? (async (params) => {
|
|
9228
|
+
await scheduleSessionCompletedPluginTasks(params);
|
|
9229
|
+
}),
|
|
9062
9230
|
generateThreadTitle: conversationMemory.generateThreadTitle
|
|
9063
9231
|
},
|
|
9064
9232
|
subscribedReplyPolicy: createSubscribedReplyPolicy({
|
|
@@ -9068,6 +9236,9 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
9068
9236
|
};
|
|
9069
9237
|
}
|
|
9070
9238
|
|
|
9239
|
+
// src/chat/runtime/reply-executor.ts
|
|
9240
|
+
import { createSlackSource } from "@sentry/junior-plugin-api";
|
|
9241
|
+
|
|
9071
9242
|
// src/chat/slack/message.ts
|
|
9072
9243
|
function isSlackMessageTs(value) {
|
|
9073
9244
|
return /^\d+(?:\.\d+)?$/.test(value.trim());
|
|
@@ -9277,10 +9448,11 @@ function createReplyToThread(deps) {
|
|
|
9277
9448
|
const threadId = getThreadId(thread, message);
|
|
9278
9449
|
const channelId = getChannelId(thread, message);
|
|
9279
9450
|
const channelName = channelId ? await resolveChannelName(thread) : void 0;
|
|
9451
|
+
const slackChannelType = resolveSlackChannelTypeFromMessage(message);
|
|
9280
9452
|
const slackConversation = resolveSlackConversationContext({
|
|
9281
9453
|
channelId,
|
|
9282
9454
|
channelName,
|
|
9283
|
-
channelType:
|
|
9455
|
+
channelType: slackChannelType
|
|
9284
9456
|
});
|
|
9285
9457
|
const threadTs = getThreadTs(threadId);
|
|
9286
9458
|
const assistantThreadContext = getAssistantThreadContext(message);
|
|
@@ -9290,6 +9462,12 @@ function createReplyToThread(deps) {
|
|
|
9290
9462
|
"Slack reply execution"
|
|
9291
9463
|
);
|
|
9292
9464
|
const teamId = destination.teamId;
|
|
9465
|
+
const source = createSlackSource({
|
|
9466
|
+
channelId: channelId ?? destination.channelId,
|
|
9467
|
+
messageTs,
|
|
9468
|
+
teamId,
|
|
9469
|
+
threadTs
|
|
9470
|
+
});
|
|
9293
9471
|
const runId = getRunId(thread, message);
|
|
9294
9472
|
const conversationId = threadId ?? runId;
|
|
9295
9473
|
await withSpan(
|
|
@@ -9329,12 +9507,12 @@ function createReplyToThread(deps) {
|
|
|
9329
9507
|
)
|
|
9330
9508
|
)
|
|
9331
9509
|
);
|
|
9332
|
-
const
|
|
9510
|
+
const requester = await ensureSlackMessageActorIdentity(
|
|
9333
9511
|
message,
|
|
9334
9512
|
teamId,
|
|
9335
9513
|
deps.services.lookupSlackUser
|
|
9336
9514
|
);
|
|
9337
|
-
const
|
|
9515
|
+
const storedRequester = turnRequester(requester);
|
|
9338
9516
|
const preparedState = options.preparedState ?? await deps.prepareTurnState({
|
|
9339
9517
|
thread,
|
|
9340
9518
|
message,
|
|
@@ -9370,16 +9548,29 @@ function createReplyToThread(deps) {
|
|
|
9370
9548
|
await options.beforeFirstResponsePost?.();
|
|
9371
9549
|
};
|
|
9372
9550
|
const postAuthPauseNotice = async (providerDisplayName) => {
|
|
9551
|
+
const text = buildAuthPauseResponse(
|
|
9552
|
+
message.author.userId,
|
|
9553
|
+
providerDisplayName
|
|
9554
|
+
);
|
|
9555
|
+
const footer = buildSlackReplyFooter({ conversationId });
|
|
9373
9556
|
try {
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9557
|
+
if (channelId && threadTs) {
|
|
9558
|
+
await postSlackApiReplyPosts({
|
|
9559
|
+
beforePost: beforeFirstResponsePost,
|
|
9560
|
+
channelId,
|
|
9561
|
+
threadTs,
|
|
9562
|
+
posts: [
|
|
9563
|
+
{
|
|
9564
|
+
text,
|
|
9565
|
+
stage: "thread_reply"
|
|
9566
|
+
}
|
|
9567
|
+
],
|
|
9568
|
+
footer
|
|
9569
|
+
});
|
|
9570
|
+
} else {
|
|
9571
|
+
await beforeFirstResponsePost();
|
|
9572
|
+
await thread.post(buildSlackOutputMessage(text));
|
|
9573
|
+
}
|
|
9383
9574
|
} catch (error) {
|
|
9384
9575
|
logException(
|
|
9385
9576
|
error,
|
|
@@ -9515,6 +9706,7 @@ function createReplyToThread(deps) {
|
|
|
9515
9706
|
surface: "slack",
|
|
9516
9707
|
requester,
|
|
9517
9708
|
destination,
|
|
9709
|
+
source,
|
|
9518
9710
|
traceId: getActiveTraceId()
|
|
9519
9711
|
}).catch((error) => {
|
|
9520
9712
|
logException(
|
|
@@ -9528,7 +9720,7 @@ function createReplyToThread(deps) {
|
|
|
9528
9720
|
void initConversationContext(conversationId, {
|
|
9529
9721
|
channelName,
|
|
9530
9722
|
originSurface: "slack",
|
|
9531
|
-
originRequester:
|
|
9723
|
+
originRequester: storedRequester,
|
|
9532
9724
|
startedAtMs: turnStartedAtMs
|
|
9533
9725
|
}).catch((error) => {
|
|
9534
9726
|
logException(
|
|
@@ -9578,12 +9770,12 @@ function createReplyToThread(deps) {
|
|
|
9578
9770
|
if (message.author.userId) {
|
|
9579
9771
|
setSentryUser({
|
|
9580
9772
|
id: message.author.userId,
|
|
9581
|
-
...
|
|
9582
|
-
...
|
|
9773
|
+
...requester.userName ? { username: requester.userName } : {},
|
|
9774
|
+
...requester.email ? { email: requester.email } : {}
|
|
9583
9775
|
});
|
|
9584
9776
|
}
|
|
9585
|
-
if (
|
|
9586
|
-
setTags({ slackUserName:
|
|
9777
|
+
if (requester.userName) {
|
|
9778
|
+
setTags({ slackUserName: requester.userName });
|
|
9587
9779
|
}
|
|
9588
9780
|
const turnAttachments = collectTurnAttachments(
|
|
9589
9781
|
message,
|
|
@@ -9763,7 +9955,7 @@ function createReplyToThread(deps) {
|
|
|
9763
9955
|
credentialContext: {
|
|
9764
9956
|
actor: { type: "user", userId: message.author.userId }
|
|
9765
9957
|
},
|
|
9766
|
-
requester
|
|
9958
|
+
requester,
|
|
9767
9959
|
conversationContext: preparedState.conversationContext,
|
|
9768
9960
|
artifactState: preparedState.artifacts,
|
|
9769
9961
|
piMessages,
|
|
@@ -9774,6 +9966,7 @@ function createReplyToThread(deps) {
|
|
|
9774
9966
|
omittedImageAttachmentCount,
|
|
9775
9967
|
userAttachments,
|
|
9776
9968
|
slackConversation,
|
|
9969
|
+
source,
|
|
9777
9970
|
destination,
|
|
9778
9971
|
surface: "slack",
|
|
9779
9972
|
turnDeadlineAtMs: getTurnRequestDeadline()?.deadlineAtMs,
|
|
@@ -9940,6 +10133,7 @@ function createReplyToThread(deps) {
|
|
|
9940
10133
|
state: "completed",
|
|
9941
10134
|
requester,
|
|
9942
10135
|
destination,
|
|
10136
|
+
source,
|
|
9943
10137
|
traceId: getActiveTraceId()
|
|
9944
10138
|
});
|
|
9945
10139
|
}
|
|
@@ -9958,6 +10152,22 @@ function createReplyToThread(deps) {
|
|
|
9958
10152
|
);
|
|
9959
10153
|
}
|
|
9960
10154
|
await options.onTurnCompleted?.();
|
|
10155
|
+
if (reply.diagnostics.outcome === "success" && conversationId) {
|
|
10156
|
+
try {
|
|
10157
|
+
await deps.services.scheduleSessionCompletedPluginTasks({
|
|
10158
|
+
conversationId,
|
|
10159
|
+
sessionId: turnId
|
|
10160
|
+
});
|
|
10161
|
+
} catch (error) {
|
|
10162
|
+
logException(
|
|
10163
|
+
error,
|
|
10164
|
+
"plugin_session_completed_task_schedule_failed",
|
|
10165
|
+
turnTraceContext,
|
|
10166
|
+
{},
|
|
10167
|
+
"Plugin session.completed task scheduling failed"
|
|
10168
|
+
);
|
|
10169
|
+
}
|
|
10170
|
+
}
|
|
9961
10171
|
} catch (error) {
|
|
9962
10172
|
if (isCooperativeTurnYieldError(error)) {
|
|
9963
10173
|
shouldPersistFailureState = false;
|
|
@@ -10093,6 +10303,7 @@ function createReplyToThread(deps) {
|
|
|
10093
10303
|
state: "failed",
|
|
10094
10304
|
requester,
|
|
10095
10305
|
destination,
|
|
10306
|
+
source,
|
|
10096
10307
|
traceId: getActiveTraceId()
|
|
10097
10308
|
});
|
|
10098
10309
|
const sessionRecord = await getAgentTurnSessionRecord(
|
|
@@ -10642,6 +10853,7 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
10642
10853
|
threadTs: thread.threadTs,
|
|
10643
10854
|
lockKey: payload.conversationId,
|
|
10644
10855
|
generateReply: options.generateReply,
|
|
10856
|
+
scheduleSessionCompletedPluginTasks: options.scheduleSessionCompletedPluginTasks,
|
|
10645
10857
|
beforeStart: async () => {
|
|
10646
10858
|
let sessionRecord;
|
|
10647
10859
|
try {
|
|
@@ -10678,11 +10890,20 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
10678
10890
|
payload.destination,
|
|
10679
10891
|
"Slack continuation"
|
|
10680
10892
|
);
|
|
10681
|
-
const requester =
|
|
10893
|
+
const requester = createSlackResumeRequester({
|
|
10682
10894
|
requester: activeSessionRecord.requester,
|
|
10683
10895
|
teamId: destination.teamId,
|
|
10684
10896
|
userId: userMessage2.author.userId
|
|
10685
10897
|
});
|
|
10898
|
+
if (!activeSessionRecord.source) {
|
|
10899
|
+
await failAgentTurnSessionRecord({
|
|
10900
|
+
conversationId: payload.conversationId,
|
|
10901
|
+
expectedVersion: activeSessionRecord.version,
|
|
10902
|
+
sessionId: payload.sessionId,
|
|
10903
|
+
errorMessage: "Stored Slack source missing for continuation"
|
|
10904
|
+
});
|
|
10905
|
+
return false;
|
|
10906
|
+
}
|
|
10686
10907
|
return {
|
|
10687
10908
|
messageText: userMessage2.text,
|
|
10688
10909
|
messageTs: getTurnUserSlackMessageTs(userMessage2),
|
|
@@ -10695,6 +10916,7 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
10695
10916
|
},
|
|
10696
10917
|
requester,
|
|
10697
10918
|
destination: payload.destination,
|
|
10919
|
+
source: activeSessionRecord.source,
|
|
10698
10920
|
correlation: {
|
|
10699
10921
|
conversationId: payload.conversationId,
|
|
10700
10922
|
turnId: payload.sessionId,
|
|
@@ -10878,7 +11100,7 @@ function getProductionSlackAdapter() {
|
|
|
10878
11100
|
return productionSlackAdapter;
|
|
10879
11101
|
}
|
|
10880
11102
|
function getProductionConversationStore() {
|
|
10881
|
-
return
|
|
11103
|
+
return getConversationStore();
|
|
10882
11104
|
}
|
|
10883
11105
|
function createProductionSlackWebhookServices(options) {
|
|
10884
11106
|
const conversationStore = getProductionConversationStore();
|
|
@@ -10910,7 +11132,8 @@ function createProductionConversationWorkOptions(options) {
|
|
|
10910
11132
|
generateReply: withSandboxTracePropagation(
|
|
10911
11133
|
generateAssistantReply,
|
|
10912
11134
|
options?.services?.sandbox?.tracePropagation
|
|
10913
|
-
)
|
|
11135
|
+
),
|
|
11136
|
+
scheduleSessionCompletedPluginTasks: options?.services?.replyExecutor?.scheduleSessionCompletedPluginTasks
|
|
10914
11137
|
}),
|
|
10915
11138
|
runtime
|
|
10916
11139
|
})
|
|
@@ -10938,7 +11161,7 @@ async function resolveVirtualConfig() {
|
|
|
10938
11161
|
return {
|
|
10939
11162
|
pluginSet: mod.pluginSet,
|
|
10940
11163
|
plugins: mod.plugins,
|
|
10941
|
-
|
|
11164
|
+
pluginRuntimeRegistrations: mod.pluginRuntimeRegistrations ?? []
|
|
10942
11165
|
};
|
|
10943
11166
|
} catch (error) {
|
|
10944
11167
|
if (!isMissingVirtualConfig(error)) {
|
|
@@ -10980,22 +11203,22 @@ function validateBuildIncludesPluginPackages(pluginConfig, virtualConfig) {
|
|
|
10980
11203
|
`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
11204
|
);
|
|
10982
11205
|
}
|
|
10983
|
-
function
|
|
10984
|
-
const
|
|
10985
|
-
if (
|
|
11206
|
+
function validateBuildIncludesPluginRuntimeRegistrations(runtimeRegistrations, virtualConfig) {
|
|
11207
|
+
const bundledRuntimeRegistrations = virtualConfig?.pluginRuntimeRegistrations ?? [];
|
|
11208
|
+
if (bundledRuntimeRegistrations.length === 0) {
|
|
10986
11209
|
return;
|
|
10987
11210
|
}
|
|
10988
11211
|
const registered = new Set(
|
|
10989
|
-
|
|
11212
|
+
runtimeRegistrations.map((plugin) => plugin.manifest.name)
|
|
10990
11213
|
);
|
|
10991
|
-
const missing =
|
|
11214
|
+
const missing = bundledRuntimeRegistrations.filter(
|
|
10992
11215
|
(pluginName) => !registered.has(pluginName)
|
|
10993
11216
|
);
|
|
10994
11217
|
if (missing.length === 0) {
|
|
10995
11218
|
return;
|
|
10996
11219
|
}
|
|
10997
11220
|
throw new Error(
|
|
10998
|
-
`createApp() is missing plugin registration(s) with runtime
|
|
11221
|
+
`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
11222
|
);
|
|
11000
11223
|
}
|
|
11001
11224
|
function mountPluginRoutes(app, routes) {
|
|
@@ -11015,14 +11238,14 @@ function mountPluginRoutes(app, routes) {
|
|
|
11015
11238
|
async function createApp(options) {
|
|
11016
11239
|
const virtualConfig = await resolveVirtualConfig();
|
|
11017
11240
|
const configuredPlugins = options?.plugins ?? virtualConfig?.pluginSet;
|
|
11018
|
-
const plugins =
|
|
11241
|
+
const plugins = pluginRuntimeRegistrationsFromPluginSet(configuredPlugins);
|
|
11019
11242
|
const pluginConfig = configuredPlugins ? pluginCatalogConfigFromPluginSet(configuredPlugins) : virtualConfig?.plugins ?? pluginCatalogConfigFromEnv();
|
|
11020
11243
|
if (configuredPlugins) {
|
|
11021
11244
|
validateBuildIncludesPluginPackages(pluginConfig, virtualConfig);
|
|
11022
11245
|
}
|
|
11023
|
-
|
|
11246
|
+
validateBuildIncludesPluginRuntimeRegistrations(plugins, virtualConfig);
|
|
11024
11247
|
validatePlugins(plugins);
|
|
11025
|
-
|
|
11248
|
+
getDb();
|
|
11026
11249
|
const shouldValidatePluginCatalog = hasConfiguredPluginCatalog(pluginConfig) || Boolean(configuredPlugins?.registrations.length) || Boolean(Object.keys(options?.configDefaults ?? {}).length);
|
|
11027
11250
|
const previousPluginCatalogConfig = setPluginCatalogConfig(pluginConfig);
|
|
11028
11251
|
const previousPlugins = setPlugins(plugins);
|
|
@@ -11097,6 +11320,7 @@ async function createApp(options) {
|
|
|
11097
11320
|
});
|
|
11098
11321
|
});
|
|
11099
11322
|
let agentContinuePOST;
|
|
11323
|
+
let pluginTaskPOST;
|
|
11100
11324
|
let conversationWorkOptions;
|
|
11101
11325
|
const getConversationWorkOptions = () => {
|
|
11102
11326
|
conversationWorkOptions ??= options?.conversationWork ?? createProductionConversationWorkOptions({
|
|
@@ -11106,6 +11330,7 @@ async function createApp(options) {
|
|
|
11106
11330
|
};
|
|
11107
11331
|
if (process.env.NODE_ENV === "development") {
|
|
11108
11332
|
registerVercelConversationWorkDevConsumer(getConversationWorkOptions());
|
|
11333
|
+
registerVercelPluginTaskDevConsumer();
|
|
11109
11334
|
}
|
|
11110
11335
|
app.post("/api/internal/agent/continue", (c) => {
|
|
11111
11336
|
agentContinuePOST ??= createVercelConversationWorkCallback(
|
|
@@ -11113,6 +11338,10 @@ async function createApp(options) {
|
|
|
11113
11338
|
);
|
|
11114
11339
|
return agentContinuePOST(c.req.raw);
|
|
11115
11340
|
});
|
|
11341
|
+
app.post(JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, (c) => {
|
|
11342
|
+
pluginTaskPOST ??= createVercelPluginTaskCallback();
|
|
11343
|
+
return pluginTaskPOST(c.req.raw);
|
|
11344
|
+
});
|
|
11116
11345
|
app.get("/api/internal/heartbeat", (c) => {
|
|
11117
11346
|
return GET2(c.req.raw, waitUntil);
|
|
11118
11347
|
});
|