@sentry/junior 0.99.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.
Files changed (91) hide show
  1. package/README.md +0 -1
  2. package/dist/{agent-hooks-OSW6C3CJ.js → agent-hooks-V6KU7PQN.js} +6 -5
  3. package/dist/api/activity.d.ts +14 -0
  4. package/dist/api/conversations/aggregate.d.ts +16 -0
  5. package/dist/api/conversations/detail-projection.d.ts +1 -0
  6. package/dist/api/conversations/list.query.d.ts +3 -0
  7. package/dist/api/conversations/projection.d.ts +1 -0
  8. package/dist/api/conversations/reporting.d.ts +42 -0
  9. package/dist/api/conversations/schema.d.ts +9 -9
  10. package/dist/api/conversations/stats.query.d.ts +1 -1
  11. package/dist/api/locations/detail.d.ts +81 -0
  12. package/dist/api/locations/list.d.ts +30 -0
  13. package/dist/api/locations/query.d.ts +5 -0
  14. package/dist/api/locations/schema.d.ts +175 -0
  15. package/dist/api/people/list.query.d.ts +1 -1
  16. package/dist/api/people/profile.query.d.ts +1 -1
  17. package/dist/api/people/schema.d.ts +10 -14
  18. package/dist/api/people/shared.d.ts +38 -78
  19. package/dist/api/schema.d.ts +8 -0
  20. package/dist/api/schema.js +14 -3
  21. package/dist/api.js +24 -11
  22. package/dist/app.js +126 -70
  23. package/dist/chat/agent/request.d.ts +4 -1
  24. package/dist/chat/config.d.ts +2 -0
  25. package/dist/chat/conversations/store.d.ts +1 -1
  26. package/dist/chat/mcp/auth-store.d.ts +1 -0
  27. package/dist/chat/mcp/client.d.ts +2 -0
  28. package/dist/chat/mcp/oauth-provider.d.ts +4 -1
  29. package/dist/chat/mcp/oauth.d.ts +3 -1
  30. package/dist/chat/mcp/tool-manager.d.ts +2 -0
  31. package/dist/chat/reasoning-level.d.ts +4 -0
  32. package/dist/chat/services/mcp-auth-orchestration.d.ts +1 -1
  33. package/dist/chat/services/pending-auth.d.ts +17 -9
  34. package/dist/chat/services/{turn-thinking-level.d.ts → turn-reasoning-level.d.ts} +11 -10
  35. package/dist/chat/services/turn-result.d.ts +3 -3
  36. package/dist/chat/state/conversation.d.ts +7 -3
  37. package/dist/chat/tools/search-tools.d.ts +2 -2
  38. package/dist/{chunk-T55RBE4Z.js → chunk-2RNOB32R.js} +3 -1
  39. package/dist/{chunk-ZZUBLPXD.js → chunk-5VGJJSSV.js} +9 -7
  40. package/dist/{chunk-EEZCY5WX.js → chunk-A7X2FDUO.js} +18 -2
  41. package/dist/{chunk-CRQVIHDI.js → chunk-DBPLXSBK.js} +2 -8
  42. package/dist/{chunk-NJEDJFK4.js → chunk-EBFJOOUE.js} +2 -2
  43. package/dist/{chunk-WTYEKPXU.js → chunk-FP5N5OWZ.js} +1 -1
  44. package/dist/chunk-FXFQNHRU.js +48 -0
  45. package/dist/chunk-GEUUJRQF.js +102 -0
  46. package/dist/chunk-HNIT4HXU.js +75 -0
  47. package/dist/{chunk-EUZ44ROE.js → chunk-HYDQULR2.js} +2 -4
  48. package/dist/{chunk-DHHU2WSG.js → chunk-IQIBZXGB.js} +2 -2
  49. package/dist/{chunk-OL6XQ23W.js → chunk-IVXL57YF.js} +3 -3
  50. package/dist/{chunk-IO65E4ZD.js → chunk-JPQISMMJ.js} +3 -3
  51. package/dist/{chunk-KFUSLFLL.js → chunk-JSAANELJ.js} +11 -4
  52. package/dist/{chunk-ER45IV77.js → chunk-L2JIOAA2.js} +10 -10
  53. package/dist/chunk-PGGEOCQY.js +77 -0
  54. package/dist/{chunk-EOWXRY5E.js → chunk-PWC24W5F.js} +1 -1
  55. package/dist/chunk-QOZOJNSE.js +96 -0
  56. package/dist/{chunk-FTTFV6DC.js → chunk-TPTJEHUE.js} +4 -4
  57. package/dist/{chunk-PYK7R5A7.js → chunk-UWGTSF5O.js} +285 -174
  58. package/dist/chunk-VFBFK6EY.js +275 -0
  59. package/dist/{chunk-OGHXZ4KQ.js → chunk-VHRM6GNH.js} +88 -122
  60. package/dist/{chunk-NG2AV7IB.js → chunk-VVIXK2BX.js} +1 -1
  61. package/dist/{chunk-6DTVCPLO.js → chunk-XIMUQ4IU.js} +4 -3
  62. package/dist/{chunk-H66UCBPW.js → chunk-XJA7BPHS.js} +1 -1
  63. package/dist/{chunk-WJ7STXT6.js → chunk-XVR4O24H.js} +8 -10
  64. package/dist/cli/chat.js +16 -15
  65. package/dist/cli/plugins.js +6 -5
  66. package/dist/cli/snapshot-warmup.js +2 -2
  67. package/dist/cli/upgrade.js +126 -8
  68. package/dist/db/schema/conversations.d.ts +17 -0
  69. package/dist/db/schema/destinations.d.ts +12 -3
  70. package/dist/db/schema.d.ts +19 -2
  71. package/dist/{db-GFSCDAHS.js → db-RCZB7KNM.js} +3 -2
  72. package/dist/{detail-Q4IVDNGS.js → detail-4EPUMSDU.js} +11 -10
  73. package/dist/detail-CD4SPJ4K.js +29 -0
  74. package/dist/{legacy-import-6WWXMALY.js → legacy-import-VCYLWT2V.js} +4 -3
  75. package/dist/list-7L5LY2WU.js +30 -0
  76. package/dist/list-DA2ATOM4.js +80 -0
  77. package/dist/{list-A3F5JDYV.js → list-J6ROVH56.js} +7 -6
  78. package/dist/{plugin-conversations-PDCQWU3O.js → plugin-conversations-JANXC4GA.js} +6 -5
  79. package/dist/profile-6NRWEKMZ.js +212 -0
  80. package/dist/{runner-267ZRLZD.js → runner-CZIKSWGC.js} +13 -12
  81. package/dist/stats-Q5FRUXLY.js +174 -0
  82. package/dist/{subagent-UN3MP6LV.js → subagent-YIINCFAS.js} +10 -9
  83. package/migrations/0003_peaceful_scalphunter.sql +4 -0
  84. package/migrations/meta/0003_snapshot.json +1035 -0
  85. package/migrations/meta/_journal.json +8 -1
  86. package/package.json +6 -6
  87. package/dist/api-reference.d.ts +0 -14
  88. package/dist/chunk-CV22LUIV.js +0 -261
  89. package/dist/list-M5BRWW3D.js +0 -92
  90. package/dist/profile-UEIRSVT3.js +0 -146
  91. package/dist/stats-L62E4O4U.js +0 -207
