@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.
Files changed (80) hide show
  1. package/README.md +0 -1
  2. package/dist/{agent-hooks-V6KU7PQN.js → agent-hooks-I4I2DHSW.js} +7 -7
  3. package/dist/api/conversations/schema.d.ts +2 -2
  4. package/dist/api/people/schema.d.ts +13 -0
  5. package/dist/api/schema.d.ts +1 -1
  6. package/dist/api/schema.js +3 -3
  7. package/dist/api.js +16 -16
  8. package/dist/app.js +165 -104
  9. package/dist/{catalog-runtime-PFHVMHDR.js → catalog-runtime-5CVM2DOF.js} +2 -2
  10. package/dist/chat/agent/prompt.d.ts +1 -1
  11. package/dist/chat/agent/request.d.ts +1 -1
  12. package/dist/chat/agent-dispatch/validation.d.ts +1 -1
  13. package/dist/chat/conversation-privacy.d.ts +2 -6
  14. package/dist/chat/conversations/store.d.ts +1 -1
  15. package/dist/chat/credentials/context.d.ts +33 -6
  16. package/dist/chat/credentials/subject.d.ts +15 -1
  17. package/dist/chat/logging.d.ts +4 -2
  18. package/dist/chat/mcp/auth-store.d.ts +1 -0
  19. package/dist/chat/mcp/client.d.ts +2 -0
  20. package/dist/chat/mcp/oauth-provider.d.ts +4 -1
  21. package/dist/chat/mcp/oauth.d.ts +3 -1
  22. package/dist/chat/mcp/tool-manager.d.ts +3 -1
  23. package/dist/chat/sandbox/egress/schemas.d.ts +13 -2
  24. package/dist/chat/services/context-compaction-marker.d.ts +8 -0
  25. package/dist/chat/services/mcp-auth-orchestration.d.ts +1 -1
  26. package/dist/chat/services/pending-auth.d.ts +17 -9
  27. package/dist/chat/state/conversation.d.ts +7 -3
  28. package/dist/{chunk-XJA7BPHS.js → chunk-3OABPOHR.js} +3 -3
  29. package/dist/{chunk-2T7DCRAW.js → chunk-3UK5DFKW.js} +3 -3
  30. package/dist/{chunk-IDZBM3NW.js → chunk-4YN2ZXKB.js} +10 -2
  31. package/dist/{chunk-NSOCZGOH.js → chunk-5K4N73TP.js} +9 -11
  32. package/dist/{chunk-LMJPRYHP.js → chunk-77LHNQK4.js} +32 -8
  33. package/dist/{chunk-I35CTGPO.js → chunk-AEWZ7F65.js} +41 -17
  34. package/dist/{chunk-IQIBZXGB.js → chunk-B5QS4AVO.js} +2 -2
  35. package/dist/{chunk-XSBIISXS.js → chunk-DTUSCR2Y.js} +9 -12
  36. package/dist/{chunk-GEUUJRQF.js → chunk-E4EMFKGB.js} +1 -1
  37. package/dist/{chunk-VVIXK2BX.js → chunk-EMUZSROX.js} +2 -2
  38. package/dist/{chunk-IVXL57YF.js → chunk-EOB77KME.js} +4 -4
  39. package/dist/{chunk-PGGEOCQY.js → chunk-F4CQEUTP.js} +1 -1
  40. package/dist/{chunk-4AQUWWEM.js → chunk-HNIT4HXU.js} +1 -1
  41. package/dist/{chunk-MM5UFDAC.js → chunk-HYDQULR2.js} +1 -1
  42. package/dist/{chunk-FP5N5OWZ.js → chunk-IQ36I3DF.js} +2 -2
  43. package/dist/{chunk-JSAANELJ.js → chunk-LJB2TLVT.js} +3 -3
  44. package/dist/{chunk-D5KZYS4T.js → chunk-MJSJAHBW.js} +1 -1
  45. package/dist/{chunk-QSBQJ3PA.js → chunk-MR6H67P2.js} +3 -3
  46. package/dist/{chunk-VY7BT4SM.js → chunk-NSP6OGL2.js} +9 -8
  47. package/dist/{chunk-VHRM6GNH.js → chunk-QZGVPPIJ.js} +27 -3
  48. package/dist/{chunk-LVA4I4H7.js → chunk-RT5BUHR5.js} +15 -44
  49. package/dist/{chunk-A7X2FDUO.js → chunk-SHBPSE7A.js} +88 -66
  50. package/dist/{chunk-CM5EZD5F.js → chunk-UIE3R5XU.js} +1 -1
  51. package/dist/{chunk-JPQISMMJ.js → chunk-VSAFV2GI.js} +7 -6
  52. package/dist/{chunk-3ECW2K2O.js → chunk-WR7H7VLJ.js} +2 -2
  53. package/dist/{chunk-TPTJEHUE.js → chunk-X2IPNCB5.js} +61 -25
  54. package/dist/{chunk-6DTVCPLO.js → chunk-XIMUQ4IU.js} +4 -3
  55. package/dist/{chunk-45DMFMY2.js → chunk-ZIX4PNBI.js} +348 -200
  56. package/dist/{chunk-PWC24W5F.js → chunk-ZSHL44IQ.js} +2 -2
  57. package/dist/cli/chat.js +22 -22
  58. package/dist/cli/check.js +3 -3
  59. package/dist/cli/plugins.js +9 -9
  60. package/dist/cli/snapshot-warmup.js +5 -5
  61. package/dist/cli/upgrade.js +203 -14
  62. package/dist/db/postgres-json.d.ts +5 -0
  63. package/dist/{db-RCZB7KNM.js → db-6QP6HY7U.js} +4 -4
  64. package/dist/{detail-LU6COZO6.js → detail-OEIVZYXS.js} +12 -12
  65. package/dist/{detail-5SLCGT6J.js → detail-U6IP2Z4N.js} +8 -8
  66. package/dist/instrumentation.js +2 -2
  67. package/dist/{legacy-import-VCYLWT2V.js → legacy-import-R3BMM2GH.js} +5 -5
  68. package/dist/{list-KHRAWZWU.js → list-AJ6RWBOG.js} +8 -8
  69. package/dist/list-UMZKA5AI.js +121 -0
  70. package/dist/{list-4ALSU6ZW.js → list-Z3CC52CZ.js} +8 -8
  71. package/dist/{plugin-conversations-JANXC4GA.js → plugin-conversations-F3IBVNFX.js} +7 -7
  72. package/dist/{profile-3O3OVENT.js → profile-CQMPFKED.js} +8 -8
  73. package/dist/{runner-BM7D35YW.js → runner-C2ZTIOUD.js} +13 -13
  74. package/dist/{skills-MAZXZ2KE.js → skills-722AXRV5.js} +3 -3
  75. package/dist/{stats-J3YGCYDF.js → stats-ZYFQFCTL.js} +6 -6
  76. package/dist/{subagent-P7HOSMVC.js → subagent-X3ZWJHR4.js} +11 -11
  77. package/dist/{validation-FMEAEKCY.js → validation-EUI2UFRM.js} +3 -3
  78. package/package.json +6 -6
  79. package/dist/api-reference.d.ts +0 -14
  80. package/dist/list-2FI5SFV7.js +0 -80
