@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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CooperativeTurnYieldError,
|
|
3
3
|
TurnInputCommitLostError,
|
|
4
|
+
abandonReplacedPendingAuth,
|
|
4
5
|
canReusePendingAuthLink,
|
|
5
6
|
getInterruptionMarker,
|
|
6
7
|
isTurnInputCommitLostError,
|
|
@@ -10,10 +11,10 @@ import {
|
|
|
10
11
|
persistRunningSessionRecord,
|
|
11
12
|
persistTimeoutSessionRecord,
|
|
12
13
|
persistYieldSessionRecord
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XVR4O24H.js";
|
|
14
15
|
import {
|
|
15
16
|
JUNIOR_THREAD_STATE_TTL_MS
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-XIMUQ4IU.js";
|
|
17
18
|
import {
|
|
18
19
|
addAgentTurnUsage,
|
|
19
20
|
hasAgentTurnUsage
|
|
@@ -3151,6 +3152,7 @@ var PluginMcpClient = class {
|
|
|
3151
3152
|
plugin;
|
|
3152
3153
|
options;
|
|
3153
3154
|
client;
|
|
3155
|
+
clientPromise;
|
|
3154
3156
|
lastAttemptedTransportSessionId;
|
|
3155
3157
|
transport;
|
|
3156
3158
|
listedTools;
|
|
@@ -3227,6 +3229,20 @@ var PluginMcpClient = class {
|
|
|
3227
3229
|
if (this.client) {
|
|
3228
3230
|
return this.client;
|
|
3229
3231
|
}
|
|
3232
|
+
if (this.clientPromise) {
|
|
3233
|
+
return await this.clientPromise;
|
|
3234
|
+
}
|
|
3235
|
+
const clientPromise = this.connectClient();
|
|
3236
|
+
this.clientPromise = clientPromise;
|
|
3237
|
+
try {
|
|
3238
|
+
return await clientPromise;
|
|
3239
|
+
} finally {
|
|
3240
|
+
if (this.clientPromise === clientPromise) {
|
|
3241
|
+
this.clientPromise = void 0;
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
async connectClient() {
|
|
3230
3246
|
const mcp = this.plugin.manifest.mcp;
|
|
3231
3247
|
if (!mcp) {
|
|
3232
3248
|
throw new Error(
|
|
@@ -3289,6 +3305,7 @@ var PluginMcpClient = class {
|
|
|
3289
3305
|
this.listedTools = void 0;
|
|
3290
3306
|
this.transport = void 0;
|
|
3291
3307
|
this.client = void 0;
|
|
3308
|
+
this.clientPromise = void 0;
|
|
3292
3309
|
if (transport) {
|
|
3293
3310
|
await transport.close();
|
|
3294
3311
|
}
|
|
@@ -3337,6 +3354,9 @@ function getMcpAwareTelemetryMessage(error, privacy) {
|
|
|
3337
3354
|
}
|
|
3338
3355
|
|
|
3339
3356
|
// src/chat/mcp/tool-manager.ts
|
|
3357
|
+
var MAX_TOOL_RESULT_TOKENS = 1e4;
|
|
3358
|
+
var MAX_TOOL_RESULT_BYTES = 32 * 1024;
|
|
3359
|
+
var CHARS_PER_ESTIMATED_TOKEN = 4;
|
|
3340
3360
|
function normalizeMcpToolName(provider, toolName) {
|
|
3341
3361
|
return `mcp__${provider}__${toolName}`;
|
|
3342
3362
|
}
|
|
@@ -3407,16 +3427,80 @@ function toAgentToolContent(result) {
|
|
|
3407
3427
|
}
|
|
3408
3428
|
return [{ type: "text", text: "ok" }];
|
|
3409
3429
|
}
|
|
3430
|
+
function utf8Bytes(value) {
|
|
3431
|
+
return Buffer.byteLength(value, "utf8");
|
|
3432
|
+
}
|
|
3433
|
+
function prefixWithin(value, maxChars, maxBytes) {
|
|
3434
|
+
let low = 0;
|
|
3435
|
+
let high = Math.min(value.length, maxChars);
|
|
3436
|
+
while (low < high) {
|
|
3437
|
+
const middle = Math.ceil((low + high) / 2);
|
|
3438
|
+
if (utf8Bytes(value.slice(0, middle)) <= maxBytes) {
|
|
3439
|
+
low = middle;
|
|
3440
|
+
} else {
|
|
3441
|
+
high = middle - 1;
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
if (low > 0 && /[\uD800-\uDBFF]/.test(value[low - 1])) {
|
|
3445
|
+
low -= 1;
|
|
3446
|
+
}
|
|
3447
|
+
return value.slice(0, low);
|
|
3448
|
+
}
|
|
3449
|
+
function suffixWithin(value, maxChars, maxBytes) {
|
|
3450
|
+
let low = Math.max(0, value.length - maxChars);
|
|
3451
|
+
let high = value.length;
|
|
3452
|
+
while (low < high) {
|
|
3453
|
+
const middle = Math.floor((low + high) / 2);
|
|
3454
|
+
if (utf8Bytes(value.slice(middle)) <= maxBytes) {
|
|
3455
|
+
high = middle;
|
|
3456
|
+
} else {
|
|
3457
|
+
low = middle + 1;
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
if (low < value.length && /[\uDC00-\uDFFF]/.test(value[low])) {
|
|
3461
|
+
low += 1;
|
|
3462
|
+
}
|
|
3463
|
+
return value.slice(low);
|
|
3464
|
+
}
|
|
3465
|
+
function boundMcpContent(content) {
|
|
3466
|
+
const text = content.filter((part) => part.type === "text").map((part) => part.text).join("\n\n");
|
|
3467
|
+
const originalBytes = utf8Bytes(text);
|
|
3468
|
+
const originalTokens = Math.ceil(text.length / CHARS_PER_ESTIMATED_TOKEN);
|
|
3469
|
+
if (originalTokens <= MAX_TOOL_RESULT_TOKENS && originalBytes <= MAX_TOOL_RESULT_BYTES) {
|
|
3470
|
+
return content;
|
|
3471
|
+
}
|
|
3472
|
+
const warning = `
|
|
3473
|
+
|
|
3474
|
+
Warning: truncated output (original token count: ${originalTokens}; original bytes: ${originalBytes})
|
|
3475
|
+
|
|
3476
|
+
`;
|
|
3477
|
+
const remainingChars = MAX_TOOL_RESULT_TOKENS * CHARS_PER_ESTIMATED_TOKEN - warning.length;
|
|
3478
|
+
const remainingBytes = MAX_TOOL_RESULT_BYTES - utf8Bytes(warning);
|
|
3479
|
+
const head = prefixWithin(
|
|
3480
|
+
text,
|
|
3481
|
+
Math.ceil(remainingChars / 2),
|
|
3482
|
+
Math.ceil(remainingBytes / 2)
|
|
3483
|
+
);
|
|
3484
|
+
const tail = suffixWithin(
|
|
3485
|
+
text.slice(head.length),
|
|
3486
|
+
remainingChars - head.length,
|
|
3487
|
+
remainingBytes - utf8Bytes(head)
|
|
3488
|
+
);
|
|
3489
|
+
return [
|
|
3490
|
+
{ type: "text", text: `${head}${warning}${tail}` },
|
|
3491
|
+
...content.filter((part) => part.type === "image")
|
|
3492
|
+
];
|
|
3493
|
+
}
|
|
3410
3494
|
function toModelVisibleMcpContent(result) {
|
|
3411
3495
|
const content = toAgentToolContent(result);
|
|
3412
3496
|
if (content.some((part) => part.type === "image")) {
|
|
3413
|
-
return content;
|
|
3497
|
+
return boundMcpContent(content);
|
|
3414
3498
|
}
|
|
3415
3499
|
const structured = summarizeStructuredContent(result.structuredContent);
|
|
3416
3500
|
if (structured) {
|
|
3417
|
-
return [{ type: "text", text: structured }];
|
|
3501
|
+
return boundMcpContent([{ type: "text", text: structured }]);
|
|
3418
3502
|
}
|
|
3419
|
-
return content;
|
|
3503
|
+
return boundMcpContent(content);
|
|
3420
3504
|
}
|
|
3421
3505
|
function describeMcpTool(provider, tool) {
|
|
3422
3506
|
const prefix = `[${provider}]`;
|
|
@@ -3453,6 +3537,7 @@ var McpToolManager = class {
|
|
|
3453
3537
|
activeProviders = /* @__PURE__ */ new Set();
|
|
3454
3538
|
authorizationPendingProviders = /* @__PURE__ */ new Set();
|
|
3455
3539
|
clientsByProvider = /* @__PURE__ */ new Map();
|
|
3540
|
+
clientPromisesByProvider = /* @__PURE__ */ new Map();
|
|
3456
3541
|
toolsByProvider = /* @__PURE__ */ new Map();
|
|
3457
3542
|
getActiveProviders() {
|
|
3458
3543
|
return [...this.activeProviders].sort(
|
|
@@ -3545,6 +3630,21 @@ var McpToolManager = class {
|
|
|
3545
3630
|
if (existing) {
|
|
3546
3631
|
return existing;
|
|
3547
3632
|
}
|
|
3633
|
+
const pending = this.clientPromisesByProvider.get(plugin.manifest.name);
|
|
3634
|
+
if (pending) {
|
|
3635
|
+
return await pending;
|
|
3636
|
+
}
|
|
3637
|
+
const clientPromise = this.createClient(plugin);
|
|
3638
|
+
this.clientPromisesByProvider.set(plugin.manifest.name, clientPromise);
|
|
3639
|
+
try {
|
|
3640
|
+
return await clientPromise;
|
|
3641
|
+
} finally {
|
|
3642
|
+
if (this.clientPromisesByProvider.get(plugin.manifest.name) === clientPromise) {
|
|
3643
|
+
this.clientPromisesByProvider.delete(plugin.manifest.name);
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
async createClient(plugin) {
|
|
3548
3648
|
const authProvider = this.options.authProviderFactory ? await this.options.authProviderFactory(plugin) : void 0;
|
|
3549
3649
|
const client = new PluginMcpClient(plugin, {
|
|
3550
3650
|
...authProvider ? { authProvider } : {},
|
|
@@ -10006,13 +10106,19 @@ function createPluginAuthOrchestration(input) {
|
|
|
10006
10106
|
}
|
|
10007
10107
|
}
|
|
10008
10108
|
if (input.sessionId && recordPendingAuth) {
|
|
10009
|
-
|
|
10109
|
+
const nextPendingAuth = {
|
|
10010
10110
|
kind: "plugin",
|
|
10011
10111
|
provider,
|
|
10012
10112
|
actorId: input.actorId,
|
|
10013
10113
|
...options?.scope ? { scope: options.scope } : {},
|
|
10014
10114
|
sessionId: input.sessionId,
|
|
10015
10115
|
linkSentAtMs: reusingPendingLink ? input.pendingAuth.linkSentAtMs : Date.now()
|
|
10116
|
+
};
|
|
10117
|
+
await recordPendingAuth(nextPendingAuth);
|
|
10118
|
+
await abandonReplacedPendingAuth({
|
|
10119
|
+
conversationId: input.conversationId,
|
|
10120
|
+
previousPendingAuth: input.pendingAuth,
|
|
10121
|
+
nextPendingAuth
|
|
10016
10122
|
});
|
|
10017
10123
|
}
|
|
10018
10124
|
if (input.conversationId && input.sessionId) {
|
|
@@ -12580,9 +12686,9 @@ import { StreamableHTTPClientTransport as StreamableHTTPClientTransport2 } from
|
|
|
12580
12686
|
import {
|
|
12581
12687
|
sourceSchema as sourceSchema2
|
|
12582
12688
|
} from "@sentry/junior-plugin-api";
|
|
12583
|
-
var MCP_AUTH_SESSION_PREFIX = "junior:
|
|
12689
|
+
var MCP_AUTH_SESSION_PREFIX = "junior:mcp_oauth_attempt:v2";
|
|
12584
12690
|
var MCP_AUTH_CREDENTIALS_PREFIX = "junior:mcp_auth_credentials";
|
|
12585
|
-
var MCP_AUTH_SESSION_INDEX_PREFIX = "junior:
|
|
12691
|
+
var MCP_AUTH_SESSION_INDEX_PREFIX = "junior:mcp_oauth_attempt_index:v2";
|
|
12586
12692
|
var MCP_SERVER_SESSION_PREFIX = "junior:mcp_server_session";
|
|
12587
12693
|
var MCP_AUTH_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
12588
12694
|
var MCP_AUTH_CREDENTIALS_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -12624,7 +12730,7 @@ function parseMcpAuthSession(value) {
|
|
|
12624
12730
|
if (!isRecord(parsed)) {
|
|
12625
12731
|
return void 0;
|
|
12626
12732
|
}
|
|
12627
|
-
if (typeof parsed.authSessionId !== "string" || typeof parsed.provider !== "string" || typeof parsed.userId !== "string" || typeof parsed.conversationId !== "string" || typeof parsed.sessionId !== "string" || typeof parsed.userMessage !== "string" || typeof parsed.createdAtMs !== "number" || typeof parsed.updatedAtMs !== "number") {
|
|
12733
|
+
if (parsed.schemaVersion !== 2 || typeof parsed.authSessionId !== "string" || typeof parsed.provider !== "string" || typeof parsed.userId !== "string" || typeof parsed.conversationId !== "string" || typeof parsed.sessionId !== "string" || typeof parsed.userMessage !== "string" || typeof parsed.createdAtMs !== "number" || typeof parsed.updatedAtMs !== "number") {
|
|
12628
12734
|
return void 0;
|
|
12629
12735
|
}
|
|
12630
12736
|
const destination = parsed.destination === void 0 ? void 0 : parseDestination(parsed.destination);
|
|
@@ -12636,6 +12742,7 @@ function parseMcpAuthSession(value) {
|
|
|
12636
12742
|
return void 0;
|
|
12637
12743
|
}
|
|
12638
12744
|
return {
|
|
12745
|
+
schemaVersion: 2,
|
|
12639
12746
|
authSessionId: parsed.authSessionId,
|
|
12640
12747
|
provider: parsed.provider,
|
|
12641
12748
|
userId: parsed.userId,
|
|
@@ -12733,6 +12840,7 @@ async function patchMcpAuthSession(authSessionId, patch) {
|
|
|
12733
12840
|
const next = {
|
|
12734
12841
|
...current,
|
|
12735
12842
|
...patch,
|
|
12843
|
+
schemaVersion: 2,
|
|
12736
12844
|
authSessionId: current.authSessionId,
|
|
12737
12845
|
provider: current.provider,
|
|
12738
12846
|
userId: current.userId,
|
|
@@ -12777,25 +12885,6 @@ async function deleteMcpAuthSessionsForUserProvider(userId, provider) {
|
|
|
12777
12885
|
}
|
|
12778
12886
|
await stateAdapter.delete(indexKey);
|
|
12779
12887
|
}
|
|
12780
|
-
async function getLatestMcpAuthSessionForUserProvider(userId, provider) {
|
|
12781
|
-
const stateAdapter = await getConnectedStateAdapter();
|
|
12782
|
-
const authSessionIds = parseSessionIndex(
|
|
12783
|
-
await stateAdapter.get(sessionIndexKey(userId, provider))
|
|
12784
|
-
);
|
|
12785
|
-
let latestSession;
|
|
12786
|
-
for (const authSessionId of authSessionIds) {
|
|
12787
|
-
const session = parseMcpAuthSession(
|
|
12788
|
-
await stateAdapter.get(sessionKey(authSessionId))
|
|
12789
|
-
);
|
|
12790
|
-
if (!session) {
|
|
12791
|
-
continue;
|
|
12792
|
-
}
|
|
12793
|
-
if (!latestSession || session.updatedAtMs > latestSession.updatedAtMs) {
|
|
12794
|
-
latestSession = session;
|
|
12795
|
-
}
|
|
12796
|
-
}
|
|
12797
|
-
return latestSession;
|
|
12798
|
-
}
|
|
12799
12888
|
async function getMcpStoredOAuthCredentials(userId, provider) {
|
|
12800
12889
|
const stateAdapter = await getConnectedStateAdapter();
|
|
12801
12890
|
return parseStoredCredentials(
|
|
@@ -12854,15 +12943,17 @@ function clientAllowsRedirectUri(clientInformation, callbackUrl) {
|
|
|
12854
12943
|
return redirectUris.includes(callbackUrl);
|
|
12855
12944
|
}
|
|
12856
12945
|
var StateBackedMcpOAuthClientProvider = class {
|
|
12857
|
-
constructor(authSessionId, callbackUrl, sessionContext) {
|
|
12946
|
+
constructor(authSessionId, callbackUrl, sessionContext, runCredentialMutation) {
|
|
12858
12947
|
this.authSessionId = authSessionId;
|
|
12859
12948
|
this.callbackUrl = callbackUrl;
|
|
12860
12949
|
this.sessionContext = sessionContext;
|
|
12950
|
+
this.runCredentialMutation = runCredentialMutation;
|
|
12861
12951
|
this.clientMetadata = createClientMetadata(callbackUrl);
|
|
12862
12952
|
}
|
|
12863
12953
|
authSessionId;
|
|
12864
12954
|
callbackUrl;
|
|
12865
12955
|
sessionContext;
|
|
12956
|
+
runCredentialMutation;
|
|
12866
12957
|
clientMetadata;
|
|
12867
12958
|
get redirectUrl() {
|
|
12868
12959
|
return this.callbackUrl;
|
|
@@ -12886,11 +12977,16 @@ var StateBackedMcpOAuthClientProvider = class {
|
|
|
12886
12977
|
return void 0;
|
|
12887
12978
|
}
|
|
12888
12979
|
async saveClientInformation(clientInformation) {
|
|
12889
|
-
|
|
12890
|
-
|
|
12891
|
-
|
|
12892
|
-
|
|
12893
|
-
|
|
12980
|
+
await this.mutateCredentials(async () => {
|
|
12981
|
+
const session = await this.getCredentialContext();
|
|
12982
|
+
const credentials = await getMcpStoredOAuthCredentials(
|
|
12983
|
+
session.userId,
|
|
12984
|
+
session.provider
|
|
12985
|
+
) ?? {};
|
|
12986
|
+
await putMcpStoredOAuthCredentials(session.userId, session.provider, {
|
|
12987
|
+
...credentials,
|
|
12988
|
+
clientInformation
|
|
12989
|
+
});
|
|
12894
12990
|
});
|
|
12895
12991
|
}
|
|
12896
12992
|
async tokens() {
|
|
@@ -12902,19 +12998,32 @@ var StateBackedMcpOAuthClientProvider = class {
|
|
|
12902
12998
|
return credentials?.tokens;
|
|
12903
12999
|
}
|
|
12904
13000
|
async saveTokens(tokens) {
|
|
12905
|
-
|
|
12906
|
-
|
|
12907
|
-
|
|
12908
|
-
|
|
12909
|
-
|
|
13001
|
+
await this.mutateCredentials(async () => {
|
|
13002
|
+
const session = await this.getCredentialContext();
|
|
13003
|
+
const credentials = await getMcpStoredOAuthCredentials(
|
|
13004
|
+
session.userId,
|
|
13005
|
+
session.provider
|
|
13006
|
+
) ?? {};
|
|
13007
|
+
await putMcpStoredOAuthCredentials(session.userId, session.provider, {
|
|
13008
|
+
...credentials,
|
|
13009
|
+
tokens
|
|
13010
|
+
});
|
|
12910
13011
|
});
|
|
12911
13012
|
}
|
|
12912
13013
|
async redirectToAuthorization(authorizationUrl) {
|
|
13014
|
+
const existing = await getMcpAuthSession(this.authSessionId);
|
|
13015
|
+
if (existing?.authorizationUrl && existing.authorizationUrl !== authorizationUrl.toString()) {
|
|
13016
|
+
throw new Error("MCP OAuth authorization attempt is already initialized");
|
|
13017
|
+
}
|
|
12913
13018
|
await this.ensureSession({
|
|
12914
13019
|
authorizationUrl: authorizationUrl.toString()
|
|
12915
13020
|
});
|
|
12916
13021
|
}
|
|
12917
13022
|
async saveCodeVerifier(codeVerifier) {
|
|
13023
|
+
const existing = await getMcpAuthSession(this.authSessionId);
|
|
13024
|
+
if (existing?.codeVerifier && existing.codeVerifier !== codeVerifier) {
|
|
13025
|
+
throw new Error("MCP OAuth authorization attempt is already initialized");
|
|
13026
|
+
}
|
|
12918
13027
|
await this.ensureSession({ codeVerifier });
|
|
12919
13028
|
}
|
|
12920
13029
|
async codeVerifier() {
|
|
@@ -12925,11 +13034,16 @@ var StateBackedMcpOAuthClientProvider = class {
|
|
|
12925
13034
|
return session.codeVerifier;
|
|
12926
13035
|
}
|
|
12927
13036
|
async saveDiscoveryState(state) {
|
|
12928
|
-
|
|
12929
|
-
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
13037
|
+
await this.mutateCredentials(async () => {
|
|
13038
|
+
const session = await this.getCredentialContext();
|
|
13039
|
+
const credentials = await getMcpStoredOAuthCredentials(
|
|
13040
|
+
session.userId,
|
|
13041
|
+
session.provider
|
|
13042
|
+
) ?? {};
|
|
13043
|
+
await putMcpStoredOAuthCredentials(session.userId, session.provider, {
|
|
13044
|
+
...credentials,
|
|
13045
|
+
discoveryState: state
|
|
13046
|
+
});
|
|
12933
13047
|
});
|
|
12934
13048
|
}
|
|
12935
13049
|
async discoveryState() {
|
|
@@ -12941,34 +13055,36 @@ var StateBackedMcpOAuthClientProvider = class {
|
|
|
12941
13055
|
return credentials?.discoveryState;
|
|
12942
13056
|
}
|
|
12943
13057
|
async invalidateCredentials(scope) {
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
|
|
12949
|
-
|
|
13058
|
+
await this.mutateCredentials(async () => {
|
|
13059
|
+
const session = await this.getCredentialContext();
|
|
13060
|
+
const credentials = await getMcpStoredOAuthCredentials(
|
|
13061
|
+
session.userId,
|
|
13062
|
+
session.provider
|
|
13063
|
+
) ?? {};
|
|
13064
|
+
await putMcpStoredOAuthCredentials(session.userId, session.provider, {
|
|
13065
|
+
...scope === "tokens" || scope === "all" ? {} : credentials.tokens ? { tokens: credentials.tokens } : {},
|
|
13066
|
+
...scope === "client" || scope === "all" ? {} : credentials.clientInformation ? { clientInformation: credentials.clientInformation } : {},
|
|
13067
|
+
...scope === "discovery" || scope === "all" ? {} : credentials.discoveryState ? { discoveryState: credentials.discoveryState } : {}
|
|
13068
|
+
});
|
|
12950
13069
|
});
|
|
12951
|
-
if (scope === "verifier" || scope === "all") {
|
|
12952
|
-
const authSession = await getMcpAuthSession(this.authSessionId);
|
|
12953
|
-
if (authSession) {
|
|
12954
|
-
await patchMcpAuthSession(this.authSessionId, {
|
|
12955
|
-
codeVerifier: void 0,
|
|
12956
|
-
...scope === "all" ? { authorizationUrl: void 0 } : {}
|
|
12957
|
-
});
|
|
12958
|
-
}
|
|
12959
|
-
}
|
|
12960
13070
|
}
|
|
12961
13071
|
async getMcpServerSessionId() {
|
|
12962
13072
|
const session = await this.getCredentialContext();
|
|
12963
13073
|
return await getMcpServerSessionId(session.userId, session.provider);
|
|
12964
13074
|
}
|
|
12965
13075
|
async saveMcpServerSessionId(sessionId) {
|
|
12966
|
-
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
|
|
12970
|
-
|
|
12971
|
-
|
|
13076
|
+
await this.mutateCredentials(async () => {
|
|
13077
|
+
const session = await this.getCredentialContext();
|
|
13078
|
+
if (!sessionId) {
|
|
13079
|
+
await deleteMcpServerSessionId(session.userId, session.provider);
|
|
13080
|
+
return;
|
|
13081
|
+
}
|
|
13082
|
+
await putMcpServerSessionId(session.userId, session.provider, sessionId);
|
|
13083
|
+
});
|
|
13084
|
+
}
|
|
13085
|
+
/** Route shared credential writes through callback-owned freshness control. */
|
|
13086
|
+
async mutateCredentials(mutation) {
|
|
13087
|
+
return this.runCredentialMutation ? await this.runCredentialMutation(mutation) : await mutation();
|
|
12972
13088
|
}
|
|
12973
13089
|
async getCredentialContext() {
|
|
12974
13090
|
return this.sessionContext ?? await this.requireSession();
|
|
@@ -12983,6 +13099,7 @@ var StateBackedMcpOAuthClientProvider = class {
|
|
|
12983
13099
|
}
|
|
12984
13100
|
const now = Date.now();
|
|
12985
13101
|
const nextSession = {
|
|
13102
|
+
schemaVersion: 2,
|
|
12986
13103
|
authSessionId: this.authSessionId,
|
|
12987
13104
|
...this.sessionContext,
|
|
12988
13105
|
...patch,
|
|
@@ -13020,32 +13137,7 @@ async function createMcpOAuthClientProvider(input) {
|
|
|
13020
13137
|
"Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)"
|
|
13021
13138
|
);
|
|
13022
13139
|
}
|
|
13023
|
-
const
|
|
13024
|
-
input.userId,
|
|
13025
|
-
input.provider
|
|
13026
|
-
);
|
|
13027
|
-
const reusableSession = existingSession && existingSession.conversationId === input.conversationId && existingSession.sessionId === input.sessionId ? existingSession : void 0;
|
|
13028
|
-
const now = Date.now();
|
|
13029
|
-
const authSessionId = reusableSession?.authSessionId ?? randomUUID3();
|
|
13030
|
-
await putMcpAuthSession({
|
|
13031
|
-
authSessionId,
|
|
13032
|
-
provider: input.provider,
|
|
13033
|
-
userId: input.userId,
|
|
13034
|
-
conversationId: input.conversationId,
|
|
13035
|
-
...input.destination ? { destination: input.destination } : {},
|
|
13036
|
-
...input.source ? { source: input.source } : {},
|
|
13037
|
-
sessionId: input.sessionId,
|
|
13038
|
-
userMessage: input.userMessage,
|
|
13039
|
-
...input.channelId ? { channelId: input.channelId } : {},
|
|
13040
|
-
...input.threadTs ? { threadTs: input.threadTs } : {},
|
|
13041
|
-
...input.toolChannelId ? { toolChannelId: input.toolChannelId } : {},
|
|
13042
|
-
...input.configuration ? { configuration: input.configuration } : {},
|
|
13043
|
-
...input.artifactState ? { artifactState: input.artifactState } : {},
|
|
13044
|
-
...reusableSession?.authorizationUrl ? { authorizationUrl: reusableSession.authorizationUrl } : {},
|
|
13045
|
-
...reusableSession?.codeVerifier ? { codeVerifier: reusableSession.codeVerifier } : {},
|
|
13046
|
-
createdAtMs: reusableSession?.createdAtMs ?? now,
|
|
13047
|
-
updatedAtMs: now
|
|
13048
|
-
});
|
|
13140
|
+
const authSessionId = randomUUID3();
|
|
13049
13141
|
return new StateBackedMcpOAuthClientProvider(
|
|
13050
13142
|
authSessionId,
|
|
13051
13143
|
`${baseUrl}${getMcpOAuthCallbackPath(input.provider)}`,
|
|
@@ -13054,6 +13146,7 @@ async function createMcpOAuthClientProvider(input) {
|
|
|
13054
13146
|
userId: input.userId,
|
|
13055
13147
|
conversationId: input.conversationId,
|
|
13056
13148
|
...input.destination ? { destination: input.destination } : {},
|
|
13149
|
+
...input.source ? { source: input.source } : {},
|
|
13057
13150
|
sessionId: input.sessionId,
|
|
13058
13151
|
userMessage: input.userMessage,
|
|
13059
13152
|
...input.channelId ? { channelId: input.channelId } : {},
|
|
@@ -13064,7 +13157,7 @@ async function createMcpOAuthClientProvider(input) {
|
|
|
13064
13157
|
}
|
|
13065
13158
|
);
|
|
13066
13159
|
}
|
|
13067
|
-
async function finalizeMcpAuthorization(provider, authSessionId, authorizationCode) {
|
|
13160
|
+
async function finalizeMcpAuthorization(provider, authSessionId, authorizationCode, runCredentialMutation) {
|
|
13068
13161
|
const plugin = requirePluginWithMcp(provider);
|
|
13069
13162
|
const mcp = plugin.manifest.mcp;
|
|
13070
13163
|
if (!mcp) {
|
|
@@ -13088,7 +13181,9 @@ async function finalizeMcpAuthorization(provider, authSessionId, authorizationCo
|
|
|
13088
13181
|
const callbackUrl = `${baseUrl}${getMcpOAuthCallbackPath(provider)}`;
|
|
13089
13182
|
const authProvider = new StateBackedMcpOAuthClientProvider(
|
|
13090
13183
|
authSessionId,
|
|
13091
|
-
callbackUrl
|
|
13184
|
+
callbackUrl,
|
|
13185
|
+
void 0,
|
|
13186
|
+
runCredentialMutation
|
|
13092
13187
|
);
|
|
13093
13188
|
const requestInit = {};
|
|
13094
13189
|
if (mcp.headers && Object.keys(mcp.headers).length > 0) {
|
|
@@ -13171,16 +13266,6 @@ function createMcpAuthOrchestration(input) {
|
|
|
13171
13266
|
`Missing pending auth recorder for MCP authorization pause "${provider}"`
|
|
13172
13267
|
);
|
|
13173
13268
|
}
|
|
13174
|
-
const latestArtifactState = input.getMergedArtifactState();
|
|
13175
|
-
await patchMcpAuthSession(authSessionId, {
|
|
13176
|
-
configuration: { ...input.getConfiguration() },
|
|
13177
|
-
artifactState: latestArtifactState,
|
|
13178
|
-
toolChannelId: input.toolChannelId ?? latestArtifactState.assistantContextChannelId ?? input.channelId
|
|
13179
|
-
});
|
|
13180
|
-
const authSession = await getMcpAuthSession(authSessionId);
|
|
13181
|
-
if (!authSession?.authorizationUrl) {
|
|
13182
|
-
throw new Error(`Missing MCP authorization URL for plugin "${provider}"`);
|
|
13183
|
-
}
|
|
13184
13269
|
const reusingPendingLink = canReusePendingAuthLink({
|
|
13185
13270
|
pendingAuth: input.pendingAuth,
|
|
13186
13271
|
kind: "mcp",
|
|
@@ -13188,8 +13273,31 @@ function createMcpAuthOrchestration(input) {
|
|
|
13188
13273
|
actorId,
|
|
13189
13274
|
sessionId
|
|
13190
13275
|
});
|
|
13276
|
+
const reusedAuthSessionId = reusingPendingLink && input.pendingAuth?.kind === "mcp" ? input.pendingAuth.authSessionId : void 0;
|
|
13277
|
+
const activeAuthSessionId = reusedAuthSessionId ?? authSessionId;
|
|
13278
|
+
const latestArtifactState = input.getMergedArtifactState();
|
|
13279
|
+
await patchMcpAuthSession(activeAuthSessionId, {
|
|
13280
|
+
configuration: { ...input.getConfiguration() },
|
|
13281
|
+
artifactState: latestArtifactState,
|
|
13282
|
+
toolChannelId: input.toolChannelId ?? latestArtifactState.assistantContextChannelId ?? input.channelId
|
|
13283
|
+
});
|
|
13191
13284
|
const providerLabel = formatProviderLabel(provider);
|
|
13285
|
+
const nextPendingAuth = {
|
|
13286
|
+
authSessionId: activeAuthSessionId,
|
|
13287
|
+
kind: "mcp",
|
|
13288
|
+
provider,
|
|
13289
|
+
actorId,
|
|
13290
|
+
sessionId,
|
|
13291
|
+
linkSentAtMs: reusingPendingLink ? input.pendingAuth.linkSentAtMs : Date.now()
|
|
13292
|
+
};
|
|
13192
13293
|
if (!reusingPendingLink) {
|
|
13294
|
+
const authSession = await getMcpAuthSession(authSessionId);
|
|
13295
|
+
if (!authSession?.authorizationUrl) {
|
|
13296
|
+
throw new Error(
|
|
13297
|
+
`Missing MCP authorization URL for plugin "${provider}"`
|
|
13298
|
+
);
|
|
13299
|
+
}
|
|
13300
|
+
await recordPendingAuth(nextPendingAuth);
|
|
13193
13301
|
const delivery = await deliverPrivateMessage({
|
|
13194
13302
|
channelId: authSession.channelId,
|
|
13195
13303
|
threadTs: authSession.threadTs,
|
|
@@ -13201,20 +13309,21 @@ function createMcpAuthOrchestration(input) {
|
|
|
13201
13309
|
})
|
|
13202
13310
|
});
|
|
13203
13311
|
if (!delivery) {
|
|
13312
|
+
await deleteMcpAuthSession(authSessionId);
|
|
13313
|
+
await recordPendingAuth(input.pendingAuth);
|
|
13204
13314
|
throw new Error(
|
|
13205
13315
|
`Unable to deliver MCP authorization link for plugin "${provider}"`
|
|
13206
13316
|
);
|
|
13207
13317
|
}
|
|
13318
|
+
await abandonReplacedPendingAuth({
|
|
13319
|
+
conversationId,
|
|
13320
|
+
previousPendingAuth: input.pendingAuth,
|
|
13321
|
+
nextPendingAuth
|
|
13322
|
+
});
|
|
13208
13323
|
} else {
|
|
13209
13324
|
await deleteMcpAuthSession(authSessionId);
|
|
13325
|
+
await recordPendingAuth(nextPendingAuth);
|
|
13210
13326
|
}
|
|
13211
|
-
await recordPendingAuth({
|
|
13212
|
-
kind: "mcp",
|
|
13213
|
-
provider,
|
|
13214
|
-
actorId,
|
|
13215
|
-
sessionId,
|
|
13216
|
-
linkSentAtMs: reusingPendingLink ? input.pendingAuth.linkSentAtMs : Date.now()
|
|
13217
|
-
});
|
|
13218
13327
|
await recordAuthorizationRequested({
|
|
13219
13328
|
conversationId,
|
|
13220
13329
|
kind: "mcp",
|
|
@@ -16102,6 +16211,7 @@ export {
|
|
|
16102
16211
|
normalizeSandboxEgressTracePropagationDomains,
|
|
16103
16212
|
shouldPropagateSandboxEgressTrace,
|
|
16104
16213
|
resolveSandboxEgressProviderForHost,
|
|
16214
|
+
getMcpAuthSession,
|
|
16105
16215
|
deleteMcpAuthSession,
|
|
16106
16216
|
deleteMcpAuthSessionsForUserProvider,
|
|
16107
16217
|
getMcpStoredOAuthCredentials,
|
|
@@ -31,20 +31,21 @@ function coercePendingAuthState(value) {
|
|
|
31
31
|
const kind = value.kind;
|
|
32
32
|
const provider = toOptionalString(value.provider);
|
|
33
33
|
const actorId = toOptionalString(value.actorId);
|
|
34
|
+
const authSessionId = toOptionalString(value.authSessionId);
|
|
34
35
|
const scope = toOptionalString(value.scope);
|
|
35
36
|
const sessionId = toOptionalString(value.sessionId);
|
|
36
37
|
const linkSentAtMs = toOptionalNumber(value.linkSentAtMs);
|
|
37
|
-
if (kind !== "mcp" && kind !== "plugin" || !provider || !actorId || !sessionId || typeof linkSentAtMs !== "number") {
|
|
38
|
+
if (kind !== "mcp" && kind !== "plugin" || !provider || !actorId || kind === "mcp" && !authSessionId || !sessionId || typeof linkSentAtMs !== "number") {
|
|
38
39
|
return void 0;
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
-
kind,
|
|
41
|
+
const base = {
|
|
42
42
|
provider,
|
|
43
43
|
actorId,
|
|
44
44
|
...scope ? { scope } : {},
|
|
45
45
|
sessionId,
|
|
46
46
|
linkSentAtMs
|
|
47
47
|
};
|
|
48
|
+
return kind === "mcp" ? { ...base, authSessionId, kind } : { ...base, kind };
|
|
48
49
|
}
|
|
49
50
|
function coerceThreadConversationState(value) {
|
|
50
51
|
if (!isRecord(value)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
JUNIOR_THREAD_STATE_TTL_MS,
|
|
3
3
|
buildConversationStatePatch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XIMUQ4IU.js";
|
|
5
5
|
import {
|
|
6
6
|
abandonAgentTurnSessionRecord,
|
|
7
7
|
addAgentTurnUsage,
|
|
@@ -899,13 +899,11 @@ function clearPendingAuth(conversation, sessionId) {
|
|
|
899
899
|
}
|
|
900
900
|
conversation.processing.pendingAuth = void 0;
|
|
901
901
|
}
|
|
902
|
-
async function
|
|
903
|
-
|
|
904
|
-
args.conversation.processing.pendingAuth = args.nextPendingAuth;
|
|
905
|
-
if (previousPendingAuth && previousPendingAuth.sessionId !== args.nextPendingAuth.sessionId && args.conversationId) {
|
|
902
|
+
async function abandonReplacedPendingAuth(args) {
|
|
903
|
+
if (args.previousPendingAuth && args.previousPendingAuth.sessionId !== args.nextPendingAuth.sessionId && args.conversationId) {
|
|
906
904
|
await abandonAgentTurnSessionRecord({
|
|
907
905
|
conversationId: args.conversationId,
|
|
908
|
-
sessionId: previousPendingAuth.sessionId,
|
|
906
|
+
sessionId: args.previousPendingAuth.sessionId,
|
|
909
907
|
errorMessage: "Abandoned by a newer auth-blocked request in the same conversation."
|
|
910
908
|
});
|
|
911
909
|
}
|
|
@@ -951,7 +949,7 @@ export {
|
|
|
951
949
|
canReusePendingAuthLink,
|
|
952
950
|
getConversationPendingAuth,
|
|
953
951
|
clearPendingAuth,
|
|
954
|
-
|
|
952
|
+
abandonReplacedPendingAuth,
|
|
955
953
|
isPendingAuthLatestRequest,
|
|
956
954
|
coerceThreadArtifactsState,
|
|
957
955
|
mergeArtifactsState,
|
package/dist/cli/chat.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createAgentRunner,
|
|
3
3
|
executeAgentRun
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-UWGTSF5O.js";
|
|
5
|
+
import "../chunk-XVR4O24H.js";
|
|
6
|
+
import "../chunk-XIMUQ4IU.js";
|
|
7
7
|
import "../chunk-IVXL57YF.js";
|
|
8
8
|
import "../chunk-IQIBZXGB.js";
|
|
9
9
|
import "../chunk-JPQISMMJ.js";
|
|
@@ -217,7 +217,7 @@ function newRunConversationId() {
|
|
|
217
217
|
async function prepareLocalChatRun(io, pluginSet) {
|
|
218
218
|
defaultStateAdapterForLocalChat();
|
|
219
219
|
await configureLocalChatPlugins(pluginSet);
|
|
220
|
-
const { runLocalAgentTurn } = await import("../runner-
|
|
220
|
+
const { runLocalAgentTurn } = await import("../runner-CZIKSWGC.js");
|
|
221
221
|
const deps = {
|
|
222
222
|
agentRunner: createAgentRunner(executeAgentRun),
|
|
223
223
|
deliverReply: async (reply) => {
|