package/dist/app.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  processPluginTask,
6
6
  requireTurnFailureEventId,
7
7
  scheduleSessionCompletedPluginTasks
8
- } from "./chunk-ER45IV77.js";
8
+ } from "./chunk-L2JIOAA2.js";
9
9
  import {
10
10
  buildSentryConversationUrl
11
11
  } from "./chunk-LVUKF5CE.js";
@@ -13,7 +13,7 @@ import {
13
13
  conversationVisibilityFromSlackChannelType,
14
14
  resolveSlackChannelTypeFromMessage,
15
15
  resolveSlackConversationContext
16
- } from "./chunk-NG2AV7IB.js";
16
+ } from "./chunk-VVIXK2BX.js";
17
17
  import {
18
18
  CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
19
19
  CONVERSATION_WORK_STALE_ENQUEUE_MS,
@@ -37,7 +37,7 @@ import {
37
37
  requestConversationContinuation,
38
38
  requestConversationWork,
39
39
  startConversationWork
40
- } from "./chunk-NJEDJFK4.js";
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-PYK7R5A7.js";
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,24 +134,24 @@ import {
134
134
  persistWithRetry,
135
135
  persistYieldSessionRecord,
136
136
  startActiveTurn
137
- } from "./chunk-WJ7STXT6.js";
137
+ } from "./chunk-XVR4O24H.js";
138
138
  import {
139
139
  JUNIOR_THREAD_STATE_TTL_MS,
140
140
  coerceThreadConversationState
141
- } from "./chunk-6DTVCPLO.js";
141
+ } from "./chunk-XIMUQ4IU.js";
142
142
  import {
143
143
  abandonAgentTurnSessionRecord,
144
144
  failAgentTurnSessionRecord,
145
145
  getAgentTurnSessionRecord,
146
146
  listAgentTurnSessionSummariesForConversation,
147
147
  recordAgentTurnSessionSummary
148
- } from "./chunk-OL6XQ23W.js";
148
+ } from "./chunk-IVXL57YF.js";
149
149
  import {
150
150
  commitMessages,
151
151
  loadConversationProjection,
152
152
  loadProjection,
153
153
  recordAuthorizationCompleted
154
- } from "./chunk-DHHU2WSG.js";
154
+ } from "./chunk-IQIBZXGB.js";
155
155
  import {
156
156
  buildConversationContext,
157
157
  createConversationMemoryService,
@@ -166,8 +166,8 @@ import {
166
166
  persistConversationMessages,
167
167
  updateConversationStats,
168
168
  upsertConversationMessage
169
- } from "./chunk-IO65E4ZD.js";
170
- import "./chunk-H66UCBPW.js";
169
+ } from "./chunk-JPQISMMJ.js";
170
+ import "./chunk-XJA7BPHS.js";
171
171
  import "./chunk-PDO5BLNM.js";