@@ -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,14 +11,14 @@ import {
10
11
  persistRunningSessionRecord,
11
12
  persistTimeoutSessionRecord,
12
13
  persistYieldSessionRecord
13
- } from "./chunk-NSOCZGOH.js";
14
+ } from "./chunk-5K4N73TP.js";
14
15
  import {
15
16
  JUNIOR_THREAD_STATE_TTL_MS
16
- } from "./chunk-6DTVCPLO.js";
17
+ } from "./chunk-XIMUQ4IU.js";
17
18
  import {
18
19
  addAgentTurnUsage,
19
20
  hasAgentTurnUsage
20
- } from "./chunk-IVXL57YF.js";
21
+ } from "./chunk-EOB77KME.js";
21
22
  import {
22
23
  loadConnectedMcpProviders,
23
24
  loadConversationProjection,
@@ -25,12 +26,12 @@ import {
25
26
  recordAuthorizationRequested,
26
27
  recordMcpProviderConnected,
27
28
  recordToolExecutionStarted
28
- } from "./chunk-IQIBZXGB.js";
29
+ } from "./chunk-B5QS4AVO.js";
29
30
  import {
30
31
  estimateTextTokens,
31
32
  getAgentContextCompactionTriggerTokens,
32
33
  updateConversationStats
33
- } from "./chunk-JPQISMMJ.js";
34
+ } from "./chunk-VSAFV2GI.js";
34
35
  import {
35
36
  buildNonInteractiveShellScript,
36
37
  createSandboxInstance,
@@ -40,10 +41,10 @@ import {
40
41
  isSnapshotMissingError,
41
42
  resolveRuntimeDependencySnapshot,
42
43
  runNonInteractiveCommand
43
- } from "./chunk-XJA7BPHS.js";
44
+ } from "./chunk-3OABPOHR.js";
44
45
  import {
45
46
  privateTraceResultAttributes
46
- } from "./chunk-CM5EZD5F.js";
47
+ } from "./chunk-UIE3R5XU.js";
47
48
  import {
48
49
  createPluginHookRunner,
49
50
  getPluginSystemPromptContributions,
@@ -52,7 +53,7 @@ import {
52
53
  getPlugins,
53
54
  getSlackToolContext,
54
55
  resolveChannelCapabilities
55
- } from "./chunk-TPTJEHUE.js";
56
+ } from "./chunk-X2IPNCB5.js";
56
57
  import {
57
58
  SlackActionError,
58
59
  downloadPrivateSlackFile,
@@ -62,10 +63,10 @@ import {
62
63
  isDmChannel,
63
64
  normalizeSlackConversationId,
64
65
  withSlackRetries
65
- } from "./chunk-FP5N5OWZ.js";
66
+ } from "./chunk-IQ36I3DF.js";
66
67
  import {
67
68
  createPluginLogger
68
- } from "./chunk-PWC24W5F.js";
69
+ } from "./chunk-ZSHL44IQ.js";
69
70
  import {
70
71
  contextProvenance,
71
72
  getAgentStepStore,
@@ -74,7 +75,7 @@ import {
74
75
  getDb,
75
76
  instructionActors,
76
77
  instructionProvenanceFor
77
- } from "./chunk-VHRM6GNH.js";
78
+ } from "./chunk-QZGVPPIJ.js";
78
79
  import {
79
80
  SANDBOX_DATA_ROOT,
80
81
  SANDBOX_SKILLS_ROOT,
@@ -86,11 +87,13 @@ import {
86
87
  sleep
87
88
  } from "./chunk-4ZNGQH7C.js";
88
89
  import {
90
+ COMPACTION_SUMMARY_PREFIX,
89
91
  DEFAULT_HANDOFF_MODEL_PROFILE,
90
92
  GEN_AI_PROVIDER_NAME,
91
93
  GEN_AI_SERVER_ADDRESS,
92
94
  GEN_AI_SERVER_PORT,
93
95
  MISSING_GATEWAY_CREDENTIALS_ERROR,
96
+ MODEL_HANDOFF_SUMMARY_PREFIX,
94
97
  ModelProfileNotConfiguredError,
95
98
  STANDARD_MODEL_PROFILE,
96
99
  TURN_CONTEXT_TAG,
@@ -105,8 +108,10 @@ import {
105
108
  getPiGatewayApiKey,
106
109
  getStateAdapter,
107
110
  getTerminalAssistantMessages,
111
+ hasCompactedConversationContext,
108
112
  hasRuntimeTurnContext,
109
113
  isAssistantMessage,
114
+ isCompactionSummaryText,
110
115
  isProviderRetryError,
111
116
  isToolResultError,
112
117
  isToolResultMessage,
@@ -120,19 +125,17 @@ import {
120
125
  stripRuntimeTurnContext,
121
126
  trimTrailingAssistantMessages,
122
127
  unwrapCurrentInstruction
123
- } from "./chunk-A7X2FDUO.js";
128
+ } from "./chunk-SHBPSE7A.js";
124
129
  import {
125
130
  parseSlackThreadId,
126
131
  resolveConversationPrivacy,
127
132
  runWithConversationPrivacy,
128
133
  toCanonicalInputMessage,
129
134
  toCanonicalOutputMessage,
130
- toGenAiMessageMetadata,
131
135
  toGenAiMessagesTraceAttributes,
132
136
  toGenAiPayloadMetadata,
133
- toGenAiPayloadTraceAttributes,
134
- toGenAiTextMetadata
135
- } from "./chunk-LVA4I4H7.js";
137
+ toGenAiPayloadTraceAttributes
138
+ } from "./chunk-RT5BUHR5.js";
136
139
  import {
137
140
  parseDestination
138
141
  } from "./chunk-B7PUBQQM.js";
@@ -141,19 +144,19 @@ import {
141
144
  findSkillByName,
142
145
  loadSkillsByName,
143
146
  parseSkillInvocation
144
- } from "./chunk-3ECW2K2O.js";
147
+ } from "./chunk-WR7H7VLJ.js";
145
148
  import {
146
149
  CredentialUnavailableError,
147
150
  credentialContextSchema,
148
151
  pluginCatalogRuntime,
149
152
  resolveAuthTokenPlaceholder,
150
153
  resolvePluginCommandEnv
151
- } from "./chunk-LMJPRYHP.js";
154
+ } from "./chunk-77LHNQK4.js";
152
155
  import {
153
156
  createActor,
154
157
  extractGenAiUsageAttributes,
155
158
  extractGenAiUsageSummary,
156
- getLogContextAttributes,
159
+ getLogContextAttributesForSpan,
157
160
  getTracePropagationHeaders,
158
161
  isUserActor,
159
162
  logError,
@@ -167,7 +170,7 @@ import {
167
170
  setTags,
168
171
  summarizeMessageText,
169
172
  withSpan
170
- } from "./chunk-I35CTGPO.js";
173
+ } from "./chunk-AEWZ7F65.js";
171
174
  import {
172
175
  isRecord
173
176
  } from "./chunk-OB42YVAE.js";
