@sentry/junior 0.100.0 → 0.101.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/api/conversations/schema.d.ts +2 -2
- package/dist/api/schema.js +3 -3
- package/dist/api.js +11 -11
- package/dist/app.js +105 -55
- package/dist/chat/agent/request.d.ts +1 -1
- package/dist/chat/conversations/store.d.ts +1 -1
- 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 +2 -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-VY7BT4SM.js → chunk-5VGJJSSV.js} +4 -3
- package/dist/{chunk-IDZBM3NW.js → chunk-DBPLXSBK.js} +1 -1
- package/dist/{chunk-2T7DCRAW.js → chunk-EBFJOOUE.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-XSBIISXS.js → chunk-L2JIOAA2.js} +2 -2
- package/dist/{chunk-45DMFMY2.js → chunk-UWGTSF5O.js} +220 -110
- package/dist/{chunk-QSBQJ3PA.js → chunk-VFBFK6EY.js} +1 -1
- package/dist/{chunk-6DTVCPLO.js → chunk-XIMUQ4IU.js} +4 -3
- package/dist/{chunk-NSOCZGOH.js → chunk-XVR4O24H.js} +5 -7
- package/dist/cli/chat.js +4 -4
- package/dist/cli/upgrade.js +119 -2
- package/dist/{detail-LU6COZO6.js → detail-4EPUMSDU.js} +2 -2
- package/dist/{detail-5SLCGT6J.js → detail-CD4SPJ4K.js} +3 -3
- package/dist/{list-4ALSU6ZW.js → list-7L5LY2WU.js} +3 -3
- package/dist/{list-2FI5SFV7.js → list-DA2ATOM4.js} +2 -2
- package/dist/{list-KHRAWZWU.js → list-J6ROVH56.js} +1 -1
- package/dist/{profile-3O3OVENT.js → profile-6NRWEKMZ.js} +2 -2
- package/dist/{runner-BM7D35YW.js → runner-CZIKSWGC.js} +3 -3
- package/dist/{stats-J3YGCYDF.js → stats-Q5FRUXLY.js} +1 -1
- package/dist/{subagent-P7HOSMVC.js → subagent-YIINCFAS.js} +2 -2
- package/package.json +6 -6
- package/dist/api-reference.d.ts +0 -14
package/README.md
CHANGED
|
@@ -50,4 +50,3 @@ Canonical docs: **https://junior.sentry.dev/**
|
|
|
50
50
|
- Slack app setup: https://junior.sentry.dev/start-here/slack-app-setup/
|
|
51
51
|
- Deployment: https://junior.sentry.dev/start-here/deploy-to-vercel/
|
|
52
52
|
- Plugin setup: https://junior.sentry.dev/extend/
|
|
53
|
-
- API reference: https://junior.sentry.dev/reference/api/
|
|
@@ -310,7 +310,7 @@ export declare const conversationContextEventSchema: z.ZodDiscriminatedUnion<[z.
|
|
|
310
310
|
type: z.ZodLiteral<"model_handoff">;
|
|
311
311
|
createdAt: z.ZodString;
|
|
312
312
|
fromModelId: z.ZodOptional<z.ZodString>;
|
|
313
|
-
|
|
313
|
+
message: z.ZodOptional<z.ZodString>;
|
|
314
314
|
toModelId: z.ZodString;
|
|
315
315
|
transcriptIndex: z.ZodNumber;
|
|
316
316
|
}, z.core.$strict>], "type">;
|
|
@@ -436,7 +436,7 @@ export declare const conversationDetailReportSchema: z.ZodObject<{
|
|
|
436
436
|
type: z.ZodLiteral<"model_handoff">;
|
|
437
437
|
createdAt: z.ZodString;
|
|
438
438
|
fromModelId: z.ZodOptional<z.ZodString>;
|
|
439
|
-
|
|
439
|
+
message: z.ZodOptional<z.ZodString>;
|
|
440
440
|
toModelId: z.ZodString;
|
|
441
441
|
transcriptIndex: z.ZodNumber;
|
|
442
442
|
}, z.core.$strict>], "type">>>;
|
package/dist/api/schema.js
CHANGED
|
@@ -9,17 +9,17 @@ import {
|
|
|
9
9
|
dailyConversationActivitySchema,
|
|
10
10
|
locationDetailReportSchema,
|
|
11
11
|
locationDirectoryReportSchema
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-HNIT4HXU.js";
|
|
13
13
|
import {
|
|
14
14
|
actorDirectoryReportSchema,
|
|
15
15
|
actorProfileReportSchema
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-DBPLXSBK.js";
|
|
17
17
|
import {
|
|
18
18
|
conversationDetailReportSchema,
|
|
19
19
|
conversationFeedSchema,
|
|
20
20
|
conversationStatsReportSchema,
|
|
21
21
|
conversationSubagentTranscriptReportSchema
|
|
22
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-HYDQULR2.js";
|
|
23
23
|
import {
|
|
24
24
|
healthReportSchema,
|
|
25
25
|
pluginOperationalReportFeedSchema,
|
package/dist/api.js
CHANGED
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
personParamsSchema,
|
|
6
6
|
subagentParamsSchema
|
|
7
7
|
} from "./chunk-2RNOB32R.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-HNIT4HXU.js";
|
|
9
|
+
import "./chunk-DBPLXSBK.js";
|
|
10
|
+
import "./chunk-HYDQULR2.js";
|
|
11
11
|
import {
|
|
12
12
|
readHealthReport
|
|
13
13
|
} from "./chunk-QNVHH5PU.js";
|
|
@@ -126,7 +126,7 @@ function createJuniorApi() {
|
|
|
126
126
|
return Response.json(await readPluginOperationalReportFeed());
|
|
127
127
|
});
|
|
128
128
|
app.get("/api/conversations", async (c) => {
|
|
129
|
-
const { readConversationFeed } = await import("./list-
|
|
129
|
+
const { readConversationFeed } = await import("./list-J6ROVH56.js");
|
|
130
130
|
const { actorEmail } = parseQuery(
|
|
131
131
|
conversationFeedQuerySchema,
|
|
132
132
|
c.req.query()
|
|
@@ -134,11 +134,11 @@ function createJuniorApi() {
|
|
|
134
134
|
return Response.json(await readConversationFeed({ actorEmail }));
|
|
135
135
|
});
|
|
136
136
|
app.get("/api/conversations/stats", async () => {
|
|
137
|
-
const { readConversationStats } = await import("./stats-
|
|
137
|
+
const { readConversationStats } = await import("./stats-Q5FRUXLY.js");
|
|
138
138
|
return Response.json(await readConversationStats());
|
|
139
139
|
});
|
|
140
140
|
app.get("/api/conversations/:conversationId", async (c) => {
|
|
141
|
-
const { readConversationDetail } = await import("./detail-
|
|
141
|
+
const { readConversationDetail } = await import("./detail-4EPUMSDU.js");
|
|
142
142
|
const { conversationId } = parseParams(
|
|
143
143
|
conversationParamsSchema,
|
|
144
144
|
c.req.param()
|
|
@@ -149,7 +149,7 @@ function createJuniorApi() {
|
|
|
149
149
|
app.get(
|
|
150
150
|
"/api/conversations/:conversationId/subagents/:subagentId",
|
|
151
151
|
async (c) => {
|
|
152
|
-
const { readConversationSubagent } = await import("./subagent-
|
|
152
|
+
const { readConversationSubagent } = await import("./subagent-YIINCFAS.js");
|
|
153
153
|
const { conversationId, subagentId } = parseParams(
|
|
154
154
|
subagentParamsSchema,
|
|
155
155
|
c.req.param()
|
|
@@ -159,21 +159,21 @@ function createJuniorApi() {
|
|
|
159
159
|
}
|
|
160
160
|
);
|
|
161
161
|
app.get("/api/people", async () => {
|
|
162
|
-
const { readPeopleList } = await import("./list-
|
|
162
|
+
const { readPeopleList } = await import("./list-DA2ATOM4.js");
|
|
163
163
|
return Response.json(await readPeopleList());
|
|
164
164
|
});
|
|
165
165
|
app.get("/api/people/:email", async (c) => {
|
|
166
166
|
const { email } = parseParams(personParamsSchema, c.req.param());
|
|
167
|
-
const { readPeopleProfile } = await import("./profile-
|
|
167
|
+
const { readPeopleProfile } = await import("./profile-6NRWEKMZ.js");
|
|
168
168
|
return Response.json(await readPeopleProfile(email));
|
|
169
169
|
});
|
|
170
170
|
app.get("/api/locations", async () => {
|
|
171
|
-
const { readLocationDirectory } = await import("./list-
|
|
171
|
+
const { readLocationDirectory } = await import("./list-7L5LY2WU.js");
|
|
172
172
|
return Response.json(await readLocationDirectory());
|
|
173
173
|
});
|
|
174
174
|
app.get("/api/locations/:locationId", async (c) => {
|
|
175
175
|
const { locationId } = parseParams(locationParamsSchema, c.req.param());
|
|
176
|
-
const { readLocationDetail } = await import("./detail-
|
|
176
|
+
const { readLocationDetail } = await import("./detail-CD4SPJ4K.js");
|
|
177
177
|
const report = await readLocationDetail(locationId);
|
|
178
178
|
return report ? Response.json(report) : Response.json({ error: "Location not found." }, { status: 404 });
|
|
179
179
|
});
|
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-L2JIOAA2.js";
|
|
9
9
|
import {
|
|
10
10
|
buildSentryConversationUrl
|
|
11
11
|
} from "./chunk-LVUKF5CE.js";
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
requestConversationContinuation,
|
|
38
38
|
requestConversationWork,
|
|
39
39
|
startConversationWork
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-EBFJOOUE.js";
|
|
41
41
|
import {
|
|
42
42
|
GET
|
|
43
43
|
} from "./chunk-QNVHH5PU.js";
|
|
@@ -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-UWGTSF5O.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,11 +134,11 @@ import {
|
|
|
134
134
|
persistWithRetry,
|
|
135
135
|
persistYieldSessionRecord,
|
|
136
136
|
startActiveTurn
|
|
137
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-XVR4O24H.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,
|
|
@@ -4497,6 +4497,11 @@ var CALLBACK_PAGES = {
|
|
|
4497
4497
|
message: "Missing code parameter.",
|
|
4498
4498
|
status: 400
|
|
4499
4499
|
},
|
|
4500
|
+
expired: {
|
|
4501
|
+
title: "Authorization expired",
|
|
4502
|
+
message: "This authorization link is no longer active. Return to Slack and retry the original request.",
|
|
4503
|
+
status: 400
|
|
4504
|
+
},
|
|
4500
4505
|
success: {
|
|
4501
4506
|
title: "Authorization complete",
|
|
4502
4507
|
message: "Your MCP access is connected. Junior will continue the paused request in Slack.",
|
|
@@ -4508,6 +4513,12 @@ var CALLBACK_PAGES = {
|
|
|
4508
4513
|
status: 500
|
|
4509
4514
|
}
|
|
4510
4515
|
};
|
|
4516
|
+
var McpOAuthAttemptExpiredError = class extends Error {
|
|
4517
|
+
constructor() {
|
|
4518
|
+
super("MCP OAuth authorization attempt is no longer current");
|
|
4519
|
+
this.name = "McpOAuthAttemptExpiredError";
|
|
4520
|
+
}
|
|
4521
|
+
};
|
|
4511
4522
|
function mcpAuthorizationId(args) {
|
|
4512
4523
|
return `${args.sessionId}:mcp:${args.provider}`;
|
|
4513
4524
|
}
|
|
@@ -4597,20 +4608,19 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4597
4608
|
provider,
|
|
4598
4609
|
actorId: authSession.userId
|
|
4599
4610
|
});
|
|
4600
|
-
|
|
4611
|
+
if (pendingAuth?.authSessionId !== authSession.authSessionId) {
|
|
4612
|
+
return;
|
|
4613
|
+
}
|
|
4614
|
+
const resolvedSessionId = pendingAuth.sessionId;
|
|
4601
4615
|
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) {
|
|
4616
|
+
if (!isPendingAuthLatestRequest(conversation, pendingAuth)) {
|
|
4617
|
+
clearPendingAuth(conversation, pendingAuth.sessionId);
|
|
4618
|
+
await persistThreadStateById(threadId, { conversation });
|
|
4619
|
+
await abandonAgentTurnSessionRecord({
|
|
4620
|
+
conversationId: authSession.conversationId,
|
|
4621
|
+
sessionId: pendingAuth.sessionId,
|
|
4622
|
+
errorMessage: "Auth completed after a newer thread message abandoned this blocked request."
|
|
4623
|
+
});
|
|
4614
4624
|
return;
|
|
4615
4625
|
}
|
|
4616
4626
|
if (!userMessage) {
|
|
@@ -4638,24 +4648,23 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4638
4648
|
provider,
|
|
4639
4649
|
actorId: authSession.userId
|
|
4640
4650
|
});
|
|
4641
|
-
|
|
4651
|
+
if (lockedPendingAuth?.authSessionId !== authSession.authSessionId) {
|
|
4652
|
+
return false;
|
|
4653
|
+
}
|
|
4654
|
+
const lockedSessionId = lockedPendingAuth.sessionId;
|
|
4642
4655
|
if (lockedSessionId !== resolvedSessionId) {
|
|
4643
4656
|
return false;
|
|
4644
4657
|
}
|
|
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) {
|
|
4658
|
+
if (!isPendingAuthLatestRequest(lockedConversation, lockedPendingAuth)) {
|
|
4659
|
+
clearPendingAuth(lockedConversation, lockedPendingAuth.sessionId);
|
|
4660
|
+
await persistThreadStateById(threadId, {
|
|
4661
|
+
conversation: lockedConversation
|
|
4662
|
+
});
|
|
4663
|
+
await abandonAgentTurnSessionRecord({
|
|
4664
|
+
conversationId: authSession.conversationId,
|
|
4665
|
+
sessionId: lockedPendingAuth.sessionId,
|
|
4666
|
+
errorMessage: "Auth completed after a newer thread message abandoned this blocked request."
|
|
4667
|
+
});
|
|
4659
4668
|
return false;
|
|
4660
4669
|
}
|
|
4661
4670
|
const lockedUserMessage = getTurnUserMessage(
|
|
@@ -4755,11 +4764,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4755
4764
|
},
|
|
4756
4765
|
durability: {
|
|
4757
4766
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
4758
|
-
|
|
4759
|
-
conversation: lockedConversation,
|
|
4760
|
-
conversationId: authSession.conversationId,
|
|
4761
|
-
nextPendingAuth
|
|
4762
|
-
});
|
|
4767
|
+
lockedConversation.processing.pendingAuth = nextPendingAuth;
|
|
4763
4768
|
await persistThreadStateById(threadId, {
|
|
4764
4769
|
conversation: lockedConversation
|
|
4765
4770
|
});
|
|
@@ -4824,6 +4829,43 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4824
4829
|
}
|
|
4825
4830
|
});
|
|
4826
4831
|
}
|
|
4832
|
+
async function isCurrentMcpAuthorizationAttempt(authSession, provider) {
|
|
4833
|
+
if (!authSession.channelId || !authSession.threadTs) {
|
|
4834
|
+
return false;
|
|
4835
|
+
}
|
|
4836
|
+
const threadId = `slack:${authSession.channelId}:${authSession.threadTs}`;
|
|
4837
|
+
const currentState = await getPersistedThreadState(threadId);
|
|
4838
|
+
const conversation = coerceThreadConversationState(currentState);
|
|
4839
|
+
const pendingAuth = getConversationPendingAuth({
|
|
4840
|
+
conversation,
|
|
4841
|
+
kind: "mcp",
|
|
4842
|
+
provider,
|
|
4843
|
+
actorId: authSession.userId
|
|
4844
|
+
});
|
|
4845
|
+
return pendingAuth?.authSessionId === authSession.authSessionId && pendingAuth.sessionId === authSession.sessionId;
|
|
4846
|
+
}
|
|
4847
|
+
async function runCurrentMcpCredentialMutation(authSession, provider, mutation) {
|
|
4848
|
+
if (!authSession.channelId || !authSession.threadTs) {
|
|
4849
|
+
throw new McpOAuthAttemptExpiredError();
|
|
4850
|
+
}
|
|
4851
|
+
const threadId = `slack:${authSession.channelId}:${authSession.threadTs}`;
|
|
4852
|
+
const stateAdapter = getStateAdapter();
|
|
4853
|
+
await stateAdapter.connect();
|
|
4854
|
+
const lock = await acquireActiveLock(stateAdapter, threadId);
|
|
4855
|
+
if (!lock) {
|
|
4856
|
+
throw new Error(
|
|
4857
|
+
`Could not acquire MCP OAuth callback lock for ${threadId}`
|
|
4858
|
+
);
|
|
4859
|
+
}
|
|
4860
|
+
try {
|
|
4861
|
+
if (!await isCurrentMcpAuthorizationAttempt(authSession, provider)) {
|
|
4862
|
+
throw new McpOAuthAttemptExpiredError();
|
|
4863
|
+
}
|
|
4864
|
+
return await mutation();
|
|
4865
|
+
} finally {
|
|
4866
|
+
await stateAdapter.releaseLock(lock);
|
|
4867
|
+
}
|
|
4868
|
+
}
|
|
4827
4869
|
async function GET4(request, provider, waitUntil, options) {
|
|
4828
4870
|
const url = new URL(request.url);
|
|
4829
4871
|
const state = url.searchParams.get("state")?.trim();
|
|
@@ -4839,7 +4881,23 @@ async function GET4(request, provider, waitUntil, options) {
|
|
|
4839
4881
|
return htmlResponse("missing_code");
|
|
4840
4882
|
}
|
|
4841
4883
|
try {
|
|
4842
|
-
const
|
|
4884
|
+
const pendingSession = await getMcpAuthSession(state);
|
|
4885
|
+
if (!pendingSession || pendingSession.provider !== provider || !await isCurrentMcpAuthorizationAttempt(pendingSession, provider)) {
|
|
4886
|
+
if (pendingSession) {
|
|
4887
|
+
await deleteMcpAuthSession(pendingSession.authSessionId);
|
|
4888
|
+
}
|
|
4889
|
+
return htmlResponse("expired");
|
|
4890
|
+
}
|
|
4891
|
+
const authSession = await finalizeMcpAuthorization(
|
|
4892
|
+
provider,
|
|
4893
|
+
state,
|
|
4894
|
+
code,
|
|
4895
|
+
async (mutation) => await runCurrentMcpCredentialMutation(
|
|
4896
|
+
pendingSession,
|
|
4897
|
+
provider,
|
|
4898
|
+
mutation
|
|
4899
|
+
)
|
|
4900
|
+
);
|
|
4843
4901
|
try {
|
|
4844
4902
|
await deleteMcpAuthSession(authSession.authSessionId);
|
|
4845
4903
|
} catch (cleanupError) {
|
|
@@ -4860,6 +4918,10 @@ async function GET4(request, provider, waitUntil, options) {
|
|
|
4860
4918
|
);
|
|
4861
4919
|
return htmlResponse("success");
|
|
4862
4920
|
} catch (callbackError) {
|
|
4921
|
+
if (callbackError instanceof McpOAuthAttemptExpiredError) {
|
|
4922
|
+
await deleteMcpAuthSession(state);
|
|
4923
|
+
return htmlResponse("expired");
|
|
4924
|
+
}
|
|
4863
4925
|
logException(
|
|
4864
4926
|
callbackError,
|
|
4865
4927
|
"mcp_oauth_callback_failed",
|
|
@@ -5304,11 +5366,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
5304
5366
|
},
|
|
5305
5367
|
durability: {
|
|
5306
5368
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
5307
|
-
|
|
5308
|
-
conversation: lockedConversation,
|
|
5309
|
-
conversationId: stored.resumeConversationId,
|
|
5310
|
-
nextPendingAuth
|
|
5311
|
-
});
|
|
5369
|
+
lockedConversation.processing.pendingAuth = nextPendingAuth;
|
|
5312
5370
|
await persistThreadStateById(stored.resumeConversationId, {
|
|
5313
5371
|
conversation: lockedConversation
|
|
5314
5372
|
});
|
|
@@ -10108,11 +10166,7 @@ function createReplyToThread(deps) {
|
|
|
10108
10166
|
});
|
|
10109
10167
|
},
|
|
10110
10168
|
recordPendingAuth: async (pendingAuth) => {
|
|
10111
|
-
|
|
10112
|
-
conversation: preparedState.conversation,
|
|
10113
|
-
conversationId,
|
|
10114
|
-
nextPendingAuth: pendingAuth
|
|
10115
|
-
});
|
|
10169
|
+
preparedState.conversation.processing.pendingAuth = pendingAuth;
|
|
10116
10170
|
await persistThreadState(thread, {
|
|
10117
10171
|
conversation: preparedState.conversation
|
|
10118
10172
|
});
|
|
@@ -11200,11 +11254,7 @@ async function continueSlackAgentRun(payload, options) {
|
|
|
11200
11254
|
},
|
|
11201
11255
|
durability: {
|
|
11202
11256
|
recordPendingAuth: async (nextPendingAuth) => {
|
|
11203
|
-
|
|
11204
|
-
conversation,
|
|
11205
|
-
conversationId: payload.conversationId,
|
|
11206
|
-
nextPendingAuth
|
|
11207
|
-
});
|
|
11257
|
+
conversation.processing.pendingAuth = nextPendingAuth;
|
|
11208
11258
|
await persistThreadStateById(payload.conversationId, {
|
|
11209
11259
|
conversation
|
|
11210
11260
|
});
|
|
@@ -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
|
}
|
|
@@ -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. */
|
|
@@ -3,6 +3,7 @@ import type { OAuthDiscoveryState } from "@modelcontextprotocol/sdk/client/auth.
|
|
|
3
3
|
import { type Destination, type Source } from "@sentry/junior-plugin-api";
|
|
4
4
|
import type { ThreadArtifactsState } from "@/chat/state/artifacts";
|
|
5
5
|
export interface McpAuthSessionState {
|
|
6
|
+
schemaVersion: 2;
|
|
6
7
|
authSessionId: string;
|
|
7
8
|
provider: string;
|
|
8
9
|
userId: string;
|
|
@@ -15,6 +15,7 @@ export declare class PluginMcpClient {
|
|
|
15
15
|
private readonly plugin;
|
|
16
16
|
private readonly options;
|
|
17
17
|
private client?;
|
|
18
|
+
private clientPromise?;
|
|
18
19
|
private lastAttemptedTransportSessionId?;
|
|
19
20
|
private transport?;
|
|
20
21
|
private listedTools?;
|
|
@@ -24,6 +25,7 @@ export declare class PluginMcpClient {
|
|
|
24
25
|
close(): Promise<void>;
|
|
25
26
|
private withSessionRecovery;
|
|
26
27
|
private getClient;
|
|
28
|
+
private connectClient;
|
|
27
29
|
private wrapAuth;
|
|
28
30
|
private shouldResetMissingSession;
|
|
29
31
|
private disposeClient;
|
|
@@ -5,8 +5,9 @@ export declare class StateBackedMcpOAuthClientProvider implements OAuthClientPro
|
|
|
5
5
|
readonly authSessionId: string;
|
|
6
6
|
private readonly callbackUrl;
|
|
7
7
|
private readonly sessionContext?;
|
|
8
|
+
private readonly runCredentialMutation?;
|
|
8
9
|
readonly clientMetadata: OAuthClientMetadata;
|
|
9
|
-
constructor(authSessionId: string, callbackUrl: string, sessionContext?: Omit<McpAuthSessionState, "authSessionId" | "authorizationUrl" | "codeVerifier" | "createdAtMs" | "updatedAtMs"> | undefined);
|
|
10
|
+
constructor(authSessionId: string, callbackUrl: string, sessionContext?: Omit<McpAuthSessionState, "schemaVersion" | "authSessionId" | "authorizationUrl" | "codeVerifier" | "createdAtMs" | "updatedAtMs"> | undefined, runCredentialMutation?: (<T>(mutation: () => Promise<T>) => Promise<T>) | undefined);
|
|
10
11
|
get redirectUrl(): string;
|
|
11
12
|
state(): Promise<string>;
|
|
12
13
|
clientInformation(): Promise<OAuthClientInformationMixed | undefined>;
|
|
@@ -21,6 +22,8 @@ export declare class StateBackedMcpOAuthClientProvider implements OAuthClientPro
|
|
|
21
22
|
invalidateCredentials(scope: "all" | "client" | "tokens" | "verifier" | "discovery"): Promise<void>;
|
|
22
23
|
getMcpServerSessionId(): Promise<string | undefined>;
|
|
23
24
|
saveMcpServerSessionId(sessionId: string | undefined): Promise<void>;
|
|
25
|
+
/** Route shared credential writes through callback-owned freshness control. */
|
|
26
|
+
private mutateCredentials;
|
|
24
27
|
private getCredentialContext;
|
|
25
28
|
private ensureSession;
|
|
26
29
|
private requireSession;
|
package/dist/chat/mcp/oauth.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { ThreadArtifactsState } from "@/chat/state/artifacts";
|
|
|
3
3
|
import { type McpAuthSessionState } from "./auth-store";
|
|
4
4
|
import { StateBackedMcpOAuthClientProvider } from "./oauth-provider";
|
|
5
5
|
export declare function getMcpOAuthCallbackPath(provider: string): string;
|
|
6
|
+
/** Create one immutable provider authorization attempt for the active turn. */
|
|
6
7
|
export declare function createMcpOAuthClientProvider(input: {
|
|
7
8
|
provider: string;
|
|
8
9
|
conversationId: string;
|
|
@@ -17,4 +18,5 @@ export declare function createMcpOAuthClientProvider(input: {
|
|
|
17
18
|
configuration?: Record<string, unknown>;
|
|
18
19
|
artifactState?: ThreadArtifactsState;
|
|
19
20
|
}): Promise<StateBackedMcpOAuthClientProvider>;
|
|
20
|
-
|
|
21
|
+
/** Exchange a callback code while guarding every shared credential mutation. */
|
|
22
|
+
export declare function finalizeMcpAuthorization(provider: string, authSessionId: string, authorizationCode: string, runCredentialMutation?: <T>(mutation: () => Promise<T>) => Promise<T>): Promise<McpAuthSessionState>;
|
|
@@ -43,6 +43,7 @@ export declare class McpToolManager {
|
|
|
43
43
|
private readonly activeProviders;
|
|
44
44
|
private readonly authorizationPendingProviders;
|
|
45
45
|
private readonly clientsByProvider;
|
|
46
|
+
private readonly clientPromisesByProvider;
|
|
46
47
|
private readonly toolsByProvider;
|
|
47
48
|
constructor(plugins: PluginDefinition[], options?: McpToolManagerOptions);
|
|
48
49
|
getActiveProviders(): string[];
|
|
@@ -61,6 +62,7 @@ export declare class McpToolManager {
|
|
|
61
62
|
}): ManagedMcpToolDescriptor[];
|
|
62
63
|
private filterListedTools;
|
|
63
64
|
private getClient;
|
|
65
|
+
private createClient;
|
|
64
66
|
private toManagedTool;
|
|
65
67
|
private handleAuthorizationRequired;
|
|
66
68
|
/** Return all active ManagedMcpTool objects, optionally filtered by provider. */
|
|
@@ -30,7 +30,7 @@ export interface McpAuthOrchestrationInput {
|
|
|
30
30
|
getConfiguration: () => Record<string, unknown>;
|
|
31
31
|
getArtifactState: () => ThreadArtifactsState | undefined;
|
|
32
32
|
getMergedArtifactState: () => ThreadArtifactsState;
|
|
33
|
-
recordPendingAuth?: (pendingAuth: ConversationPendingAuthState) => void | Promise<void>;
|
|
33
|
+
recordPendingAuth?: (pendingAuth: ConversationPendingAuthState | undefined) => void | Promise<void>;
|
|
34
34
|
authorizationFlowMode?: AuthorizationFlowMode;
|
|
35
35
|
}
|
|
36
36
|
export interface McpAuthOrchestration {
|
|
@@ -10,22 +10,30 @@ export declare function canReusePendingAuthLink(args: {
|
|
|
10
10
|
scope?: string;
|
|
11
11
|
sessionId: string;
|
|
12
12
|
}): boolean;
|
|
13
|
+
/** Return the exact pending authorization target for one actor and provider. */
|
|
13
14
|
export declare function getConversationPendingAuth(args: {
|
|
14
15
|
conversation: ThreadConversationState;
|
|
15
|
-
kind:
|
|
16
|
+
kind: "mcp";
|
|
16
17
|
provider: string;
|
|
17
18
|
actorId: string;
|
|
18
19
|
scope?: string;
|
|
19
|
-
}): ConversationPendingAuthState
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* different session's pending-auth, mark the prior session record as abandoned.
|
|
24
|
-
* Callers are responsible for persisting the mutated conversation afterwards.
|
|
25
|
-
*/
|
|
26
|
-
export declare function applyPendingAuthUpdate(args: {
|
|
20
|
+
}): Extract<ConversationPendingAuthState, {
|
|
21
|
+
kind: "mcp";
|
|
22
|
+
}> | undefined;
|
|
23
|
+
export declare function getConversationPendingAuth(args: {
|
|
27
24
|
conversation: ThreadConversationState;
|
|
25
|
+
kind: "plugin";
|
|
26
|
+
provider: string;
|
|
27
|
+
actorId: string;
|
|
28
|
+
scope?: string;
|
|
29
|
+
}): Extract<ConversationPendingAuthState, {
|
|
30
|
+
kind: "plugin";
|
|
31
|
+
}> | undefined;
|
|
32
|
+
export declare function clearPendingAuth(conversation: ThreadConversationState, sessionId?: string): void;
|
|
33
|
+
/** Mark the prior blocked turn abandoned after a new auth attempt replaces it. */
|
|
34
|
+
export declare function abandonReplacedPendingAuth(args: {
|
|
28
35
|
conversationId: string | undefined;
|
|
36
|
+
previousPendingAuth: ConversationPendingAuthState | undefined;
|
|
29
37
|
nextPendingAuth: ConversationPendingAuthState;
|
|
30
38
|
}): Promise<void>;
|
|
31
39
|
/**
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { AuthorizationPauseKind } from "@/chat/services/auth-pause";
|
|
2
1
|
type ConversationRole = "assistant" | "system" | "user";
|
|
3
2
|
export interface ConversationAuthor {
|
|
4
3
|
fullName?: string;
|
|
@@ -39,14 +38,19 @@ export interface ConversationProcessingState {
|
|
|
39
38
|
lastCompletedAtMs?: number;
|
|
40
39
|
pendingAuth?: ConversationPendingAuthState;
|
|
41
40
|
}
|
|
42
|
-
|
|
43
|
-
kind: AuthorizationPauseKind;
|
|
41
|
+
interface ConversationPendingAuthBase {
|
|
44
42
|
linkSentAtMs: number;
|
|
45
43
|
provider: string;
|
|
46
44
|
actorId: string;
|
|
47
45
|
scope?: string;
|
|
48
46
|
sessionId: string;
|
|
49
47
|
}
|
|
48
|
+
export type ConversationPendingAuthState = (ConversationPendingAuthBase & {
|
|
49
|
+
authSessionId: string;
|
|
50
|
+
kind: "mcp";
|
|
51
|
+
}) | (ConversationPendingAuthBase & {
|
|
52
|
+
kind: "plugin";
|
|
53
|
+
});
|
|
50
54
|
export interface ConversationStats {
|
|
51
55
|
compactedMessageCount: number;
|
|
52
56
|
estimatedContextTokens: number;
|
|
@@ -465,10 +465,11 @@ function historyContent(args) {
|
|
|
465
465
|
) : marker?.entry.reason === "handoff" ? summaryIndex(projected, projectedProvenance, [
|
|
466
466
|
MODEL_HANDOFF_SUMMARY_PREFIX
|
|
467
467
|
]) : -1;
|
|
468
|
-
const summary = replacementSummaryIndex >= 0 ? summaryAfterPrefix(
|
|
468
|
+
const summary = marker?.entry.reason === "compaction" && replacementSummaryIndex >= 0 ? summaryAfterPrefix(
|
|
469
469
|
projected[replacementSummaryIndex],
|
|
470
|
-
|
|
470
|
+
COMPACTION_SUMMARY_PREFIXES
|
|
471
471
|
) : void 0;
|
|
472
|
+
const handoffMessage = marker?.entry.reason === "handoff" && replacementSummaryIndex >= 0 ? messageText(projected[replacementSummaryIndex]) || void 0 : void 0;
|
|
472
473
|
if (marker?.entry.reason === "compaction") {
|
|
473
474
|
contextEvents.push({
|
|
474
475
|
type: "context_compacted",
|
|
@@ -483,7 +484,7 @@ function historyContent(args) {
|
|
|
483
484
|
createdAt: new Date(marker.createdAtMs).toISOString(),
|
|
484
485
|
...previousModelId ? { fromModelId: previousModelId } : {},
|
|
485
486
|
toModelId: marker.entry.modelId,
|
|
486
|
-
...args.canExposePayload &&
|
|
487
|
+
...args.canExposePayload && handoffMessage ? { message: handoffMessage } : {},
|
|
487
488
|
transcriptIndex: messages.length
|
|
488
489
|
});
|
|
489
490
|
}
|
|
@@ -131,7 +131,7 @@ var conversationContextEventSchema = z.discriminatedUnion("type", [
|
|
|
131
131
|
type: z.literal("model_handoff"),
|
|
132
132
|
createdAt: z.string(),
|
|
133
133
|
fromModelId: z.string().optional(),
|
|
134
|
-
|
|
134
|
+
message: z.string().optional(),
|
|
135
135
|
toModelId: z.string(),
|
|
136
136
|
transcriptIndex: z.number().int().nonnegative()
|
|
137
137
|
}).strict()
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
getPersistedThreadState,
|
|
10
10
|
markTurnCompleted,
|
|
11
11
|
mergeArtifactsState
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-XVR4O24H.js";
|
|
13
13
|
import {
|
|
14
14
|
coerceThreadConversationState
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-XIMUQ4IU.js";
|
|
16
16
|
import {
|
|
17
17
|
getAgentTurnSessionRecord
|
|
18
18
|
} from "./chunk-IVXL57YF.js";
|