172
172
  import "./chunk-CM5EZD5F.js";
173
173
  import {
@@ -179,7 +179,7 @@ import {
179
179
  setPlugins,
180
180
  validatePlugins,
181
181
  verifySlackDirectCredentialSubject
182
- } from "./chunk-FTTFV6DC.js";
182
+ } from "./chunk-TPTJEHUE.js";
183
183
  import {
184
184
  SlackActionError,
185
185
  downloadPrivateSlackFile,
@@ -190,11 +190,11 @@ import {
190
190
  normalizeSlackConversationId,
191
191
  runWithSlackInstallationToken,
192
192
  runWithWorkspaceTeamId
193
- } from "./chunk-WTYEKPXU.js";
193
+ } from "./chunk-FP5N5OWZ.js";
194
194
  import {
195
195
  createPluginLogger,
196
196
  createPluginState
197
- } from "./chunk-EOWXRY5E.js";
197
+ } from "./chunk-PWC24W5F.js";
198
198
  import {
199
199
  contextProvenance,
200
200
  getConversationStore,
@@ -203,9 +203,8 @@ import {
203
203
  instructionProvenanceFor,
204
204
  juniorAgentSteps,
205
205
  juniorConversationMessages,
206
- juniorConversations,
207
- juniorDestinations
208
- } from "./chunk-OGHXZ4KQ.js";
206
+ juniorConversations
207
+ } from "./chunk-VHRM6GNH.js";
209
208
  import "./chunk-G3E7SCME.js";