@@ -475,7 +478,7 @@ import {
475
478
  function attributeModeForPrivacy(conversationPrivacy) {
476
479
  return conversationPrivacy === "public" ? "content" : "metadata";
477
480
  }
478
- function buildChatStartAttributes(model, context, mode, conversationPrivacy) {
481
+ function buildChatStartAttributes(model, context, options, mode, conversationPrivacy) {
479
482
  const attributes = {
480
483
  "gen_ai.operation.name": "chat",
481
484
  "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
@@ -484,35 +487,45 @@ function buildChatStartAttributes(model, context, mode, conversationPrivacy) {
484
487
  "gen_ai.output.type": "text",
485
488
  "server.address": GEN_AI_SERVER_ADDRESS,
486
489
  "server.port": GEN_AI_SERVER_PORT,
490
+ ...options?.temperature !== void 0 ? { "gen_ai.request.temperature": options.temperature } : {},
491
+ ...options?.maxTokens !== void 0 ? { "gen_ai.request.max_tokens": options.maxTokens } : {},
492
+ ...options?.reasoning ? { "gen_ai.request.reasoning.level": options.reasoning } : {},
493
+ ...hasCompactedConversationContext(context.messages) ? { "gen_ai.conversation.compacted": true } : {},
487
494
  ...conversationPrivacy ? { "app.conversation.privacy": conversationPrivacy } : {},
488
- ...toGenAiMessagesTraceAttributes("app.ai.input", context.messages)
495
+ ...toGenAiMessagesTraceAttributes("gen_ai.input", context.messages)
489
496
  };
490
- const inputMessages = serializeGenAiAttribute(
491
- mode === "metadata" ? context.messages.map(toGenAiMessageMetadata) : context.messages.map(toCanonicalInputMessage)
492
- );
493
- if (inputMessages) {
494
- attributes["gen_ai.input.messages"] = inputMessages;
497
+ if (mode === "content") {
498
+ const inputMessages = serializeGenAiAttribute(
499
+ context.messages.map(toCanonicalInputMessage)
500
+ );
501
+ if (inputMessages) {
502
+ attributes["gen_ai.input.messages"] = inputMessages;
503
+ }
495
504
  }
496
505
  if (context.systemPrompt) {
497
- const systemInstructions = serializeGenAiAttribute([
498
- mode === "metadata" ? toGenAiTextMetadata(context.systemPrompt) : { type: "text", content: context.systemPrompt }
499
- ]);
500
- if (systemInstructions) {
501
- attributes["gen_ai.system_instructions"] = systemInstructions;
506
+ if (mode === "content") {
507
+ const systemInstructions = serializeGenAiAttribute([
508
+ { type: "text", content: context.systemPrompt }
509
+ ]);
510
+ if (systemInstructions) {
511
+ attributes["gen_ai.system_instructions"] = systemInstructions;
512
+ }
502
513
  }
503
- attributes["app.ai.system_instructions.content_chars"] = context.systemPrompt.length;
514
+ attributes["gen_ai.system_instructions.content_chars"] = context.systemPrompt.length;
504
515
  }
505
516
  return attributes;
506
517
  }
507
518
  function buildChatEndAttributes(message, mode) {
508
519
  const attributes = {
509
- ...toGenAiMessagesTraceAttributes("app.ai.output", [message])
520
+ ...toGenAiMessagesTraceAttributes("gen_ai.output", [message])
510
521
  };
511
- const outputMessages = serializeGenAiAttribute(
512
- mode === "metadata" ? [toGenAiMessageMetadata(message)] : [toCanonicalOutputMessage(message)]
513
- );
514
- if (outputMessages) {
515
- attributes["gen_ai.output.messages"] = outputMessages;
522
+ if (mode === "content") {
523
+ const outputMessages = serializeGenAiAttribute([
524
+ toCanonicalOutputMessage(message)
525
+ ]);
526
+ if (outputMessages) {
527
+ attributes["gen_ai.output.messages"] = outputMessages;
528
+ }
516
529
  }
517
530
  Object.assign(attributes, extractGenAiUsageAttributes(message));
518
531
  if (message.stopReason) {
@@ -537,8 +550,14 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
537
550
  name: `chat ${model.id}`,
538
551
  op: "gen_ai.chat",
539
552
  attributes: {
540
- ...getLogContextAttributes(),
541
- ...buildChatStartAttributes(model, context, mode, effectivePrivacy)
553
+ ...getLogContextAttributesForSpan("gen_ai.chat"),
554
+ ...buildChatStartAttributes(
555
+ model,
556
+ context,
557
+ options,
558
+ mode,
559
+ effectivePrivacy
560
+ )
542
561
  }
543
562
  });
544
563
  try {
@@ -554,11 +573,19 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
554
573
  )) {
555
574
  span.setAttribute(key, value);
556
575
  }
576
+ if (finalMessage.stopReason === "error") {
577
+ span.setAttribute("error.type", "provider_error");
578
+ span.setStatus({ code: 2, message: "LLM stream failed" });
579
+ }
557
580
  } finally {
558
581
  span.end();
559
582
  }
560
583
  },
561
- () => {
584
+ (error) => {
585
+ span.setAttribute(
586
+ "error.type",
587
+ error instanceof Error ? error.name : typeof error
588
+ );
562
589
  span.setStatus({ code: 2, message: "LLM stream failed" });
563
590
  span.end();
564
591
  }
@@ -566,6 +593,10 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
566
593
  });
567
594
  return stream;
568
595
  } catch (error) {
596
+ span.setAttribute(
597
+ "error.type",
598
+ error instanceof Error ? error.name : typeof error
599
+ );
569
600
  span.setStatus({ code: 2, message: "LLM call failed" });
570
601
  span.end();
571
602
  throw error;
@@ -998,10 +1029,10 @@ async function selectTurnReasoningLevel(args) {
998
1029
  minimum: trimmedContext || turnBlockCount > 0 ? "medium" : void 0
999
1030
  });
1000
1031
  setSpanAttributes({
1001
- "app.ai.reasoning_level": normalizedSelection.reasoningLevel,
1002
- "app.ai.reasoning_level_reason": normalizedSelection.reason,
1032
+ "gen_ai.request.reasoning.level": normalizedSelection.reasoningLevel,
1033
+ "gen_ai.request.reasoning.level_reason": normalizedSelection.reason,
1003
1034
  ...normalizedSelection.confidence !== void 0 ? {
1004
- "app.ai.reasoning_level_confidence": normalizedSelection.confidence
1035
+ "gen_ai.request.reasoning.level_confidence": normalizedSelection.confidence
1005
1036
  } : {}
1006
1037
  });
1007
1038
  return normalizedSelection;
@@ -2621,7 +2652,18 @@ async function assemblePrompt(args) {
2621
2652
  }
2622
2653
  ];
2623
2654
  const inputMessagesAttribute = serializeGenAiAttribute(
2624
- args.conversationPrivacy !== "public" ? inputMessages.map(toGenAiMessageMetadata) : inputMessages
2655
+ args.conversationPrivacy === "public" ? [
2656
+ {
2657
+ role: "system",
2658
+ parts: [{ type: "text", content: baseInstructions }]
2659
+ },
2660
+ {
2661
+ role: "user",
2662
+ parts: promptContentParts.flatMap(
2663
+ (part) => part.type === "text" ? [{ type: "text", content: part.text }] : []
2664
+ )
2665
+ }
2666
+ ] : void 0
2625
2667
  );
