@sentry/junior 0.100.0 → 0.102.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 +0 -1
- package/dist/{agent-hooks-V6KU7PQN.js → agent-hooks-I4I2DHSW.js} +7 -7
- package/dist/api/conversations/schema.d.ts +2 -2
- package/dist/api/people/schema.d.ts +13 -0
- package/dist/api/schema.d.ts +1 -1
- package/dist/api/schema.js +3 -3
- package/dist/api.js +16 -16
- package/dist/app.js +165 -104
- package/dist/{catalog-runtime-PFHVMHDR.js → catalog-runtime-5CVM2DOF.js} +2 -2
- package/dist/chat/agent/prompt.d.ts +1 -1
- package/dist/chat/agent/request.d.ts +1 -1
- package/dist/chat/agent-dispatch/validation.d.ts +1 -1
- package/dist/chat/conversation-privacy.d.ts +2 -6
- package/dist/chat/conversations/store.d.ts +1 -1
- package/dist/chat/credentials/context.d.ts +33 -6
- package/dist/chat/credentials/subject.d.ts +15 -1
- package/dist/chat/logging.d.ts +4 -2
- package/dist/chat/mcp/auth-store.d.ts +1 -0
- package/dist/chat/mcp/client.d.ts +2 -0
- package/dist/chat/mcp/oauth-provider.d.ts +4 -1
- package/dist/chat/mcp/oauth.d.ts +3 -1
- package/dist/chat/mcp/tool-manager.d.ts +3 -1
- package/dist/chat/sandbox/egress/schemas.d.ts +13 -2
- package/dist/chat/services/context-compaction-marker.d.ts +8 -0
- package/dist/chat/services/mcp-auth-orchestration.d.ts +1 -1
- package/dist/chat/services/pending-auth.d.ts +17 -9
- package/dist/chat/state/conversation.d.ts +7 -3
- package/dist/{chunk-XJA7BPHS.js → chunk-3OABPOHR.js} +3 -3
- package/dist/{chunk-2T7DCRAW.js → chunk-3UK5DFKW.js} +3 -3
- package/dist/{chunk-IDZBM3NW.js → chunk-4YN2ZXKB.js} +10 -2
- package/dist/{chunk-NSOCZGOH.js → chunk-5K4N73TP.js} +9 -11
- package/dist/{chunk-LMJPRYHP.js → chunk-77LHNQK4.js} +32 -8
- package/dist/{chunk-I35CTGPO.js → chunk-AEWZ7F65.js} +41 -17
- package/dist/{chunk-IQIBZXGB.js → chunk-B5QS4AVO.js} +2 -2
- package/dist/{chunk-XSBIISXS.js → chunk-DTUSCR2Y.js} +9 -12
- package/dist/{chunk-GEUUJRQF.js → chunk-E4EMFKGB.js} +1 -1
- package/dist/{chunk-VVIXK2BX.js → chunk-EMUZSROX.js} +2 -2
- package/dist/{chunk-IVXL57YF.js → chunk-EOB77KME.js} +4 -4
- package/dist/{chunk-PGGEOCQY.js → chunk-F4CQEUTP.js} +1 -1
- package/dist/{chunk-4AQUWWEM.js → chunk-HNIT4HXU.js} +1 -1
- package/dist/{chunk-MM5UFDAC.js → chunk-HYDQULR2.js} +1 -1
- package/dist/{chunk-FP5N5OWZ.js → chunk-IQ36I3DF.js} +2 -2
- package/dist/{chunk-JSAANELJ.js → chunk-LJB2TLVT.js} +3 -3
- package/dist/{chunk-D5KZYS4T.js → chunk-MJSJAHBW.js} +1 -1
- package/dist/{chunk-QSBQJ3PA.js → chunk-MR6H67P2.js} +3 -3
- package/dist/{chunk-VY7BT4SM.js → chunk-NSP6OGL2.js} +9 -8
- package/dist/{chunk-VHRM6GNH.js → chunk-QZGVPPIJ.js} +27 -3
- package/dist/{chunk-LVA4I4H7.js → chunk-RT5BUHR5.js} +15 -44
- package/dist/{chunk-A7X2FDUO.js → chunk-SHBPSE7A.js} +88 -66
- package/dist/{chunk-CM5EZD5F.js → chunk-UIE3R5XU.js} +1 -1
- package/dist/{chunk-JPQISMMJ.js → chunk-VSAFV2GI.js} +7 -6
- package/dist/{chunk-3ECW2K2O.js → chunk-WR7H7VLJ.js} +2 -2
- package/dist/{chunk-TPTJEHUE.js → chunk-X2IPNCB5.js} +61 -25
- package/dist/{chunk-6DTVCPLO.js → chunk-XIMUQ4IU.js} +4 -3
- package/dist/{chunk-45DMFMY2.js → chunk-ZIX4PNBI.js} +348 -200
- package/dist/{chunk-PWC24W5F.js → chunk-ZSHL44IQ.js} +2 -2
- package/dist/cli/chat.js +22 -22
- package/dist/cli/check.js +3 -3
- package/dist/cli/plugins.js +9 -9
- package/dist/cli/snapshot-warmup.js +5 -5
- package/dist/cli/upgrade.js +203 -14
- package/dist/db/postgres-json.d.ts +5 -0
- package/dist/{db-RCZB7KNM.js → db-6QP6HY7U.js} +4 -4
- package/dist/{detail-LU6COZO6.js → detail-OEIVZYXS.js} +12 -12
- package/dist/{detail-5SLCGT6J.js → detail-U6IP2Z4N.js} +8 -8
- package/dist/instrumentation.js +2 -2
- package/dist/{legacy-import-VCYLWT2V.js → legacy-import-R3BMM2GH.js} +5 -5
- package/dist/{list-KHRAWZWU.js → list-AJ6RWBOG.js} +8 -8
- package/dist/list-UMZKA5AI.js +121 -0
- package/dist/{list-4ALSU6ZW.js → list-Z3CC52CZ.js} +8 -8
- package/dist/{plugin-conversations-JANXC4GA.js → plugin-conversations-F3IBVNFX.js} +7 -7
- package/dist/{profile-3O3OVENT.js → profile-CQMPFKED.js} +8 -8
- package/dist/{runner-BM7D35YW.js → runner-C2ZTIOUD.js} +13 -13
- package/dist/{skills-MAZXZ2KE.js → skills-722AXRV5.js} +3 -3
- package/dist/{stats-J3YGCYDF.js → stats-ZYFQFCTL.js} +6 -6
- package/dist/{subagent-P7HOSMVC.js → subagent-X3ZWJHR4.js} +11 -11
- package/dist/{validation-FMEAEKCY.js → validation-EUI2UFRM.js} +3 -3
- package/package.json +6 -6
- package/dist/api-reference.d.ts +0 -14
- package/dist/list-2FI5SFV7.js +0 -80
package/dist/app.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
processPluginTask,
|
|
6
6
|
requireTurnFailureEventId,
|
|
7
7
|
scheduleSessionCompletedPluginTasks
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-DTUSCR2Y.js";
|
|
9
9
|
import {
|
|
10
10
|
buildSentryConversationUrl
|
|
11
11
|
} from "./chunk-LVUKF5CE.js";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
conversationVisibilityFromSlackChannelType,
|
|
14
14
|
resolveSlackChannelTypeFromMessage,
|
|
15
15
|
resolveSlackConversationContext
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-EMUZSROX.js";
|
|
17
17
|
import {
|
|
18
18
|
CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
|
|
19
19
|
CONVERSATION_WORK_STALE_ENQUEUE_MS,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
requestConversationContinuation,
|
|
38
38
|
requestConversationWork,
|
|
39
39
|
startConversationWork
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-3UK5DFKW.js";
|
|
41
41
|
import {
|
|
42
42
|
GET
|
|
43
43
|
} from "./chunk-QNVHH5PU.js";
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
import {
|
|
56
56
|
validatePluginEgressCredentialHooks,
|
|
57
57
|
validatePluginRegistrations
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-MJSJAHBW.js";
|
|
59
59
|
import {
|
|
60
60
|
defineJuniorPlugins,
|
|
61
61
|
pluginCatalogConfigFromEnv,
|
|
@@ -86,6 +86,7 @@ import {
|
|
|
86
86
|
formatProviderLabel,
|
|
87
87
|
formatSlackLink,
|
|
88
88
|
getConfigDefaults,
|
|
89
|
+
getMcpAuthSession,
|
|
89
90
|
getMcpStoredOAuthCredentials,
|
|
90
91
|
latestReportedProgress,
|
|
91
92
|
listThreadReplies,
|
|
@@ -105,12 +106,11 @@ import {
|
|
|
105
106
|
splitSlackReplyText,
|
|
106
107
|
startOAuthFlow,
|
|
107
108
|
truncateStatusText
|
|
108
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-ZIX4PNBI.js";
|
|
109
110
|
import {
|
|
110
111
|
CooperativeTurnYieldError,
|
|
111
112
|
TurnInputCommitLostError,
|
|
112
113
|
TurnInputDeferredError,
|
|
113
|
-
applyPendingAuthUpdate,
|
|
114
114
|
buildDeterministicTurnId,
|
|
115
115
|
clearPendingAuth,
|
|
116
116
|
coerceThreadArtifactsState,
|
|
@@ -134,24 +134,24 @@ import {
|
|
|
134
134
|
persistWithRetry,
|
|
135
135
|
persistYieldSessionRecord,
|
|
136
136
|
startActiveTurn
|
|
137
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-5K4N73TP.js";
|
|
138
138
|
import {
|
|
139
139
|
JUNIOR_THREAD_STATE_TTL_MS,
|
|
140
140
|
coerceThreadConversationState
|
|
141
|
-
} from "./chunk-
|
|
141
|
+
} from "./chunk-XIMUQ4IU.js";
|
|
142
142
|
import {
|
|
143
143
|
abandonAgentTurnSessionRecord,
|
|
144
144
|
failAgentTurnSessionRecord,
|
|
145
145
|
getAgentTurnSessionRecord,
|
|
146
146
|
listAgentTurnSessionSummariesForConversation,
|
|
147
147
|
recordAgentTurnSessionSummary
|
|
148
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-EOB77KME.js";
|
|
149
149
|
import {
|
|
150
150
|
commitMessages,
|
|
151
151
|
loadConversationProjection,
|
|
152
152
|
loadProjection,
|
|
153
153
|
recordAuthorizationCompleted
|
|
154
|
-
} from "./chunk-
|
|
154
|
+
} from "./chunk-B5QS4AVO.js";
|
|
155
155
|
import {
|
|
156
156
|
buildConversationContext,
|
|
157
157
|
createConversationMemoryService,
|
|
@@ -166,11 +166,12 @@ import {
|
|
|
166
166
|
persistConversationMessages,
|
|
167
167
|
updateConversationStats,
|
|
168
168
|
upsertConversationMessage
|
|
169
|
-
} from "./chunk-
|
|
170
|
-
import "./chunk-
|
|
169
|
+
} from "./chunk-VSAFV2GI.js";
|
|
170
|
+
import "./chunk-3OABPOHR.js";
|
|
171
171
|
import "./chunk-PDO5BLNM.js";
|
|
172
|
-
import "./chunk-
|
|
172
|
+
import "./chunk-UIE3R5XU.js";
|
|
173
173
|
import {
|
|
174
|
+
bindScheduledTaskCredentialSubject,
|
|
174
175
|
bindSlackDirectCredentialSubject,
|
|
175
176
|
getPluginApiRoutes,
|
|
176
177
|
getPluginRoutes,
|
|
@@ -178,8 +179,9 @@ import {
|
|
|
178
179
|
getPlugins,
|
|
179
180
|
setPlugins,
|
|
180
181
|
validatePlugins,
|
|
182
|
+
verifyScheduledTaskCredentialSubject,
|
|
181
183
|
verifySlackDirectCredentialSubject
|
|
182
|
-
} from "./chunk-
|
|
184
|
+
} from "./chunk-X2IPNCB5.js";
|
|
183
185
|
import {
|
|
184
186
|
SlackActionError,
|
|
185
187
|
downloadPrivateSlackFile,
|
|
@@ -190,11 +192,11 @@ import {
|
|
|
190
192
|
normalizeSlackConversationId,
|
|
191
193
|
runWithSlackInstallationToken,
|
|
192
194
|
runWithWorkspaceTeamId
|
|
193
|
-
} from "./chunk-
|
|
195
|
+
} from "./chunk-IQ36I3DF.js";
|
|
194
196
|
import {
|
|
195
197
|
createPluginLogger,
|
|
196
198
|
createPluginState
|
|
197
|
-
} from "./chunk-
|
|
199
|
+
} from "./chunk-ZSHL44IQ.js";
|
|
198
200
|
import {
|
|
199
201
|
contextProvenance,
|
|
200
202
|
getConversationStore,
|
|
@@ -204,7 +206,7 @@ import {
|
|
|
204
206
|
juniorAgentSteps,
|
|
205
207
|
juniorConversationMessages,
|
|
206
208
|
juniorConversations
|
|
207
|
-
} from "./chunk-
|
|
209
|
+
} from "./chunk-QZGVPPIJ.js";
|
|
208
210
|
import "./chunk-G3E7SCME.js";
|
|
209
211
|
import {
|
|
210
212
|
sleep
|
|
@@ -232,7 +234,7 @@ import {
|
|
|
232
234
|
setSlackReactionConfig,
|
|
233
235
|
stripRuntimeTurnContext,
|
|
234
236
|
trimTrailingAssistantMessages
|
|
235
|
-
} from "./chunk-
|
|
237
|
+
} from "./chunk-SHBPSE7A.js";
|
|
236
238
|
import {
|
|
237
239
|
juniorDestinations
|
|
238
240
|
} from "./chunk-FXFQNHRU.js";
|
|
@@ -241,7 +243,7 @@ import {
|
|
|
241
243
|
readSlackRawMessageContext,
|
|
242
244
|
resolveSlackChannelIdFromMessage,
|
|
243
245
|
resolveSlackChannelIdFromThreadId
|
|
244
|
-
} from "./chunk-
|
|
246
|
+
} from "./chunk-RT5BUHR5.js";
|
|
245
247
|
import {
|
|
246
248
|
createSlackDestination,
|
|
247
249
|
destinationKey,
|
|
@@ -251,13 +253,14 @@ import {
|
|
|
251
253
|
} from "./chunk-B7PUBQQM.js";
|
|
252
254
|
import {
|
|
253
255
|
discoverSkills
|
|
254
|
-
} from "./chunk-
|
|
256
|
+
} from "./chunk-WR7H7VLJ.js";
|
|
255
257
|
import {
|
|
256
258
|
buildOAuthTokenRequest,
|
|
259
|
+
credentialSubjectSchema,
|
|
257
260
|
hasRequiredOAuthScope,
|
|
258
261
|
parseOAuthTokenResponse,
|
|
259
262
|
pluginCatalogRuntime
|
|
260
|
-
} from "./chunk-
|
|
263
|
+
} from "./chunk-77LHNQK4.js";
|
|
261
264
|
import {
|
|
262
265
|
buildTurnFailureResponse,
|
|
263
266
|
createActor,
|
|
@@ -279,7 +282,7 @@ import {
|
|
|
279
282
|
setTags,
|
|
280
283
|
withContext,
|
|
281
284
|
withSpan
|
|
282
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-AEWZ7F65.js";
|
|
283
286
|
import {
|
|
284
287
|
toOptionalString
|
|
285
288
|
} from "./chunk-OB42YVAE.js";
|
|
@@ -570,7 +573,6 @@ async function verifyDispatchCallbackRequest(request) {
|
|
|
570
573
|
// src/chat/agent-dispatch/store.ts
|
|
571
574
|
import { createHash } from "crypto";
|
|
572
575
|
import {
|
|
573
|
-
pluginCredentialSubjectSchema,
|
|
574
576
|
destinationSchema,
|
|
575
577
|
isSlackDestination,
|
|
576
578
|
sourceSchema
|
|
@@ -596,20 +598,11 @@ var dispatchActorSchema = z.object({
|
|
|
596
598
|
platform: z.literal("system"),
|
|
597
599
|
name: nonEmptyExactStringSchema
|
|
598
600
|
}).strict();
|
|
599
|
-
var credentialSubjectBindingSchema = z.object({
|
|
600
|
-
type: z.literal("slack-direct-conversation"),
|
|
601
|
-
teamId: z.string().min(1),
|
|
602
|
-
channelId: z.string().min(1),
|
|
603
|
-
signature: z.string().min(1)
|
|
604
|
-
}).strict();
|
|
605
|
-
var boundCredentialSubjectSchema = pluginCredentialSubjectSchema.extend({
|
|
606
|
-
binding: credentialSubjectBindingSchema
|
|
607
|
-
}).strict();
|
|
608
601
|
var dispatchRecordSchema = z.object({
|
|
609
602
|
actor: dispatchActorSchema,
|
|
610
603
|
attempt: z.number().int().nonnegative(),
|
|
611
604
|
createdAtMs: z.number().finite(),
|
|
612
|
-
credentialSubject:
|
|
605
|
+
credentialSubject: credentialSubjectSchema.optional(),
|
|
613
606
|
destination: destinationSchema,
|
|
614
607
|
errorMessage: z.string().optional(),
|
|
615
608
|
id: nonEmptyExactStringSchema,
|
|
@@ -638,18 +631,28 @@ var dispatchRecordSchema = z.object({
|
|
|
638
631
|
if (!subject) {
|
|
639
632
|
return;
|
|
640
633
|
}
|
|
641
|
-
if (
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
634
|
+
if (subject.allowedWhen === "private-direct-conversation") {
|
|
635
|
+
if (!record.destination.channelId.startsWith("D")) {
|
|
636
|
+
ctx.addIssue({
|
|
637
|
+
code: z.ZodIssueCode.custom,
|
|
638
|
+
message: "Dispatch credentialSubject requires a private direct Slack destination",
|
|
639
|
+
path: ["credentialSubject"]
|
|
640
|
+
});
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
if (subject.binding.type !== "slack-direct-conversation" || subject.binding.teamId !== record.destination.teamId || subject.binding.channelId !== record.destination.channelId) {
|
|
644
|
+
ctx.addIssue({
|
|
645
|
+
code: z.ZodIssueCode.custom,
|
|
646
|
+
message: "Dispatch credentialSubject binding must match destination",
|
|
647
|
+
path: ["credentialSubject", "binding"]
|
|
648
|
+
});
|
|
649
|
+
}
|
|
647
650
|
return;
|
|
648
651
|
}
|
|
649
|
-
if (subject.binding.
|
|
652
|
+
if (subject.binding.type !== "scheduled-task" || subject.binding.plugin !== record.plugin || subject.binding.taskId !== subject.taskId) {
|
|
650
653
|
ctx.addIssue({
|
|
651
654
|
code: z.ZodIssueCode.custom,
|
|
652
|
-
message: "Dispatch credentialSubject binding must match
|
|
655
|
+
message: "Dispatch credentialSubject binding must match task",
|
|
653
656
|
path: ["credentialSubject", "binding"]
|
|
654
657
|
});
|
|
655
658
|
}
|
|
@@ -2745,7 +2748,7 @@ function dispatchOptionsErrorMessage(issues) {
|
|
|
2745
2748
|
return "Dispatch credentialSubject userId is required";
|
|
2746
2749
|
}
|
|
2747
2750
|
if (hasIssueUnderPath(issues, ["credentialSubject", "allowedWhen"])) {
|
|
2748
|
-
return "Dispatch credentialSubject allowedWhen
|
|
2751
|
+
return "Dispatch credentialSubject allowedWhen is invalid";
|
|
2749
2752
|
}
|
|
2750
2753
|
if (hasIssueUnderPath(issues, ["credentialSubject"])) {
|
|
2751
2754
|
return "Dispatch credentialSubject type must be user";
|
|
@@ -2772,26 +2775,27 @@ function validateDispatchOptions(options) {
|
|
|
2772
2775
|
throw new Error("Dispatch destination platform must be slack");
|
|
2773
2776
|
}
|
|
2774
2777
|
if (credentialSubject !== void 0) {
|
|
2775
|
-
if (!isDmChannel(destination.channelId)) {
|
|
2778
|
+
if (credentialSubject.allowedWhen === "private-direct-conversation" && !isDmChannel(destination.channelId)) {
|
|
2776
2779
|
throw new Error(
|
|
2777
2780
|
"Dispatch credentialSubject requires a private direct Slack destination"
|
|
2778
2781
|
);
|
|
2779
2782
|
}
|
|
2780
2783
|
}
|
|
2781
2784
|
}
|
|
2782
|
-
async function verifyDispatchCredentialSubjectAccess(options) {
|
|
2785
|
+
async function verifyDispatchCredentialSubjectAccess(options, plugin) {
|
|
2783
2786
|
if (!options.credentialSubject) {
|
|
2784
2787
|
return;
|
|
2785
2788
|
}
|
|
2786
|
-
const verified =
|
|
2789
|
+
const verified = options.credentialSubject.allowedWhen === "scheduled-task" ? verifyScheduledTaskCredentialSubject({
|
|
2790
|
+
plugin,
|
|
2791
|
+
subject: options.credentialSubject
|
|
2792
|
+
}) : verifySlackDirectCredentialSubject({
|
|
2787
2793
|
channelId: options.destination.channelId,
|
|
2788
2794
|
teamId: options.destination.teamId,
|
|
2789
2795
|
subject: options.credentialSubject
|
|
2790
2796
|
});
|
|
2791
2797
|
if (!verified) {
|
|
2792
|
-
throw new Error(
|
|
2793
|
-
"Dispatch credentialSubject must match the private direct Slack destination"
|
|
2794
|
-
);
|
|
2798
|
+
throw new Error("Dispatch credentialSubject is not valid for this action");
|
|
2795
2799
|
}
|
|
2796
2800
|
}
|
|
2797
2801
|
|
|
@@ -2803,7 +2807,7 @@ function shouldScheduleDispatch(record, nowMs) {
|
|
|
2803
2807
|
}
|
|
2804
2808
|
return record.status !== "running" || typeof record.leaseExpiresAtMs !== "number" || record.leaseExpiresAtMs <= nowMs;
|
|
2805
2809
|
}
|
|
2806
|
-
function bindDispatchCredentialSubject(options) {
|
|
2810
|
+
function bindDispatchCredentialSubject(options, plugin) {
|
|
2807
2811
|
const { credentialSubject, ...baseOptions } = options;
|
|
2808
2812
|
if (!credentialSubject) {
|
|
2809
2813
|
return baseOptions;
|
|
@@ -2811,15 +2815,16 @@ function bindDispatchCredentialSubject(options) {
|
|
|
2811
2815
|
if ("binding" in credentialSubject) {
|
|
2812
2816
|
throw new Error("Dispatch credentialSubject binding is runtime-owned");
|
|
2813
2817
|
}
|
|
2814
|
-
const boundSubject =
|
|
2818
|
+
const boundSubject = credentialSubject.allowedWhen === "scheduled-task" ? bindScheduledTaskCredentialSubject({
|
|
2819
|
+
plugin,
|
|
2820
|
+
subject: credentialSubject
|
|
2821
|
+
}) : bindSlackDirectCredentialSubject({
|
|
2815
2822
|
channelId: options.destination.channelId,
|
|
2816
2823
|
teamId: options.destination.teamId,
|
|
2817
2824
|
subject: credentialSubject
|
|
2818
2825
|
});
|
|
2819
2826
|
if (!boundSubject) {
|
|
2820
|
-
throw new Error(
|
|
2821
|
-
"Dispatch credentialSubject must match the private direct Slack destination"
|
|
2822
|
-
);
|
|
2827
|
+
throw new Error("Dispatch credentialSubject is not valid for this action");
|
|
2823
2828
|
}
|
|
2824
2829
|
return {
|
|
2825
2830
|
...baseOptions,
|
|
@@ -2838,11 +2843,17 @@ function createHeartbeatContext(args) {
|
|
|
2838
2843
|
agent: {
|
|
2839
2844
|
async dispatch(options) {
|
|
2840
2845
|
validateDispatchOptions(options);
|
|
2841
|
-
const dispatchOptions = bindDispatchCredentialSubject(
|
|
2846
|
+
const dispatchOptions = bindDispatchCredentialSubject(
|
|
2847
|
+
options,
|
|
2848
|
+
pluginName
|
|
2849
|
+
);
|
|
2842
2850
|
if (dispatchCount >= MAX_DISPATCHES_PER_HEARTBEAT) {
|
|
2843
2851
|
throw new Error("Plugin heartbeat exceeded the dispatch limit");
|
|
2844
2852
|
}
|
|
2845
|
-
await verifyDispatchCredentialSubjectAccess(
|
|
2853
|
+
await verifyDispatchCredentialSubjectAccess(
|
|
2854
|
+
dispatchOptions,
|
|
2855
|
+
pluginName
|
|
2856
|
+
);
|
|
2846
2857
|
const result = await createOrGetDispatch({
|
|
2847
2858
|
plugin: pluginName,
|
|
2848
2859
|
options: dispatchOptions,
|
|
@@ -4497,6 +4508,11 @@ var CALLBACK_PAGES = {
|
|
|
4497
4508
|
message: "Missing code parameter.",
|
|
4498
4509
|
status: 400
|
|
4499
4510
|
},
|
|
4511
|
+
expired: {
|
|
4512
|
+
title: "Authorization expired",
|
|
4513
|
+
message: "This authorization link is no longer active. Return to Slack and retry the original request.",
|
|
4514
|
+
status: 400
|
|
4515
|
+
},
|
|
4500
4516
|
success: {
|
|
4501
4517
|
title: "Authorization complete",
|
|
4502
4518
|
message: "Your MCP access is connected. Junior will continue the paused request in Slack.",
|
|
@@ -4508,6 +4524,12 @@ var CALLBACK_PAGES = {
|
|
|
4508
4524
|
status: 500
|
|
4509
4525
|
}
|
|
4510
4526
|
};
|
|
4527
|
+
var McpOAuthAttemptExpiredError = class extends Error {
|
|
4528
|
+
constructor() {
|
|
4529
|
+
super("MCP OAuth authorization attempt is no longer current");
|
|
4530
|
+
this.name = "McpOAuthAttemptExpiredError";
|
|
4531
|
+
}
|
|
4532
|
+
};
|
|
4511
4533
|
function mcpAuthorizationId(args) {
|
|
4512
4534
|
return `${args.sessionId}:mcp:${args.provider}`;
|
|
4513
4535
|
}
|
|
@@ -4597,20 +4619,19 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4597
4619
|
provider,
|
|
4598
4620
|
actorId: authSession.userId
|
|
4599
4621
|
});
|
|
4600
|
-
|
|
4622
|
+
if (pendingAuth?.authSessionId !== authSession.authSessionId) {
|
|
4623
|
+
return;
|
|
4624
|
+
}
|
|
4625
|
+
const resolvedSessionId = pendingAuth.sessionId;
|
|
4601
4626
|
const userMessage = getTurnUserMessage(conversation, resolvedSessionId);
|
|
4602
|
-
if (pendingAuth) {
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
});
|
|
4611
|
-
return;
|
|
4612
|
-
}
|
|
4613
|
-
} else if (conversation.processing.activeTurnId !== authSession.sessionId) {
|
|
4627
|
+
if (!isPendingAuthLatestRequest(conversation, pendingAuth)) {
|
|
4628
|
+
clearPendingAuth(conversation, pendingAuth.sessionId);
|
|
4629
|
+
await persistThreadStateById(threadId, { conversation });
|
|
4630
|
+
await abandonAgentTurnSessionRecord({
|
|
4631
|
+
conversationId: authSession.conversationId,
|
|
4632
|
+
sessionId: pendingAuth.sessionId,
|
|
4633
|
+
errorMessage: "Auth completed after a newer thread message abandoned this blocked request."
|
|
4634
|
+
});
|
|
4614
4635
|
return;
|
|
4615
4636
|
}
|
|
4616
4637
|
if (!userMessage) {
|
|
@@ -4638,24 +4659,23 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4638
4659
|
provider,
|
|
4639
4660
|
actorId: authSession.userId
|
|
4640
4661
|
});
|
|
4641
|
-
|
|
4662
|
+
if (lockedPendingAuth?.authSessionId !== authSession.authSessionId) {
|
|
4663
|
+
return false;
|
|
4664
|
+
}
|
|
4665
|
+
const lockedSessionId = lockedPendingAuth.sessionId;
|
|
4642
4666
|
if (lockedSessionId !== resolvedSessionId) {
|
|
4643
4667
|
return false;
|
|
4644
4668
|
}
|
|
4645
|
-
if (lockedPendingAuth) {
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
});
|
|
4656
|
-
return false;
|
|
4657
|
-
}
|
|
4658
|
-
} else if (lockedConversation.processing.activeTurnId !== authSession.sessionId) {
|
|
4669
|
+
if (!isPendingAuthLatestRequest(lockedConversation, lockedPendingAuth)) {
|
|
4670
|
+
clearPendingAuth(lockedConversation, lockedPendingAuth.sessionId);
|
|
4671
|
+
await persistThreadStateById(threadId, {
|
|
4672
|
+
conversation: lockedConversation
|
|
4673
|
+
});
|
|
4674
|
+
await abandonAgentTurnSessionRecord({
|
|
4675
|
+
conversationId: authSession.conversationId,
|
|
4676
|
+
sessionId: lockedPendingAuth.sessionId,
|
|
4677
|
+
errorMessage: "Auth completed after a newer thread message abandoned this blocked request."
|
|
4678
|
+
});
|
|
4659
4679
|
return false;
|
|
4660
4680
|
}
|
|
4661
4681
|
const lockedUserMessage = getTurnUserMessage(
|
|
@@ -4755,11 +4775,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4755
4775
|
},
|
|
4756
4776
|
durability: {
|
|
4757
4777
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
4758
|
-
|
|
4759
|
-
conversation: lockedConversation,
|
|
4760
|
-
conversationId: authSession.conversationId,
|
|
4761
|
-
nextPendingAuth
|
|
4762
|
-
});
|
|
4778
|
+
lockedConversation.processing.pendingAuth = nextPendingAuth;
|
|
4763
4779
|
await persistThreadStateById(threadId, {
|
|
4764
4780
|
conversation: lockedConversation
|
|
4765
4781
|
});
|
|
@@ -4824,6 +4840,43 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4824
4840
|
}
|
|
4825
4841
|
});
|
|
4826
4842
|
}
|
|
4843
|
+
async function isCurrentMcpAuthorizationAttempt(authSession, provider) {
|
|
4844
|
+
if (!authSession.channelId || !authSession.threadTs) {
|
|
4845
|
+
return false;
|
|
4846
|
+
}
|
|
4847
|
+
const threadId = `slack:${authSession.channelId}:${authSession.threadTs}`;
|
|
4848
|
+
const currentState = await getPersistedThreadState(threadId);
|
|
4849
|
+
const conversation = coerceThreadConversationState(currentState);
|
|
4850
|
+
const pendingAuth = getConversationPendingAuth({
|
|
4851
|
+
conversation,
|
|
4852
|
+
kind: "mcp",
|
|
4853
|
+
provider,
|
|
4854
|
+
actorId: authSession.userId
|
|
4855
|
+
});
|
|
4856
|
+
return pendingAuth?.authSessionId === authSession.authSessionId && pendingAuth.sessionId === authSession.sessionId;
|
|
4857
|
+
}
|
|
4858
|
+
async function runCurrentMcpCredentialMutation(authSession, provider, mutation) {
|
|
4859
|
+
if (!authSession.channelId || !authSession.threadTs) {
|
|
4860
|
+
throw new McpOAuthAttemptExpiredError();
|
|
4861
|
+
}
|
|
4862
|
+
const threadId = `slack:${authSession.channelId}:${authSession.threadTs}`;
|
|
4863
|
+
const stateAdapter = getStateAdapter();
|
|
4864
|
+
await stateAdapter.connect();
|
|
4865
|
+
const lock = await acquireActiveLock(stateAdapter, threadId);
|
|
4866
|
+
if (!lock) {
|
|
4867
|
+
throw new Error(
|
|
4868
|
+
`Could not acquire MCP OAuth callback lock for ${threadId}`
|
|
4869
|
+
);
|
|
4870
|
+
}
|
|
4871
|
+
try {
|
|
4872
|
+
if (!await isCurrentMcpAuthorizationAttempt(authSession, provider)) {
|
|
4873
|
+
throw new McpOAuthAttemptExpiredError();
|
|
4874
|
+
}
|
|
4875
|
+
return await mutation();
|
|
4876
|
+
} finally {
|
|
4877
|
+
await stateAdapter.releaseLock(lock);
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4827
4880
|
async function GET4(request, provider, waitUntil, options) {
|
|
4828
4881
|
const url = new URL(request.url);
|
|
4829
4882
|
const state = url.searchParams.get("state")?.trim();
|
|
@@ -4839,7 +4892,23 @@ async function GET4(request, provider, waitUntil, options) {
|
|
|
4839
4892
|
return htmlResponse("missing_code");
|
|
4840
4893
|
}
|
|
4841
4894
|
try {
|
|
4842
|
-
const
|
|
4895
|
+
const pendingSession = await getMcpAuthSession(state);
|
|
4896
|
+
if (!pendingSession || pendingSession.provider !== provider || !await isCurrentMcpAuthorizationAttempt(pendingSession, provider)) {
|
|
4897
|
+
if (pendingSession) {
|
|
4898
|
+
await deleteMcpAuthSession(pendingSession.authSessionId);
|
|
4899
|
+
}
|
|
4900
|
+
return htmlResponse("expired");
|
|
4901
|
+
}
|
|
4902
|
+
const authSession = await finalizeMcpAuthorization(
|
|
4903
|
+
provider,
|
|
4904
|
+
state,
|
|
4905
|
+
code,
|
|
4906
|
+
async (mutation) => await runCurrentMcpCredentialMutation(
|
|
4907
|
+
pendingSession,
|
|
4908
|
+
provider,
|
|
4909
|
+
mutation
|
|
4910
|
+
)
|
|
4911
|
+
);
|
|
4843
4912
|
try {
|
|
4844
4913
|
await deleteMcpAuthSession(authSession.authSessionId);
|
|
4845
4914
|
} catch (cleanupError) {
|
|
@@ -4860,6 +4929,10 @@ async function GET4(request, provider, waitUntil, options) {
|
|
|
4860
4929
|
);
|
|
4861
4930
|
return htmlResponse("success");
|
|
4862
4931
|
} catch (callbackError) {
|
|
4932
|
+
if (callbackError instanceof McpOAuthAttemptExpiredError) {
|
|
4933
|
+
await deleteMcpAuthSession(state);
|
|
4934
|
+
return htmlResponse("expired");
|
|
4935
|
+
}
|
|
4863
4936
|
logException(
|
|
4864
4937
|
callbackError,
|
|
4865
4938
|
"mcp_oauth_callback_failed",
|
|
@@ -5304,11 +5377,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
5304
5377
|
},
|
|
5305
5378
|
durability: {
|
|
5306
5379
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
5307
|
-
|
|
5308
|
-
conversation: lockedConversation,
|
|
5309
|
-
conversationId: stored.resumeConversationId,
|
|
5310
|
-
nextPendingAuth
|
|
5311
|
-
});
|
|
5380
|
+
lockedConversation.processing.pendingAuth = nextPendingAuth;
|
|
5312
5381
|
await persistThreadStateById(stored.resumeConversationId, {
|
|
5313
5382
|
conversation: lockedConversation
|
|
5314
5383
|
});
|
|
@@ -10108,11 +10177,7 @@ function createReplyToThread(deps) {
|
|
|
10108
10177
|
});
|
|
10109
10178
|
},
|
|
10110
10179
|
recordPendingAuth: async (pendingAuth) => {
|
|
10111
|
-
|
|
10112
|
-
conversation: preparedState.conversation,
|
|
10113
|
-
conversationId,
|
|
10114
|
-
nextPendingAuth: pendingAuth
|
|
10115
|
-
});
|
|
10180
|
+
preparedState.conversation.processing.pendingAuth = pendingAuth;
|
|
10116
10181
|
await persistThreadState(thread, {
|
|
10117
10182
|
conversation: preparedState.conversation
|
|
10118
10183
|
});
|
|
@@ -11200,11 +11265,7 @@ async function continueSlackAgentRun(payload, options) {
|
|
|
11200
11265
|
},
|
|
11201
11266
|
durability: {
|
|
11202
11267
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
11203
|
-
|
|
11204
|
-
conversation,
|
|
11205
|
-
conversationId: payload.conversationId,
|
|
11206
|
-
nextPendingAuth
|
|
11207
|
-
});
|
|
11268
|
+
conversation.processing.pendingAuth = nextPendingAuth;
|
|
11208
11269
|
await persistThreadStateById(payload.conversationId, {
|
|
11209
11270
|
conversation
|
|
11210
11271
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PiMessage } from "@/chat/pi/messages";
|
|
2
2
|
import { type LogContext } from "@/chat/logging";
|
|
3
|
-
import {
|
|
3
|
+
import type { ConversationPrivacy } from "@/chat/conversation-privacy";
|
|
4
4
|
import type { SkillInvocation, SkillMetadata } from "@/chat/skills";
|
|
5
5
|
import type { ActiveMcpCatalogSummary } from "@/chat/tool-support/skill/mcp-tool-summary";
|
|
6
6
|
import type { ToolRuntimeContext } from "@/chat/tools/types";
|
|
@@ -133,7 +133,7 @@ export interface AgentRunDurability {
|
|
|
133
133
|
/** Return true when the durable worker should pause at the next Pi boundary. */
|
|
134
134
|
shouldYield?: () => boolean;
|
|
135
135
|
drainSteeringMessages?: (accept: (messages: AgentRunSteeringMessage[]) => Promise<void>) => Promise<AgentRunSteeringMessage[]>;
|
|
136
|
-
recordPendingAuth?: (pendingAuth: ConversationPendingAuthState) => void | Promise<void>;
|
|
136
|
+
recordPendingAuth?: (pendingAuth: ConversationPendingAuthState | undefined) => void | Promise<void>;
|
|
137
137
|
onSandboxAcquired?: (sandbox: SandboxAcquiredState) => void | Promise<void>;
|
|
138
138
|
onArtifactStateUpdated?: (artifactState: ThreadArtifactsState) => void | Promise<void>;
|
|
139
139
|
}
|
|
@@ -2,4 +2,4 @@ import type { BoundDispatchOptions, SlackDispatchOptions } from "./types";
|
|
|
2
2
|
/** Validate plugin-provided dispatch options before core persists them. */
|
|
3
3
|
export declare function validateDispatchOptions(options: unknown): asserts options is SlackDispatchOptions;
|
|
4
4
|
/** Verify runtime-owned access requirements for delegated dispatch credentials. */
|
|
5
|
-
export declare function verifyDispatchCredentialSubjectAccess(options: BoundDispatchOptions): Promise<void>;
|
|
5
|
+
export declare function verifyDispatchCredentialSubjectAccess(options: BoundDispatchOptions, plugin: string): Promise<void>;
|
|
@@ -25,14 +25,10 @@ export declare function canExposeConversationPayload(input: {
|
|
|
25
25
|
export declare function getCurrentConversationPrivacy(): ConversationPrivacy | undefined;
|
|
26
26
|
/** Bind one conversation privacy mode to all async work in a turn. */
|
|
27
27
|
export declare function runWithConversationPrivacy<T>(privacy: ConversationPrivacy, callback: () => T): T;
|
|
28
|
-
/** Convert a GenAI message into safe metadata for private trace contexts. */
|
|
29
|
-
export declare function toGenAiMessageMetadata(message: unknown): Record<string, unknown>;
|
|
30
|
-
/** Convert raw text into size-only metadata for private trace contexts. */
|
|
31
|
-
export declare function toGenAiTextMetadata(text: string): Record<string, unknown>;
|
|
32
28
|
/** Convert an arbitrary payload into safe structured metadata for trace data fields. */
|
|
33
29
|
export declare function toGenAiPayloadMetadata(payload: unknown): Record<string, unknown>;
|
|
34
30
|
/** Convert an arbitrary payload into safe flattened trace attributes. */
|
|
35
|
-
export declare function toGenAiPayloadTraceAttributes(prefix:
|
|
31
|
+
export declare function toGenAiPayloadTraceAttributes(prefix: "gen_ai.tool.call.arguments" | "gen_ai.tool.call.result", payload: unknown): Record<string, TraceAttributeValue>;
|
|
36
32
|
/**
|
|
37
33
|
* Map a pi-ai AssistantMessage to the canonical gen_ai.output.messages shape:
|
|
38
34
|
* `{ role, parts: [...], finish_reason }` — drops provider noise fields.
|
|
@@ -44,5 +40,5 @@ export declare function toCanonicalOutputMessage(message: AssistantMessage): Rec
|
|
|
44
40
|
*/
|
|
45
41
|
export declare function toCanonicalInputMessage(message: Message): Record<string, unknown>;
|
|
46
42
|
/** Summarize a message list without exposing raw message content. */
|
|
47
|
-
export declare function toGenAiMessagesTraceAttributes(prefix:
|
|
43
|
+
export declare function toGenAiMessagesTraceAttributes(prefix: "gen_ai.input" | "gen_ai.output", messages: unknown[]): Record<string, TraceAttributeValue>;
|
|
48
44
|
export {};
|
|
@@ -26,7 +26,7 @@ export interface Conversation {
|
|
|
26
26
|
/**
|
|
27
27
|
* When retention purged this conversation's content. Set means messages and
|
|
28
28
|
* steps were deleted wholesale; reporting presents the transcript as expired
|
|
29
|
-
* rather than privacy-redacted (
|
|
29
|
+
* rather than privacy-redacted (`../../../../../policies/data-redaction.md`).
|
|
30
30
|
*/
|
|
31
31
|
transcriptPurgedAtMs?: number;
|
|
32
32
|
/** Persisted destination visibility. Undefined means no destination row exists. */
|