210
209
  import {
211
210
  sleep
@@ -233,7 +232,10 @@ import {
233
232
  setSlackReactionConfig,
234
233
  stripRuntimeTurnContext,
235
234
  trimTrailingAssistantMessages
236
- } from "./chunk-EEZCY5WX.js";
235
+ } from "./chunk-A7X2FDUO.js";
236
+ import {
237
+ juniorDestinations
238
+ } from "./chunk-FXFQNHRU.js";
237
239
  import {
238
240
  parseSlackThreadId,
239
241
  readSlackRawMessageContext,
@@ -1153,7 +1155,7 @@ async function runAgentDispatchSlice(callback, deps) {
1153
1155
  modelId: reply.diagnostics.modelId,
1154
1156
  durationMs: reply.diagnostics.durationMs,
1155
1157
  usage: reply.diagnostics.usage,
1156
- reasoningLevel: reply.diagnostics.thinkingLevel,
1158
+ reasoningLevel: reply.diagnostics.reasoningLevel,
1157
1159
  destination: dispatch.destination,
1158
1160
  source: dispatch.source,
1159
1161
  actor: dispatch.actor,
@@ -4495,6 +4497,11 @@ var CALLBACK_PAGES = {
4495
4497
  message: "Missing code parameter.",
4496
4498
  status: 400
4497
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
+ },
4498
4505
  success: {
4499
4506
  title: "Authorization complete",
4500
4507
  message: "Your MCP access is connected. Junior will continue the paused request in Slack.",
@@ -4506,6 +4513,12 @@ var CALLBACK_PAGES = {
4506
4513
  status: 500
4507
4514
  }
4508
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
+ };
4509
4522
  function mcpAuthorizationId(args) {
4510
4523
  return `${args.sessionId}:mcp:${args.provider}`;
4511
4524
  }
@@ -4595,20 +4608,19 @@ async function resumeAuthorizedMcpTurn(args) {
4595
4608
  provider,
4596
4609
  actorId: authSession.userId
4597
4610
  });
4598
- const resolvedSessionId = pendingAuth?.sessionId ?? authSession.sessionId;
4611
+ if (pendingAuth?.authSessionId !== authSession.authSessionId) {
4612
+ return;
4613
+ }
4614
+ const resolvedSessionId = pendingAuth.sessionId;
4599
4615
  const userMessage = getTurnUserMessage(conversation, resolvedSessionId);
4600
- if (pendingAuth) {
4601
- if (!isPendingAuthLatestRequest(conversation, pendingAuth)) {
4602
- clearPendingAuth(conversation, pendingAuth.sessionId);
4603
- await persistThreadStateById(threadId, { conversation });
4604
- await abandonAgentTurnSessionRecord({
4605
- conversationId: authSession.conversationId,
4606
- sessionId: pendingAuth.sessionId,
4607
- errorMessage: "Auth completed after a newer thread message abandoned this blocked request."
4608
- });
4609
- return;
4610
- }
4611
- } 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
+ });
4612
4624
  return;
4613
4625
  }
4614
4626
  if (!userMessage) {
@@ -4636,24 +4648,23 @@ async function resumeAuthorizedMcpTurn(args) {
4636
4648
  provider,
4637
4649
  actorId: authSession.userId
4638
4650
  });
4639
- const lockedSessionId = lockedPendingAuth?.sessionId ?? authSession.sessionId;
4651
+ if (lockedPendingAuth?.authSessionId !== authSession.authSessionId) {
4652
+ return false;
4653
+ }
4654
+ const lockedSessionId = lockedPendingAuth.sessionId;
4640
4655
  if (lockedSessionId !== resolvedSessionId) {
4641
4656
  return false;
4642
4657
  }
4643
- if (lockedPendingAuth) {
4644
- if (!isPendingAuthLatestRequest(lockedConversation, lockedPendingAuth)) {
4645
- clearPendingAuth(lockedConversation, lockedPendingAuth.sessionId);
4646
- await persistThreadStateById(threadId, {
4647
- conversation: lockedConversation
4648
- });
4649
- await abandonAgentTurnSessionRecord({
4650
- conversationId: authSession.conversationId,
4651
- sessionId: lockedPendingAuth.sessionId,
4652
- errorMessage: "Auth completed after a newer thread message abandoned this blocked request."
4653
- });
4654
- return false;
4655
- }
4656
- } 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
+ });
4657
4668
  return false;
4658
4669
  }