2626
2668
  return {
2627
2669
  baseInstructions,
@@ -3151,6 +3193,7 @@ var PluginMcpClient = class {
3151
3193
  plugin;
3152
3194
  options;
3153
3195
  client;
3196
+ clientPromise;
3154
3197
  lastAttemptedTransportSessionId;
3155
3198
  transport;
3156
3199
  listedTools;
@@ -3227,6 +3270,20 @@ var PluginMcpClient = class {
3227
3270
  if (this.client) {
3228
3271
  return this.client;
3229
3272
  }
3273
+ if (this.clientPromise) {
3274
+ return await this.clientPromise;
3275
+ }
3276
+ const clientPromise = this.connectClient();
3277
+ this.clientPromise = clientPromise;
3278
+ try {
3279
+ return await clientPromise;
3280
+ } finally {
3281
+ if (this.clientPromise === clientPromise) {
3282
+ this.clientPromise = void 0;
3283
+ }
3284
+ }
3285
+ }
3286
+ async connectClient() {
3230
3287
  const mcp = this.plugin.manifest.mcp;
3231
3288
  if (!mcp) {
3232
3289
  throw new Error(
@@ -3289,6 +3346,7 @@ var PluginMcpClient = class {
3289
3346
  this.listedTools = void 0;
3290
3347
  this.transport = void 0;
3291
3348
  this.client = void 0;
3349
+ this.clientPromise = void 0;
3292
3350
  if (transport) {
3293
3351
  await transport.close();
3294
3352
  }
@@ -3337,6 +3395,9 @@ function getMcpAwareTelemetryMessage(error, privacy) {
3337
3395
  }
3338
3396
 
3339
3397
  // src/chat/mcp/tool-manager.ts
3398
+ var MAX_TOOL_RESULT_TOKENS = 1e4;
3399
+ var MAX_TOOL_RESULT_BYTES = 32 * 1024;
3400
+ var CHARS_PER_ESTIMATED_TOKEN = 4;
3340
3401
  function normalizeMcpToolName(provider, toolName) {
3341
3402
  return `mcp__${provider}__${toolName}`;
3342
3403
  }
@@ -3407,16 +3468,80 @@ function toAgentToolContent(result) {
3407
3468
  }
3408
3469
  return [{ type: "text", text: "ok" }];
3409
3470
  }
3471
+ function utf8Bytes(value) {
3472
+ return Buffer.byteLength(value, "utf8");
3473
+ }
3474
+ function prefixWithin(value, maxChars, maxBytes) {
3475
+ let low = 0;
3476
+ let high = Math.min(value.length, maxChars);
3477
+ while (low < high) {
3478
+ const middle = Math.ceil((low + high) / 2);
3479
+ if (utf8Bytes(value.slice(0, middle)) <= maxBytes) {
3480
+ low = middle;
3481
+ } else {
3482
+ high = middle - 1;
3483
+ }
3484
+ }
3485
+ if (low > 0 && /[\uD800-\uDBFF]/.test(value[low - 1])) {
3486
+ low -= 1;
3487
+ }
3488
+ return value.slice(0, low);
3489
+ }
3490
+ function suffixWithin(value, maxChars, maxBytes) {
3491
+ let low = Math.max(0, value.length - maxChars);
3492
+ let high = value.length;
3493
+ while (low < high) {
3494
+ const middle = Math.floor((low + high) / 2);
3495
+ if (utf8Bytes(value.slice(middle)) <= maxBytes) {
3496
+ high = middle;
3497
+ } else {
3498
+ low = middle + 1;
3499
+ }
3500
+ }
3501
+ if (low < value.length && /[\uDC00-\uDFFF]/.test(value[low])) {
3502
+ low += 1;
3503
+ }
3504
+ return value.slice(low);
3505
+ }
3506
+ function boundMcpContent(content) {
3507
+ const text = content.filter((part) => part.type === "text").map((part) => part.text).join("\n\n");
3508
+ const originalBytes = utf8Bytes(text);
3509
+ const originalTokens = Math.ceil(text.length / CHARS_PER_ESTIMATED_TOKEN);
3510
+ if (originalTokens <= MAX_TOOL_RESULT_TOKENS && originalBytes <= MAX_TOOL_RESULT_BYTES) {
3511
+ return content;
3512
+ }
3513
+ const warning = `
3514
+
3515
+ Warning: truncated output (original token count: ${originalTokens}; original bytes: ${originalBytes})
3516
+
3517
+ `;
3518
+ const remainingChars = MAX_TOOL_RESULT_TOKENS * CHARS_PER_ESTIMATED_TOKEN - warning.length;
3519
+ const remainingBytes = MAX_TOOL_RESULT_BYTES - utf8Bytes(warning);
3520
+ const head = prefixWithin(
3521
+ text,
3522
+ Math.ceil(remainingChars / 2),
3523
+ Math.ceil(remainingBytes / 2)
3524
+ );
3525
+ const tail = suffixWithin(
3526
+ text.slice(head.length),
3527
+ remainingChars - head.length,
3528
+ remainingBytes - utf8Bytes(head)
3529
+ );
3530
+ return [
3531
+ { type: "text", text: `${head}${warning}${tail}` },
3532
+ ...content.filter((part) => part.type === "image")
3533
+ ];
3534
+ }
3410
3535
  function toModelVisibleMcpContent(result) {
3411
3536
  const content = toAgentToolContent(result);
3412
3537
  if (content.some((part) => part.type === "image")) {
3413
- return content;
3538
+ return boundMcpContent(content);
3414
3539
  }
3415
3540
  const structured = summarizeStructuredContent(result.structuredContent);
3416
3541
  if (structured) {
3417
- return [{ type: "text", text: structured }];
3542
+ return boundMcpContent([{ type: "text", text: structured }]);
3418
3543
  }
3419
- return content;
3544
+ return boundMcpContent(content);
3420
3545
  }
3421
3546
  function describeMcpTool(provider, tool) {
3422
3547
  const prefix = `[${provider}]`;
@@ -3453,6 +3578,7 @@ var McpToolManager = class {
3453
3578
  activeProviders = /* @__PURE__ */ new Set();
3454
3579
  authorizationPendingProviders = /* @__PURE__ */ new Set();
3455
3580
  clientsByProvider = /* @__PURE__ */ new Map();
3581
+ clientPromisesByProvider = /* @__PURE__ */ new Map();
3456
3582
  toolsByProvider = /* @__PURE__ */ new Map();
3457
3583
  getActiveProviders() {
3458
3584
  return [...this.activeProviders].sort(
@@ -3545,6 +3671,21 @@ var McpToolManager = class {
3545
3671
  if (existing) {
3546
3672
  return existing;
3547
3673
  }
3674
+ const pending = this.clientPromisesByProvider.get(plugin.manifest.name);
3675
+ if (pending) {
3676
+ return await pending;
3677
+ }
3678
+ const clientPromise = this.createClient(plugin);
3679
+ this.clientPromisesByProvider.set(plugin.manifest.name, clientPromise);
3680
+ try {
3681
+ return await clientPromise;
3682
+ } finally {
3683
+ if (this.clientPromisesByProvider.get(plugin.manifest.name) === clientPromise) {
3684
+ this.clientPromisesByProvider.delete(plugin.manifest.name);
3685
+ }
3686
+ }
3687
+ }
3688
+ async createClient(plugin) {
3548
3689
  const authProvider = this.options.authProviderFactory ? await this.options.authProviderFactory(plugin) : void 0;
3549
3690
  const client = new PluginMcpClient(plugin, {
3550
3691
  ...authProvider ? { authProvider } : {},
@@ -3580,13 +3721,14 @@ var McpToolManager = class {
3580
3721
  plugin.manifest.name,
3581
3722
  tool
3582
3723
  ),
3583
- "gen_ai.tool.type": "extension",
3724
+ "gen_ai.tool.type": "function",
3584
3725
  "app.plugin.name": plugin.manifest.name,
3585
3726
  ...options?.toolCallId ? { "gen_ai.tool.call.id": options.toolCallId } : {}
3586
3727
  };
3587
3728
  const argumentAttribute = serializeMcpPayload(
3588
3729
  resolvedArgs,
3589
- conversationPrivacy
3730
+ conversationPrivacy,
3731
+ { privateMetadata: true }
3590
3732
  );
3591
3733
  return await withSpan(
3592
3734
  `execute_tool ${managedToolName}`,
@@ -3600,7 +3742,8 @@ var McpToolManager = class {
3600
3742
  }
3601
3743
  const resultAttribute = serializeMcpPayload(
3602
3744
  result,
3603
- conversationPrivacy
3745
+ conversationPrivacy,
3746
+ { privateMetadata: true }
3604
3747
  );
3605
3748
  if (resultAttribute) {
3606
3749
  setSpanAttributes({
@@ -3691,10 +3834,11 @@ var McpToolManager = class {
3691
3834
  function toOptionalRecord(value) {
3692
3835
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3693
3836
  }
3694
- function serializeMcpPayload(payload, privacy) {
3695
- return serializeGenAiAttribute(
3696
- privacy === "private" ? toGenAiPayloadMetadata(payload) : payload
3697
- );
3837
+ function serializeMcpPayload(payload, privacy, options = {}) {
3838
+ if (privacy !== "private") {
3839
+ return serializeGenAiAttribute(payload);
3840
+ }
3841
+ return options.privateMetadata ? serializeGenAiAttribute(toGenAiPayloadMetadata(payload)) : void 0;
3698
3842
  }
3699
3843
 
3700
3844
  // src/chat/tools/sandbox/bash.ts
@@ -10006,13 +10150,19 @@ function createPluginAuthOrchestration(input) {
10006
10150
  }
10007
10151
  }
10008
10152
  if (input.sessionId && recordPendingAuth) {
10009
- await recordPendingAuth({
10153
+ const nextPendingAuth = {
10010
10154
  kind: "plugin",
10011
10155
  provider,
10012
10156
  actorId: input.actorId,
10013
10157
  ...options?.scope ? { scope: options.scope } : {},
10014
10158
  sessionId: input.sessionId,
10015
10159
  linkSentAtMs: reusingPendingLink ? input.pendingAuth.linkSentAtMs : Date.now()
10160
+ };
10161
+ await recordPendingAuth(nextPendingAuth);
10162
+ await abandonReplacedPendingAuth({
10163
+ conversationId: input.conversationId,
10164
+ previousPendingAuth: input.pendingAuth,
10165
+ nextPendingAuth
10016
10166
  });
10017
10167
  }
10018
10168
  if (input.conversationId && input.sessionId) {
@@ -10122,7 +10272,6 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
10122
10272
  traceContext,
10123
10273
  {
10124
10274
  "app.credential.provider": error.provider,
10125
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
10126
10275
  "gen_ai.operation.name": "execute_tool",
10127
10276
  "gen_ai.tool.name": toolName,
10128
10277
  ...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
@@ -10138,7 +10287,6 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
10138
10287
  "agent_tool_call_failed",
10139
10288
  traceContext,
10140
10289
  {
10141
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
10142
10290
  "gen_ai.operation.name": "execute_tool",
10143
10291
  "gen_ai.tool.name": toolName,
10144
10292
  ...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
@@ -10155,7 +10303,6 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
10155
10303
  "agent_tool_call_failed",
10156
10304
  {},
10157
10305
  {
10158
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
10159
10306
  "gen_ai.operation.name": "execute_tool",
10160
10307
  "gen_ai.tool.name": toolName,
10161
10308
  ...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
@@ -10523,9 +10670,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
10523
10670
  visibleTools[EXECUTE_TOOL_NAME] = createExecuteToolTool();
10524
10671
  const shouldTrace = shouldEmitDevAgentTrace();
10525
10672
  const effectiveConversationPrivacy = conversationPrivacy ?? "private";
10526
- const serializeToolPayload = (payload, options = {}) => serializeGenAiAttribute(
10527
- effectiveConversationPrivacy === "private" && !options.exposePrivate ? toGenAiPayloadMetadata(payload) : payload
10528
- );
10673
+ const serializeToolPayload = (payload, options = {}) => effectiveConversationPrivacy === "private" && !options.exposePrivate ? options.privateMetadata ? serializeGenAiAttribute(toGenAiPayloadMetadata(payload)) : void 0 : serializeGenAiAttribute(payload);
10529
10674
  const notifyToolResult = async (report) => {
10530
10675
  try {
10531
10676
  await onToolResult?.(report);
@@ -10616,14 +10761,17 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
10616
10761
  }
10617
10762
  const toolResultAttribute = effectiveConversationPrivacy === "private" && toolDef.privateTraceResult && !hasProjectedPrivateResult ? void 0 : serializeToolPayload(
10618
10763
  hasProjectedPrivateResult ? projectedPrivateResult : resultAttributeValue,
10619
- { exposePrivate: hasProjectedPrivateResult }
10764
+ {
10765
+ exposePrivate: hasProjectedPrivateResult,
10766
+ privateMetadata: true
10767
+ }
10620
10768
  );
10621
10769
  if (toolResultAttribute) {
10622
10770
  setSpanAttributes2({
10623
10771
  "gen_ai.tool.call.result": toolResultAttribute,
10624
10772
  ...hasProjectedPrivateResult ? privateTraceResultAttributes() : {},
10625
10773
  ...toGenAiPayloadTraceAttributes(
10626
- "app.ai.tool.call.result",
10774
+ "gen_ai.tool.call.result",
10627
10775
  resultAttributeValue
10628
10776
  )
10629
10777
  });
@@ -10654,9 +10802,11 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
10654
10802
  executionMode: toolDef.executionMode,
10655
10803
  execute: async (toolCallId, params, signal) => {
10656
10804
  const normalizedToolCallId = typeof toolCallId === "string" && toolCallId.length > 0 ? toolCallId : void 0;
10657
- const toolArgumentsAttribute = serializeToolPayload(params);
10805
+ const toolArgumentsAttribute = serializeToolPayload(params, {
10806
+ privateMetadata: true
10807
+ });
10658
10808
  const toolArgumentsMetadata = toGenAiPayloadTraceAttributes(
10659
- "app.ai.tool.call.arguments",
10809
+ "gen_ai.tool.call.arguments",
10660
10810
  params
10661
10811
  );
10662
10812
  return withSpan(
@@ -10676,7 +10826,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
10676
10826
  executionToolName = resolvedCatalogCall.toolName;
10677
10827
  executionParams = resolvedCatalogCall.arguments;
10678
10828
  setSpanAttributes2({
10679
- "app.ai.tool.dispatcher.name": EXECUTE_TOOL_NAME,
10829
+ "gen_ai.tool.dispatcher.name": EXECUTE_TOOL_NAME,
10680
10830
  "gen_ai.tool.description": resolvedCatalogCall.definition.description,
10681
10831
  "gen_ai.tool.name": resolvedCatalogCall.toolName
10682
10832
  });
@@ -10723,11 +10873,10 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
10723
10873
  }
10724
10874
  },
10725
10875
  {
10726
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
10727
10876
  "gen_ai.operation.name": "execute_tool",
10728
10877
  "gen_ai.tool.name": toolName,
10729
10878
  "gen_ai.tool.description": toolDef.description,
10730
- "gen_ai.tool.type": "extension",
10879
+ "gen_ai.tool.type": "function",
10731
10880
  ...toolArgumentsMetadata,
10732
10881
  ...normalizedToolCallId ? { "gen_ai.tool.call.id": normalizedToolCallId } : {},
10733
10882
  ...toolArgumentsAttribute ? { "gen_ai.tool.call.arguments": toolArgumentsAttribute } : {}
@@ -12580,9 +12729,9 @@ import { StreamableHTTPClientTransport as StreamableHTTPClientTransport2 } from
12580
12729
  import {
12581
12730
  sourceSchema as sourceSchema2
12582
12731
  } from "@sentry/junior-plugin-api";
12583
- var MCP_AUTH_SESSION_PREFIX = "junior:mcp_auth_session";
12732
+ var MCP_AUTH_SESSION_PREFIX = "junior:mcp_oauth_attempt:v2";
12584
12733
  var MCP_AUTH_CREDENTIALS_PREFIX = "junior:mcp_auth_credentials";
12585
- var MCP_AUTH_SESSION_INDEX_PREFIX = "junior:mcp_auth_session_index";
12734
+ var MCP_AUTH_SESSION_INDEX_PREFIX = "junior:mcp_oauth_attempt_index:v2";
12586
12735
  var MCP_SERVER_SESSION_PREFIX = "junior:mcp_server_session";
12587
12736
  var MCP_AUTH_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
12588
12737
  var MCP_AUTH_CREDENTIALS_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
@@ -12624,7 +12773,7 @@ function parseMcpAuthSession(value) {
12624
12773
  if (!isRecord(parsed)) {
12625
12774
  return void 0;
12626
12775
  }
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") {
12776
+ 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
12777
  return void 0;
12629
12778
  }
12630
12779
  const destination = parsed.destination === void 0 ? void 0 : parseDestination(parsed.destination);
@@ -12636,6 +12785,7 @@ function parseMcpAuthSession(value) {
12636
12785
  return void 0;
12637
12786
  }
12638
12787
  return {
12788
+ schemaVersion: 2,
12639
12789
  authSessionId: parsed.authSessionId,
12640
12790
  provider: parsed.provider,
12641
12791
  userId: parsed.userId,
@@ -12733,6 +12883,7 @@ async function patchMcpAuthSession(authSessionId, patch) {
12733
12883
  const next = {
12734
12884
  ...current,
12735
12885
  ...patch,
12886
+ schemaVersion: 2,
12736
12887
  authSessionId: current.authSessionId,
12737
12888
  provider: current.provider,
12738
12889
  userId: current.userId,
@@ -12777,25 +12928,6 @@ async function deleteMcpAuthSessionsForUserProvider(userId, provider) {
12777
12928
  }
12778
12929
  await stateAdapter.delete(indexKey);
12779
12930
  }
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
12931
  async function getMcpStoredOAuthCredentials(userId, provider) {
12800
12932
  const stateAdapter = await getConnectedStateAdapter();
12801
12933
  return parseStoredCredentials(
@@ -12854,15 +12986,17 @@ function clientAllowsRedirectUri(clientInformation, callbackUrl) {
12854
12986
  return redirectUris.includes(callbackUrl);
12855
12987
  }
12856
12988
  var StateBackedMcpOAuthClientProvider = class {
12857
- constructor(authSessionId, callbackUrl, sessionContext) {
12989
+ constructor(authSessionId, callbackUrl, sessionContext, runCredentialMutation) {
12858
12990
  this.authSessionId = authSessionId;
12859
12991
  this.callbackUrl = callbackUrl;
12860
12992
  this.sessionContext = sessionContext;
12993
+ this.runCredentialMutation = runCredentialMutation;
12861
12994
  this.clientMetadata = createClientMetadata(callbackUrl);
12862
12995
  }
12863
12996
  authSessionId;
12864
12997
  callbackUrl;
12865
12998
  sessionContext;
12999
+ runCredentialMutation;
12866
13000
  clientMetadata;
12867
13001
  get redirectUrl() {
12868
13002
  return this.callbackUrl;
@@ -12886,11 +13020,16 @@ var StateBackedMcpOAuthClientProvider = class {
12886
13020
  return void 0;
12887
13021
  }
12888
13022
  async saveClientInformation(clientInformation) {
12889
- const session = await this.getCredentialContext();
12890
- const credentials = await getMcpStoredOAuthCredentials(session.userId, session.provider) ?? {};
12891
- await putMcpStoredOAuthCredentials(session.userId, session.provider, {
12892
- ...credentials,
12893
- clientInformation
13023
+ await this.mutateCredentials(async () => {
13024
+ const session = await this.getCredentialContext();
13025
+ const credentials = await getMcpStoredOAuthCredentials(
13026
+ session.userId,
13027
+ session.provider
13028
+ ) ?? {};
13029
+ await putMcpStoredOAuthCredentials(session.userId, session.provider, {
13030
+ ...credentials,
13031
+ clientInformation
13032
+ });
12894
13033
  });
12895
13034
  }
12896
13035
  async tokens() {
@@ -12902,19 +13041,32 @@ var StateBackedMcpOAuthClientProvider = class {
12902
13041
  return credentials?.tokens;
12903
13042
  }
12904
13043
  async saveTokens(tokens) {
12905
- const session = await this.getCredentialContext();
12906
- const credentials = await getMcpStoredOAuthCredentials(session.userId, session.provider) ?? {};
12907
- await putMcpStoredOAuthCredentials(session.userId, session.provider, {
12908
- ...credentials,
12909
- tokens
13044
+ await this.mutateCredentials(async () => {
13045
+ const session = await this.getCredentialContext();
13046
+ const credentials = await getMcpStoredOAuthCredentials(
13047
+ session.userId,
13048
+ session.provider
13049
+ ) ?? {};
13050
+ await putMcpStoredOAuthCredentials(session.userId, session.provider, {
13051
+ ...credentials,
13052
+ tokens
13053
+ });
12910
13054
  });
12911
13055
  }
12912
13056
  async redirectToAuthorization(authorizationUrl) {
13057
+ const existing = await getMcpAuthSession(this.authSessionId);
13058
+ if (existing?.authorizationUrl && existing.authorizationUrl !== authorizationUrl.toString()) {
13059
+ throw new Error("MCP OAuth authorization attempt is already initialized");
13060
+ }
12913
13061
  await this.ensureSession({
12914
13062
  authorizationUrl: authorizationUrl.toString()
12915
13063
  });
12916
13064
  }
12917
13065
  async saveCodeVerifier(codeVerifier) {
13066
+ const existing = await getMcpAuthSession(this.authSessionId);
13067
+ if (existing?.codeVerifier && existing.codeVerifier !== codeVerifier) {
13068
+ throw new Error("MCP OAuth authorization attempt is already initialized");
13069
+ }
12918
13070
  await this.ensureSession({ codeVerifier });
12919
13071
  }
12920
13072
  async codeVerifier() {
@@ -12925,11 +13077,16 @@ var StateBackedMcpOAuthClientProvider = class {
12925
13077
  return session.codeVerifier;
12926
13078
  }
12927
13079
  async saveDiscoveryState(state) {
12928
- const session = await this.getCredentialContext();
12929
- const credentials = await getMcpStoredOAuthCredentials(session.userId, session.provider) ?? {};
12930
- await putMcpStoredOAuthCredentials(session.userId, session.provider, {
12931
- ...credentials,
12932
- discoveryState: state
13080
+ await this.mutateCredentials(async () => {
13081
+ const session = await this.getCredentialContext();
13082
+ const credentials = await getMcpStoredOAuthCredentials(
13083
+ session.userId,
13084
+ session.provider
13085
+ ) ?? {};
13086
+ await putMcpStoredOAuthCredentials(session.userId, session.provider, {
13087
+ ...credentials,
13088
+ discoveryState: state
13089
+ });
12933
13090
  });
12934
13091
  }
12935
13092
  async discoveryState() {
@@ -12941,34 +13098,36 @@ var StateBackedMcpOAuthClientProvider = class {
12941
13098
  return credentials?.discoveryState;
12942
13099
  }
12943
13100
  async invalidateCredentials(scope) {
12944
- const session = await this.getCredentialContext();
12945
- const credentials = await getMcpStoredOAuthCredentials(session.userId, session.provider) ?? {};
12946
- await putMcpStoredOAuthCredentials(session.userId, session.provider, {
12947
- ...scope === "tokens" || scope === "all" ? {} : credentials.tokens ? { tokens: credentials.tokens } : {},
12948
- ...scope === "client" || scope === "all" ? {} : credentials.clientInformation ? { clientInformation: credentials.clientInformation } : {},
12949
- ...scope === "discovery" || scope === "all" ? {} : credentials.discoveryState ? { discoveryState: credentials.discoveryState } : {}
13101
+ await this.mutateCredentials(async () => {
13102
+ const session = await this.getCredentialContext();
13103
+ const credentials = await getMcpStoredOAuthCredentials(
13104
+ session.userId,
13105
+ session.provider
13106
+ ) ?? {};
13107
+ await putMcpStoredOAuthCredentials(session.userId, session.provider, {
13108
+ ...scope === "tokens" || scope === "all" ? {} : credentials.tokens ? { tokens: credentials.tokens } : {},
13109
+ ...scope === "client" || scope === "all" ? {} : credentials.clientInformation ? { clientInformation: credentials.clientInformation } : {},
13110
+ ...scope === "discovery" || scope === "all" ? {} : credentials.discoveryState ? { discoveryState: credentials.discoveryState } : {}
13111
+ });
12950
13112
  });
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
13113
  }
12961
13114
  async getMcpServerSessionId() {
12962
13115
  const session = await this.getCredentialContext();
12963
13116
  return await getMcpServerSessionId(session.userId, session.provider);
12964
13117
  }
12965
13118
  async saveMcpServerSessionId(sessionId) {
12966
- const session = await this.getCredentialContext();
12967
- if (!sessionId) {
12968
- await deleteMcpServerSessionId(session.userId, session.provider);
12969
- return;
12970
- }
12971
- await putMcpServerSessionId(session.userId, session.provider, sessionId);
13119
+ await this.mutateCredentials(async () => {
13120
+ const session = await this.getCredentialContext();
13121
+ if (!sessionId) {
13122
+ await deleteMcpServerSessionId(session.userId, session.provider);
13123
+ return;
13124
+ }
13125
+ await putMcpServerSessionId(session.userId, session.provider, sessionId);
13126
+ });
13127
+ }
13128
+ /** Route shared credential writes through callback-owned freshness control. */
13129
+ async mutateCredentials(mutation) {
13130
+ return this.runCredentialMutation ? await this.runCredentialMutation(mutation) : await mutation();
12972
13131
  }
12973
13132
  async getCredentialContext() {
12974
13133
  return this.sessionContext ?? await this.requireSession();
@@ -12983,6 +13142,7 @@ var StateBackedMcpOAuthClientProvider = class {
12983
13142
  }
12984
13143
  const now = Date.now();
12985
13144
  const nextSession = {
13145
+ schemaVersion: 2,
12986
13146
  authSessionId: this.authSessionId,
12987
13147
  ...this.sessionContext,
12988
13148
  ...patch,
@@ -13020,32 +13180,7 @@ async function createMcpOAuthClientProvider(input) {
13020
13180
  "Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)"
13021
13181
  );
13022
13182
  }
13023
- const existingSession = await getLatestMcpAuthSessionForUserProvider(
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
- });
13183
+ const authSessionId = randomUUID3();
13049
13184
  return new StateBackedMcpOAuthClientProvider(
13050
13185
  authSessionId,
13051
13186
  `${baseUrl}${getMcpOAuthCallbackPath(input.provider)}`,
@@ -13054,6 +13189,7 @@ async function createMcpOAuthClientProvider(input) {
13054
13189
  userId: input.userId,
13055
13190
  conversationId: input.conversationId,
13056
13191
  ...input.destination ? { destination: input.destination } : {},
13192
+ ...input.source ? { source: input.source } : {},
13057
13193
  sessionId: input.sessionId,
13058
13194
  userMessage: input.userMessage,
13059
13195
  ...input.channelId ? { channelId: input.channelId } : {},
@@ -13064,7 +13200,7 @@ async function createMcpOAuthClientProvider(input) {
13064
13200
  }
13065
13201
  );
13066
13202
  }
13067
- async function finalizeMcpAuthorization(provider, authSessionId, authorizationCode) {
13203
+ async function finalizeMcpAuthorization(provider, authSessionId, authorizationCode, runCredentialMutation) {
13068
13204
  const plugin = requirePluginWithMcp(provider);
13069
13205
  const mcp = plugin.manifest.mcp;
13070
13206
  if (!mcp) {
@@ -13088,7 +13224,9 @@ async function finalizeMcpAuthorization(provider, authSessionId, authorizationCo
13088
13224
  const callbackUrl = `${baseUrl}${getMcpOAuthCallbackPath(provider)}`;
13089
13225
  const authProvider = new StateBackedMcpOAuthClientProvider(
13090
13226
  authSessionId,
13091
- callbackUrl
13227
+ callbackUrl,
13228
+ void 0,
13229
+ runCredentialMutation
13092
13230
  );
13093
13231
  const requestInit = {};
13094
13232
  if (mcp.headers && Object.keys(mcp.headers).length > 0) {
@@ -13171,16 +13309,6 @@ function createMcpAuthOrchestration(input) {
13171
13309
  `Missing pending auth recorder for MCP authorization pause "${provider}"`
13172
13310
  );
13173
13311
  }
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
13312
  const reusingPendingLink = canReusePendingAuthLink({
13185
13313
  pendingAuth: input.pendingAuth,
13186
13314
  kind: "mcp",
@@ -13188,8 +13316,31 @@ function createMcpAuthOrchestration(input) {
13188
13316
  actorId,
13189
13317
  sessionId
13190
13318
  });
13319
+ const reusedAuthSessionId = reusingPendingLink && input.pendingAuth?.kind === "mcp" ? input.pendingAuth.authSessionId : void 0;
13320
+ const activeAuthSessionId = reusedAuthSessionId ?? authSessionId;
13321
+ const latestArtifactState = input.getMergedArtifactState();
13322
+ await patchMcpAuthSession(activeAuthSessionId, {
13323
+ configuration: { ...input.getConfiguration() },
13324
+ artifactState: latestArtifactState,
13325
+ toolChannelId: input.toolChannelId ?? latestArtifactState.assistantContextChannelId ?? input.channelId
13326
+ });
13191
13327
  const providerLabel = formatProviderLabel(provider);
13328
+ const nextPendingAuth = {
13329
+ authSessionId: activeAuthSessionId,
13330
+ kind: "mcp",
13331
+ provider,
13332
+ actorId,
13333
+ sessionId,
13334
+ linkSentAtMs: reusingPendingLink ? input.pendingAuth.linkSentAtMs : Date.now()
13335
+ };
13192
13336
  if (!reusingPendingLink) {
13337
+ const authSession = await getMcpAuthSession(authSessionId);
13338
+ if (!authSession?.authorizationUrl) {
13339
+ throw new Error(
13340
+ `Missing MCP authorization URL for plugin "${provider}"`
13341
+ );
13342
+ }
13343
+ await recordPendingAuth(nextPendingAuth);
13193
13344
  const delivery = await deliverPrivateMessage({
13194
13345
  channelId: authSession.channelId,
13195
13346
  threadTs: authSession.threadTs,
@@ -13201,20 +13352,21 @@ function createMcpAuthOrchestration(input) {
13201
13352
  })
13202
13353
  });
13203
13354
  if (!delivery) {
13355
+ await deleteMcpAuthSession(authSessionId);
13356
+ await recordPendingAuth(input.pendingAuth);
13204
13357
  throw new Error(
13205
13358
  `Unable to deliver MCP authorization link for plugin "${provider}"`
13206
13359
  );
13207
13360
  }
13361
+ await abandonReplacedPendingAuth({
13362
+ conversationId,
13363
+ previousPendingAuth: input.pendingAuth,
13364
+ nextPendingAuth
13365
+ });
13208
13366
  } else {
13209
13367
  await deleteMcpAuthSession(authSessionId);
13368
+ await recordPendingAuth(nextPendingAuth);
13210
13369
  }
13211
- await recordPendingAuth({
13212
- kind: "mcp",
13213
- provider,
13214
- actorId,
13215
- sessionId,
13216
- linkSentAtMs: reusingPendingLink ? input.pendingAuth.linkSentAtMs : Date.now()
13217
- });
13218
13370
  await recordAuthorizationRequested({
13219
13371
  conversationId,
13220
13372
  kind: "mcp",
@@ -14843,9 +14995,6 @@ var MAX_SUMMARY_INPUT_CHARS = 8e4;
14843
14995
  var MAX_VISIBLE_CONTEXT_CHARS = 2e4;
14844
14996
  var MAX_SUMMARY_CHARS = 6e3;
14845
14997
  var MAX_RENDERED_MESSAGE_CHARS = 4e3;
14846
- var COMPACTION_SUMMARY_PREFIX = "Context compaction summary for future Junior turns:";
14847
- var LEGACY_COMPACTION_SUMMARY_PREFIX = "Context handoff summary for future Junior turns:";
14848
- var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
14849
14998
  var OMITTED_OLDER_CONTEXT_NOTICE = "[older context omitted]";
14850
14999
  function textPart(value) {
14851
15000
  if (value && typeof value === "object" && value.type === "text" && typeof value.text === "string") {
@@ -14879,8 +15028,7 @@ function truncateToTokenBudget(text, maxTokens) {
14879
15028
  return `${text.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
14880
15029
  }
14881
15030
  function isCompactionSummary(text) {
14882
- const normalized = text.trimStart();
14883
- return normalized.startsWith(COMPACTION_SUMMARY_PREFIX) || normalized.startsWith(LEGACY_COMPACTION_SUMMARY_PREFIX) || normalized.startsWith(MODEL_HANDOFF_SUMMARY_PREFIX);
15031
+ return isCompactionSummaryText(text);
14884
15032
  }
14885
15033
  function isPayloadHeavy(text) {
14886
15034
  return /<data_base64>[\s\S]*?<\/data_base64>|data:image\/[a-z0-9.+-]+;base64,/i.test(
@@ -15413,14 +15561,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
15413
15561
  fastModelId: botConfig.fastModelId,
15414
15562
  messageText: userInput
15415
15563
  });
15416
- setSpanAttributes({
15417
- "gen_ai.request.model": activeModelId,
15418
- "gen_ai.request.reasoning.level": reasoningSelection.reasoningLevel,
15419
- "app.ai.reasoning_level_reason": reasoningSelection.reason,
15420
- ...reasoningSelection.confidence !== void 0 ? {
15421
- "app.ai.reasoning_level_confidence": reasoningSelection.confidence
15422
- } : {}
15423
- });
15424
15564
  const generatedFiles = [];
15425
15565
  const artifactStatePatch = {};
15426
15566
  const toolCalls = [];
@@ -15678,9 +15818,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
15678
15818
  runResume.setTurnStartMessageIndex(0);
15679
15819
  runResume.adoptCommittedBoundary(replacement);
15680
15820
  setSpanAttributes({
15681
- "gen_ai.request.model": activeModelId,
15682
- "gen_ai.request.reasoning.level": reasoningSelection.reasoningLevel,
15683
- "app.ai.model_profile": activeModelProfile
15821
+ "gen_ai.agent.model": activeModelId,
15822
+ "gen_ai.agent.model_profile": activeModelProfile,
15823
+ "gen_ai.agent.reasoning.level": reasoningSelection.reasoningLevel
15684
15824
  });
15685
15825
  update = {
15686
15826
  context: {
@@ -15764,7 +15904,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
15764
15904
  runResume.setTurnStartMessageIndex(agent.state.messages.length);
15765
15905
  }
15766
15906
  await withSpan(
15767
- `invoke_agent ${activeModelId}`,
15907
+ `invoke_agent ${botConfig.userName}`,
15768
15908
  "gen_ai.invoke_agent",
15769
15909
  spanContext,
15770
15910
  async () => {
@@ -15885,8 +16025,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
15885
16025
  );
15886
16026
  const outputMessages = newMessages.filter(isAssistantMessage);
15887
16027
  const outputMessagesAttribute = serializeGenAiAttribute(
15888
- conversationPrivacy !== "public" ? outputMessages.map(toGenAiMessageMetadata) : outputMessages.map(toCanonicalOutputMessage)
16028
+ conversationPrivacy === "public" ? outputMessages.map(toCanonicalOutputMessage) : void 0
15889
16029
  );
16030
+ const lastAssistant = outputMessages.at(-1);
15890
16031
  const usageSummary = extractGenAiUsageSummary(...outputMessages);
15891
16032
  const currentUsage = hasAgentTurnUsage(usageSummary) ? usageSummary : void 0;
15892
16033
  const currentPhaseUsage = addAgentTurnUsage(
@@ -15897,9 +16038,14 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
15897
16038
  setSpanAttributes({
15898
16039
  ...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : {},
15899
16040
  ...toGenAiMessagesTraceAttributes(
15900
- "app.ai.output",
16041
+ "gen_ai.output",
15901
16042
  outputMessages
15902
16043
  ),
16044
+ ...lastAssistant ? {
16045
+ "gen_ai.response.finish_reasons": [
16046
+ normalizeGenAiFinishReason(lastAssistant.stopReason)
16047
+ ]
16048
+ } : {},
15903
16049
  ...extractGenAiUsageAttributes(usageSummary)
15904
16050
  });
15905
16051
  if (getPendingAuthPause()) {
@@ -15908,7 +16054,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
15908
16054
  );
15909
16055
  throw getPendingAuthPause();
15910
16056
  }
15911
- const lastAssistant = outputMessages.at(-1);
15912
16057
  const providerRetry = nextProviderRetry({
15913
16058
  attempt,
15914
16059
  lastAssistant,
@@ -15932,18 +16077,20 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
15932
16077
  }
15933
16078
  },
15934
16079
  {
15935
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
15936
16080
  "gen_ai.operation.name": "invoke_agent",
15937
- "gen_ai.request.model": activeModelId,
16081
+ "gen_ai.agent.model": activeModelId,
16082
+ "gen_ai.agent.model_profile": activeModelProfile,
16083
+ "gen_ai.agent.reasoning.level": reasoningSelection.reasoningLevel,
16084
+ "gen_ai.agent.reasoning.level_reason": reasoningSelection.reason,
16085
+ ...reasoningSelection.confidence !== void 0 ? {
16086
+ "gen_ai.agent.reasoning.level_confidence": reasoningSelection.confidence
16087
+ } : {},
15938
16088
  "gen_ai.output.type": "text",
15939
- "server.address": GEN_AI_SERVER_ADDRESS,
15940
- "server.port": GEN_AI_SERVER_PORT,
15941
16089
  ...conversationPrivacy ? { "app.conversation.privacy": conversationPrivacy } : {},
15942
16090
  ...sessionConversationId ? { "app.ai.session.conversation_id": sessionConversationId } : {},
15943
16091
  ...sessionId ? { "app.ai.turn.session_id": sessionId } : {},
15944
16092
  ...currentSliceId ? { "app.ai.turn.slice_id": currentSliceId } : {},
15945
- "gen_ai.request.reasoning.level": reasoningSelection.reasoningLevel,
15946
- ...toGenAiMessagesTraceAttributes("app.ai.input", inputMessages),
16093
+ ...toGenAiMessagesTraceAttributes("gen_ai.input", inputMessages),
15947
16094
  ...inputMessagesAttribute ? { "gen_ai.input.messages": inputMessagesAttribute } : {}
15948
16095
  }
15949
16096
  );
@@ -16102,6 +16249,7 @@ export {
16102
16249
  normalizeSandboxEgressTracePropagationDomains,
16103
16250
  shouldPropagateSandboxEgressTrace,
16104
16251
  resolveSandboxEgressProviderForHost,
16252
+ getMcpAuthSession,
16105
16253
  deleteMcpAuthSession,
16106
16254
  deleteMcpAuthSessionsForUserProvider,
16107
16255
  getMcpStoredOAuthCredentials,