4659
4670
  const lockedUserMessage = getTurnUserMessage(
@@ -4753,11 +4764,7 @@ async function resumeAuthorizedMcpTurn(args) {
4753
4764
  },
4754
4765
  durability: {
4755
4766
  recordPendingAuth: async (nextPendingAuth) => {
4756
- await applyPendingAuthUpdate({
4757
- conversation: lockedConversation,
4758
- conversationId: authSession.conversationId,
4759
- nextPendingAuth
4760
- });
4767
+ lockedConversation.processing.pendingAuth = nextPendingAuth;
4761
4768
  await persistThreadStateById(threadId, {
4762
4769
  conversation: lockedConversation
4763
4770
  });
@@ -4822,6 +4829,43 @@ async function resumeAuthorizedMcpTurn(args) {
4822
4829
  }
4823
4830
  });
4824
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
+ }
4825
4869
  async function GET4(request, provider, waitUntil, options) {
4826
4870
  const url = new URL(request.url);
4827
4871
  const state = url.searchParams.get("state")?.trim();
@@ -4837,7 +4881,23 @@ async function GET4(request, provider, waitUntil, options) {
4837
4881
  return htmlResponse("missing_code");
4838
4882
  }
4839
4883
  try {
4840
- const authSession = await finalizeMcpAuthorization(provider, state, code);
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
+ );
4841
4901
  try {
4842
4902
  await deleteMcpAuthSession(authSession.authSessionId);
4843
4903
  } catch (cleanupError) {
@@ -4858,6 +4918,10 @@ async function GET4(request, provider, waitUntil, options) {
4858
4918
  );
4859
4919
  return htmlResponse("success");
4860
4920
  } catch (callbackError) {
4921
+ if (callbackError instanceof McpOAuthAttemptExpiredError) {
4922
+ await deleteMcpAuthSession(state);
4923
+ return htmlResponse("expired");
4924
+ }
4861
4925
  logException(
4862
4926
  callbackError,
4863
4927
  "mcp_oauth_callback_failed",
@@ -5302,11 +5366,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
5302
5366
  },
5303
5367
  durability: {
5304
5368
  recordPendingAuth: async (nextPendingAuth) => {
5305
- await applyPendingAuthUpdate({
5306
- conversation: lockedConversation,
5307
- conversationId: stored.resumeConversationId,
5308
- nextPendingAuth
5309
- });
5369
+ lockedConversation.processing.pendingAuth = nextPendingAuth;
5310
5370
  await persistThreadStateById(stored.resumeConversationId, {
5311
5371
  conversation: lockedConversation
5312
5372
  });
@@ -10106,11 +10166,7 @@ function createReplyToThread(deps) {
10106
10166
  });
10107
10167
  },
10108
10168
  recordPendingAuth: async (pendingAuth) => {
10109
- await applyPendingAuthUpdate({
10110
- conversation: preparedState.conversation,
10111
- conversationId,
10112
- nextPendingAuth: pendingAuth
10113
- });
10169
+ preparedState.conversation.processing.pendingAuth = pendingAuth;
10114
10170
  await persistThreadState(thread, {
10115
10171
  conversation: preparedState.conversation
10116
10172
  });
@@ -10304,7 +10360,7 @@ function createReplyToThread(deps) {
10304
10360
  conversationId,
10305
10361
  durationMs: reply.diagnostics.durationMs,
10306
10362
  usage: reply.diagnostics.usage,
10307
- reasoningLevel: reply.diagnostics.thinkingLevel,
10363
+ reasoningLevel: reply.diagnostics.reasoningLevel,
10308
10364
  destination,
10309
10365
  destinationVisibility,
10310
10366
  source,
@@ -11198,11 +11254,7 @@ async function continueSlackAgentRun(payload, options) {
11198
11254
  },
11199
11255
  durability: {
11200
11256
  recordPendingAuth: async (nextPendingAuth) => {
11201
- await applyPendingAuthUpdate({
11202
- conversation,
11203
- conversationId: payload.conversationId,
11204
- nextPendingAuth
11205
- });
11257
+ conversation.processing.pendingAuth = nextPendingAuth;
11206
11258
  await persistThreadStateById(payload.conversationId, {
11207
11259
  conversation
11208
11260
  });
@@ -11674,9 +11726,11 @@ function dashboardHostRoutePaths(dashboard) {
11674
11726
  basePath,
11675
11727
  conversationsPath,
11676
11728
  `${conversationsPath}/*`,
11729
+ pagePath("locations"),
11730
+ `${pagePath("locations")}/*`,
11677
11731
  peoplePath,
11678
11732
  `${peoplePath}/*`,
11679
- pagePath("plugins")
11733
+ pagePath("system")
11680
11734
  ];
11681
11735
  const loginPath = basePath === "/" ? "/auth/login" : `${basePath}/auth/login`;
11682
11736
  return [
@@ -11692,6 +11746,8 @@ function dashboardHostRoutePaths(dashboard) {
11692
11746
  "/api/skills",
11693
11747
  "/api/conversations",
11694
11748
  "/api/conversations/*",
11749
+ "/api/locations",
11750
+ "/api/locations/*",
11695
11751
  "/api/people",
11696
11752
  "/api/people/*",
11697
11753
  "/api/config",
@@ -22,6 +22,7 @@ import type { ConversationPendingAuthState } from "@/chat/state/conversation";
22
22
  import type { PiMessageProvenance } from "@/chat/state/session-log";
23
23
  import type { AgentTurnSurface } from "@/chat/state/turn-session";
24
24
  import type { ToolExecutionReport } from "@/chat/tool-support/tool-execution-report";
25
+ import type { TurnReasoningLevel } from "@/chat/reasoning-level";
25
26
  import type { ImageGenerateToolDeps, WebFetchToolDeps, WebSearchToolDeps } from "@/chat/tools/types";
26
27
  export interface AgentRunAttachment {
27
28
  data?: Buffer;
@@ -89,6 +90,8 @@ export interface AgentRunPolicy {
89
90
  /** Cancels provider work when the owning host request is abandoned. */
90
91
  signal?: AbortSignal;
91
92
  authorizationFlowMode?: AuthorizationFlowMode;
93
+ /** Explicit per-agent reasoning level. When set, adaptive routing is disabled. */
94
+ reasoningLevel?: TurnReasoningLevel;
92
95
  configuration?: Record<string, unknown>;
93
96
  channelConfiguration?: ChannelConfigurationService;
94
97
  skillDirs?: string[];
@@ -130,7 +133,7 @@ export interface AgentRunDurability {
130
133
  /** Return true when the durable worker should pause at the next Pi boundary. */
131
134
  shouldYield?: () => boolean;
132
135
  drainSteeringMessages?: (accept: (messages: AgentRunSteeringMessage[]) => Promise<void>) => Promise<AgentRunSteeringMessage[]>;
133
- recordPendingAuth?: (pendingAuth: ConversationPendingAuthState) => void | Promise<void>;
136
+ recordPendingAuth?: (pendingAuth: ConversationPendingAuthState | undefined) => void | Promise<void>;
134
137
  onSandboxAcquired?: (sandbox: SandboxAcquiredState) => void | Promise<void>;
135
138
  onArtifactStateUpdated?: (artifactState: ThreadArtifactsState) => void | Promise<void>;
136
139
  }
@@ -1,3 +1,4 @@
1
+ import { type TurnReasoningLevel } from "@/chat/reasoning-level";
1
2
  /**
2
3
  * Buffer between the Vercel function timeout and the agent turn timeout so
3
4
  * Junior can abort, persist, and schedule continuation before host teardown.
@@ -9,6 +10,7 @@ export interface BotConfig {
9
10
  loadingMessages: string[];
10
11
  modelId: string;
11
12
  modelProfiles: Readonly<Record<string, string>>;
13
+ reasoningLevel?: TurnReasoningLevel;
12
14
  modelContextWindowTokens?: number;
13
15
  visionModelId?: string;
14
16
  turnTimeoutMs: number;
@@ -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 (`../../../specs/data-redaction-policy.md`).
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;
@@ -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
- export declare function finalizeMcpAuthorization(provider: string, authSessionId: string, authorizationCode: string): Promise<McpAuthSessionState>;
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. */
@@ -0,0 +1,4 @@
1
+ export declare const TURN_REASONING_LEVELS: readonly ["none", "low", "medium", "high", "xhigh"];
2
+ export type TurnReasoningLevel = (typeof TURN_REASONING_LEVELS)[number];
3
+ /** Validate a configured main-agent reasoning level. */
4
+ export declare function parseTurnReasoningLevel(value: unknown): TurnReasoningLevel;
@@ -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: AuthorizationPauseKind;
16
+ kind: "mcp";
16
17
  provider: string;
17
18
  actorId: string;
18
19
  scope?: string;
19
- }): ConversationPendingAuthState | undefined;
20
- export declare function clearPendingAuth(conversation: ThreadConversationState, sessionId?: string): void;
21
- /**
22
- * Apply a new pending-auth record to the conversation and, when replacing a
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,9 +1,9 @@
1
1
  import type { ThinkingLevel as AgentThinkingLevel } from "@earendil-works/pi-agent-core";
2
2
  import type { ThinkingLevel as ProviderThinkingLevel } from "@earendil-works/pi-ai";
3
3
  import { z } from "zod";
4
- declare const TURN_THINKING_LEVELS: readonly ["none", "low", "medium", "high", "xhigh"];
4
+ import { type TurnReasoningLevel } from "@/chat/reasoning-level";
5
5
  declare const turnExecutionProfileSchema: z.ZodObject<{
6
- thinking_level: z.ZodEnum<{
6
+ reasoning_level: z.ZodEnum<{
7
7
  low: "low";
8
8
  medium: "medium";
9
9
  high: "high";
@@ -13,14 +13,15 @@ declare const turnExecutionProfileSchema: z.ZodObject<{
13
13
  confidence: z.ZodPreprocess<z.ZodNumber>;
14
14
  reason: z.ZodString;
15
15
  }, z.core.$strip>;
16
- type TurnThinkingLevel = (typeof TURN_THINKING_LEVELS)[number];
17
- export interface TurnThinkingSelection {
16
+ export interface TurnReasoningSelection {
18
17
  confidence?: number;
19
- thinkingLevel: TurnThinkingLevel;
18
+ reasoningLevel: TurnReasoningLevel;
20
19
  reason: string;
21
20
  }
22
- /** Choose the thinking level for the upcoming assistant turn. */
23
- export declare function selectTurnThinkingLevel(args: {
21
+ /** Preserve an explicitly configured reasoning level without invoking the router. */
22
+ export declare function configuredTurnReasoningLevel(reasoningLevel: TurnReasoningLevel, source: "agent_config" | "default"): TurnReasoningSelection;
23
+ /** Choose the reasoning level for the upcoming assistant turn when none is configured. */
24
+ export declare function selectTurnReasoningLevel(args: {
24
25
  completeObject: (args: {
25
26
  modelId: string;
26
27
  schema: typeof turnExecutionProfileSchema;
@@ -43,7 +44,7 @@ export declare function selectTurnThinkingLevel(args: {
43
44
  currentTurnBlocks?: string[];
44
45
  fastModelId: string;
45
46
  messageText: string;
46
- }): Promise<TurnThinkingSelection>;
47
- /** Convert a routing bucket into the Pi Agent thinking level for a main turn. */
48
- export declare function toAgentThinkingLevel(level: TurnThinkingSelection["thinkingLevel"]): AgentThinkingLevel | "off";
47
+ }): Promise<TurnReasoningSelection>;
48
+ /** Convert a routing bucket into the Pi Agent reasoning setting for a main turn. */
49
+ export declare function toPiReasoningLevel(level: TurnReasoningSelection["reasoningLevel"]): AgentThinkingLevel | "off";
49
50
  export {};
@@ -1,6 +1,6 @@
1
1
  import type { LogContext } from "@/chat/logging";
2
2
  import type { PiMessage } from "@/chat/pi/messages";
3
- import type { TurnThinkingSelection } from "@/chat/services/turn-thinking-level";
3
+ import type { TurnReasoningSelection } from "@/chat/services/turn-reasoning-level";
4
4
  import type { AgentTurnUsage } from "@/chat/usage";
5
5
  import type { ReplyDeliveryPlan } from "@/chat/services/reply-delivery-plan";
6
6
  import type { ThreadArtifactsState } from "@/chat/state/artifacts";
@@ -11,7 +11,7 @@ export interface AgentTurnDiagnostics {
11
11
  providerError?: unknown;
12
12
  modelId: string;
13
13
  outcome: "success" | "execution_failure" | "provider_error";
14
- thinkingLevel?: TurnThinkingSelection["thinkingLevel"];
14
+ reasoningLevel?: TurnReasoningSelection["reasoningLevel"];
15
15
  stopReason?: string;
16
16
  toolCalls: string[];
17
17
  toolErrorCount: number;
@@ -42,7 +42,7 @@ export interface TurnResultInput {
42
42
  shouldTrace: boolean;
43
43
  spanContext: LogContext;
44
44
  usage?: AgentTurnUsage;
45
- thinkingSelection: TurnThinkingSelection;
45
+ reasoningSelection: TurnReasoningSelection;
46
46
  correlation?: {
47
47
  threadId?: string;
48
48
  actorId?: string;