@sentry/junior 0.111.0 → 0.113.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 (57) hide show
  1. package/dist/{agent-hooks-QQ2IWKOP.js → agent-hooks-BKEMWR3Z.js} +8 -8
  2. package/dist/api/conversations/cursor.d.ts +17 -0
  3. package/dist/api/conversations/detail.d.ts +16 -18
  4. package/dist/api/conversations/event-list.d.ts +91 -0
  5. package/dist/api/conversations/event-page.d.ts +18 -0
  6. package/dist/api/conversations/events.d.ts +5 -1
  7. package/dist/api/conversations/projection.d.ts +6 -1
  8. package/dist/api/people/profile.d.ts +1 -0
  9. package/dist/api/schema/conversation.d.ts +132 -51
  10. package/dist/api/schema/person.d.ts +2 -0
  11. package/dist/api/schema.d.ts +2 -2
  12. package/dist/api/schema.js +7 -1
  13. package/dist/api.js +445 -138
  14. package/dist/app.js +50 -27
  15. package/dist/{catalog-runtime-D22W6QEJ.js → catalog-runtime-6XYOUVRZ.js} +5 -5
  16. package/dist/chat/pi/transcript.d.ts +2 -0
  17. package/dist/chat/runtime/agent-run-outcome.d.ts +1 -0
  18. package/dist/chat/services/auth-pause-response.d.ts +1 -1
  19. package/dist/chat/services/auth-pause.d.ts +2 -1
  20. package/dist/chat/services/mcp-auth-orchestration.d.ts +1 -1
  21. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
  22. package/dist/chat/services/provider-error.d.ts +39 -0
  23. package/dist/chat/services/provider-retry.d.ts +3 -6
  24. package/dist/chat/task-execution/state.d.ts +2 -2
  25. package/dist/chat/task-execution/store.d.ts +1 -1
  26. package/dist/chat/tools/resource-events.d.ts +3 -129
  27. package/dist/{chunk-J7APPQIJ.js → chunk-36UJA3OD.js} +1 -1
  28. package/dist/{chunk-Z2W4SJZ7.js → chunk-3CTIAKSS.js} +1 -1
  29. package/dist/{chunk-B45FPP2A.js → chunk-4VKFQPCW.js} +4 -4
  30. package/dist/{chunk-BTRNMS6A.js → chunk-4WZ7YKDF.js} +2 -2
  31. package/dist/{chunk-SL3ZKNLQ.js → chunk-DXRPHBOU.js} +132 -23
  32. package/dist/{chunk-OOLU34J4.js → chunk-H5ON7XTE.js} +125 -62
  33. package/dist/{chunk-PYKKM4MM.js → chunk-HMRVILWZ.js} +1 -1
  34. package/dist/{chunk-L6JPKANW.js → chunk-K5BXPM74.js} +1 -1
  35. package/dist/{chunk-ZRZ4SVWG.js → chunk-LLKDNPYV.js} +2 -2
  36. package/dist/{chunk-WSRBFHPX.js → chunk-LR2SKL5Y.js} +1 -1
  37. package/dist/{chunk-MPVES2IC.js → chunk-NP7TYFYR.js} +1 -1
  38. package/dist/{chunk-XQAYFRWT.js → chunk-OXE5ZUTS.js} +1 -1
  39. package/dist/{chunk-IFAHK54X.js → chunk-QTS66GMR.js} +2 -2
  40. package/dist/{chunk-NQLWOTY4.js → chunk-RCBUZGIT.js} +217 -199
  41. package/dist/{chunk-FPK7XY3F.js → chunk-UKGNSJQQ.js} +51 -42
  42. package/dist/{chunk-PZELBSHC.js → chunk-WBB22ANL.js} +20 -15
  43. package/dist/{chunk-QQIVLZW4.js → chunk-YJ44UT7D.js} +5 -5
  44. package/dist/{chunk-Z4G3WCP3.js → chunk-ZRSUCJGA.js} +1 -1
  45. package/dist/cli/chat.js +19 -19
  46. package/dist/cli/check.js +6 -6
  47. package/dist/cli/plugins.js +11 -11
  48. package/dist/cli/snapshot-warmup.js +8 -8
  49. package/dist/cli/upgrade.js +5 -5
  50. package/dist/{db-WXQOQESG.js → db-2ASK6MV6.js} +5 -5
  51. package/dist/instrumentation.js +2 -2
  52. package/dist/nitro.js +2 -2
  53. package/dist/{runner-4QY4XH4B.js → runner-L363K62Z.js} +12 -13
  54. package/dist/{skills-P5MU4EBX.js → skills-VCPG3NOO.js} +6 -6
  55. package/dist/{validation-PQF5OP6T.js → validation-GY7AJBLC.js} +6 -6
  56. package/dist/version.js +1 -1
  57. package/package.json +5 -5
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-MU6HHZEN.js";
5
5
  import {
6
6
  getStateAdapter
7
- } from "./chunk-PYKKM4MM.js";
7
+ } from "./chunk-HMRVILWZ.js";
8
8
  import {
9
9
  contextProvenance,
10
10
  createSqlConversationEventStore,
@@ -15,20 +15,17 @@ import {
15
15
  instructionProvenanceFor,
16
16
  sanitizePostgresJson,
17
17
  withConversationEventLock
18
- } from "./chunk-ZRZ4SVWG.js";
18
+ } from "./chunk-LLKDNPYV.js";
19
19
  import {
20
20
  sleep
21
21
  } from "./chunk-4ZNGQH7C.js";
22
22
  import {
23
23
  botConfig,
24
24
  escapeXml,
25
- getPiMessageRole,
26
25
  resolveGatewayModel,
27
- retainRuntimeTurnContext,
28
26
  standardModelId,
29
- stripRuntimeTurnContext,
30
- trimTrailingAssistantMessages
31
- } from "./chunk-NQLWOTY4.js";
27
+ unwrapCurrentInstruction
28
+ } from "./chunk-RCBUZGIT.js";
32
29
  import {
33
30
  toStoredSlackActor
34
31
  } from "./chunk-C4MZ3GP5.js";
@@ -37,7 +34,7 @@ import {
37
34
  logException,
38
35
  logWarn,
39
36
  setSpanAttributes
40
- } from "./chunk-J7APPQIJ.js";
37
+ } from "./chunk-36UJA3OD.js";
41
38
  import {
42
39
  isRecord,
43
40
  parseSlackMessageTs,
@@ -45,6 +42,111 @@ import {
45
42
  toOptionalString
46
43
  } from "./chunk-42WRQLJ6.js";
47
44
 
45
+ // src/chat/turn-context-tag.ts
46
+ var TURN_CONTEXT_TAG = "runtime-turn-context";
47
+
48
+ // src/chat/pi/transcript.ts
49
+ var RUNTIME_TURN_CONTEXT_START = `<${TURN_CONTEXT_TAG}>`;
50
+ function userMessageContent(message) {
51
+ const record = message;
52
+ return record.role === "user" && Array.isArray(record.content) ? record.content : void 0;
53
+ }
54
+ function isRuntimeTurnContextPart(part) {
55
+ return part !== null && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text.startsWith(RUNTIME_TURN_CONTEXT_START);
56
+ }
57
+ var EMBEDDED_THREAD_CONTEXT_TAGS = [
58
+ "recent-thread-messages",
59
+ "thread-compactions",
60
+ "thread-transcript",
61
+ "thread-background"
62
+ ];
63
+ var EMBEDDED_THREAD_CONTEXT_PATTERN = new RegExp(
64
+ `<(${EMBEDDED_THREAD_CONTEXT_TAGS.join("|")})(?:\\s[^>]*)?>[\\s\\S]*?</\\1>`,
65
+ "g"
66
+ );
67
+ function isAssistantMessage(value) {
68
+ return typeof value === "object" && value !== null && value.role === "assistant";
69
+ }
70
+ function isToolResultMessage(value) {
71
+ return typeof value === "object" && value !== null && value.role === "toolResult";
72
+ }
73
+ function isToolResultError(result) {
74
+ if (!result || typeof result !== "object") return false;
75
+ return Boolean(result.isError);
76
+ }
77
+ function normalizeToolNameFromResult(result) {
78
+ if (!result || typeof result !== "object") return void 0;
79
+ const record = result;
80
+ if (typeof record.toolName === "string" && record.toolName.length > 0) {
81
+ return record.toolName;
82
+ }
83
+ if (typeof record.name === "string" && record.name.length > 0) {
84
+ return record.name;
85
+ }
86
+ return void 0;
87
+ }
88
+ function getPiMessageRole(value) {
89
+ if (!value || typeof value !== "object") {
90
+ return void 0;
91
+ }
92
+ const role = value.role;
93
+ return typeof role === "string" ? role : void 0;
94
+ }
95
+ function isContinuablePiBoundary(messages) {
96
+ const lastRole = getPiMessageRole(messages.at(-1));
97
+ return lastRole === "user" || lastRole === "toolResult";
98
+ }
99
+ function extractAssistantText(message) {
100
+ const content = message.content ?? [];
101
+ return content.filter(
102
+ (part) => part.type === "text" && typeof part.text === "string"
103
+ ).map((part) => part.text).join("\n");
104
+ }
105
+ function getTerminalAssistantMessages(messages) {
106
+ let lastNonAssistantIndex = -1;
107
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
108
+ if (!isAssistantMessage(messages[index])) {
109
+ lastNonAssistantIndex = index;
110
+ break;
111
+ }
112
+ }
113
+ return messages.slice(lastNonAssistantIndex + 1).filter(isAssistantMessage);
114
+ }
115
+ function trimTrailingAssistantMessages(messages) {
116
+ let end = messages.length;
117
+ while (end > 0 && getPiMessageRole(messages[end - 1]) === "assistant") {
118
+ end -= 1;
119
+ }
120
+ return end === messages.length ? [...messages] : messages.slice(0, end);
121
+ }
122
+ function hasRuntimeTurnContext(messages) {
123
+ return messages.some(
124
+ (message) => userMessageContent(message)?.some(isRuntimeTurnContextPart)
125
+ );
126
+ }
127
+ function retainRuntimeTurnContext(messages) {
128
+ return messages.flatMap((message) => {
129
+ const runtimeContent = userMessageContent(message)?.filter(isRuntimeTurnContextPart) ?? [];
130
+ return runtimeContent.length > 0 ? [{ ...message, content: runtimeContent }] : [];
131
+ });
132
+ }
133
+ function instructionTextForProjection(text) {
134
+ const withoutContext = text.replace(EMBEDDED_THREAD_CONTEXT_PATTERN, "").trim();
135
+ return unwrapCurrentInstruction(withoutContext) ?? withoutContext;
136
+ }
137
+ function stripRuntimeTurnContext(messages) {
138
+ return messages.flatMap((message) => {
139
+ const content = userMessageContent(message);
140
+ if (!content) return [message];
141
+ const nextContent = content.filter(
142
+ (part) => !isRuntimeTurnContextPart(part)
143
+ );
144
+ if (nextContent.length === content.length) return [message];
145
+ if (nextContent.length === 0) return [];
146
+ return [{ ...message, content: nextContent }];
147
+ });
148
+ }
149
+
48
150
  // src/chat/conversations/projection.ts
49
151
  import { isDeepStrictEqual } from "util";
50
152
 
@@ -1033,13 +1135,9 @@ function addDurationMs(prior, current) {
1033
1135
  }, void 0);
1034
1136
  return total;
1035
1137
  }
1036
- function isContinuableBoundary(messages) {
1037
- const lastRole = getPiMessageRole(messages.at(-1));
1038
- return lastRole === "user" || lastRole === "toolResult";
1039
- }
1040
1138
  function resumableBoundary(messages, fallbackMessages) {
1041
1139
  const current = trimTrailingAssistantMessages(messages);
1042
- if (current.length > 0 && isContinuableBoundary(current)) {
1140
+ if (current.length > 0 && isContinuablePiBoundary(current)) {
1043
1141
  return current;
1044
1142
  }
1045
1143
  return trimTrailingAssistantMessages(fallbackMessages ?? []);
@@ -1059,7 +1157,7 @@ async function loadTurnSessionRecord(ctx) {
1059
1157
  };
1060
1158
  }
1061
1159
  async function persistRunningSessionRecord(args) {
1062
- if (args.messages.length === 0 || !isContinuableBoundary(args.messages)) {
1160
+ if (args.messages.length === 0 || !isContinuablePiBoundary(args.messages)) {
1063
1161
  return false;
1064
1162
  }
1065
1163
  try {
@@ -1184,7 +1282,7 @@ async function persistAuthPauseSessionRecord(args) {
1184
1282
  args.messages,
1185
1283
  latestSessionRecord?.piMessages
1186
1284
  );
1187
- if (piMessages.length > 0 && !isContinuableBoundary(piMessages)) {
1285
+ if (piMessages.length > 0 && !isContinuablePiBoundary(piMessages)) {
1188
1286
  return void 0;
1189
1287
  }
1190
1288
  return await upsertAgentTurnSessionRecord({
@@ -1241,7 +1339,7 @@ async function persistContinuationSessionRecord(args) {
1241
1339
  args.messages,
1242
1340
  latestSessionRecord?.piMessages
1243
1341
  );
1244
- if (piMessages.length === 0 || !isContinuableBoundary(piMessages)) {
1342
+ if (piMessages.length === 0 || !isContinuablePiBoundary(piMessages)) {
1245
1343
  return void 0;
1246
1344
  }
1247
1345
  const cumulativeDurationMs = addDurationMs(
@@ -1322,17 +1420,14 @@ async function persistContinuationSessionRecord(args) {
1322
1420
  }
1323
1421
  async function persistYieldSessionRecord(args) {
1324
1422
  try {
1423
+ const piMessages = [...args.messages];
1424
+ if (piMessages.length === 0 || !isContinuablePiBoundary(piMessages)) {
1425
+ return void 0;
1426
+ }
1325
1427
  const latestSessionRecord = await getAgentTurnSessionRecord(
1326
1428
  args.conversationId,
1327
1429
  args.sessionId
1328
1430
  );
1329
- const piMessages = resumableBoundary(
1330
- args.messages,
1331
- latestSessionRecord?.piMessages
1332
- );
1333
- if (piMessages.length === 0 || !isContinuableBoundary(piMessages)) {
1334
- return void 0;
1335
- }
1336
1431
  return await upsertAgentTurnSessionRecord({
1337
1432
  ...args.channelName ?? latestSessionRecord?.channelName ? { channelName: args.channelName ?? latestSessionRecord?.channelName } : {},
1338
1433
  conversationId: args.conversationId,
@@ -2533,6 +2628,20 @@ function isPendingAuthLatestRequest(conversation, pendingAuth) {
2533
2628
  }
2534
2629
 
2535
2630
  export {
2631
+ TURN_CONTEXT_TAG,
2632
+ isAssistantMessage,
2633
+ isToolResultMessage,
2634
+ isToolResultError,
2635
+ normalizeToolNameFromResult,
2636
+ getPiMessageRole,
2637
+ isContinuablePiBoundary,
2638
+ extractAssistantText,
2639
+ getTerminalAssistantMessages,
2640
+ trimTrailingAssistantMessages,
2641
+ hasRuntimeTurnContext,
2642
+ retainRuntimeTurnContext,
2643
+ instructionTextForProjection,
2644
+ stripRuntimeTurnContext,
2536
2645
  loadProjection,
2537
2646
  loadConversationProjection,
2538
2647
  openConversationProjection,
@@ -1,18 +1,28 @@
1
1
  import {
2
2
  CooperativeTurnYieldError,
3
3
  JUNIOR_THREAD_STATE_TTL_MS,
4
+ TURN_CONTEXT_TAG,
4
5
  TurnInputCommitLostError,
5
6
  TurnSliceLimitExceededError,
6
7
  abandonReplacedPendingAuth,
7
8
  canReusePendingAuthLink,
8
9
  estimateTextTokens,
10
+ extractAssistantText,
9
11
  getAgentContextCompactionTriggerTokens,
10
12
  getInterruptionMarker,
13
+ getPiMessageRole,
14
+ getTerminalAssistantMessages,
15
+ hasRuntimeTurnContext,
16
+ isAssistantMessage,
17
+ isContinuablePiBoundary,
18
+ isToolResultError,
19
+ isToolResultMessage,
11
20
  isTurnInputCommitLostError,
12
21
  loadConnectedMcpProviders,
13
22
  loadConversationProjection,
14
23
  loadTurnSessionRecord,
15
24
  mergeArtifactsState,
25
+ normalizeToolNameFromResult,
16
26
  openConversationProjection,
17
27
  persistAuthPauseSessionRecord,
18
28
  persistContinuationSessionRecord,
@@ -21,8 +31,11 @@ import {
21
31
  recordAuthorizationRequested,
22
32
  recordMcpProviderConnected,
23
33
  recordToolExecutionStarted,
34
+ retainRuntimeTurnContext,
35
+ stripRuntimeTurnContext,
36
+ trimTrailingAssistantMessages,
24
37
  updateConversationStats
25
- } from "./chunk-SL3ZKNLQ.js";
38
+ } from "./chunk-DXRPHBOU.js";
26
39
  import {
27
40
  buildNonInteractiveShellScript,
28
41
  createSandboxSession,
@@ -39,7 +52,7 @@ import {
39
52
  runNonInteractiveCommand,
40
53
  throwSandboxOperationError,
41
54
  wrapSandboxSetupError
42
- } from "./chunk-B45FPP2A.js";
55
+ } from "./chunk-4VKFQPCW.js";
43
56
  import {
44
57
  addAgentTurnUsage,
45
58
  hasAgentTurnUsage
@@ -56,7 +69,7 @@ import {
56
69
  getPlugins,
57
70
  getSlackToolContext,
58
71
  resolveChannelCapabilities
59
- } from "./chunk-QQIVLZW4.js";
72
+ } from "./chunk-YJ44UT7D.js";
60
73
  import {
61
74
  SANDBOX_DATA_ROOT,
62
75
  SANDBOX_SKILLS_ROOT,
@@ -65,7 +78,7 @@ import {
65
78
  getStateAdapter,
66
79
  sandboxSkillDir,
67
80
  sandboxSkillFile
68
- } from "./chunk-PYKKM4MM.js";
81
+ } from "./chunk-HMRVILWZ.js";
69
82
  import {
70
83
  SlackActionError,
71
84
  downloadPrivateSlackFile,
@@ -75,7 +88,7 @@ import {
75
88
  isDmChannel,
76
89
  normalizeSlackConversationId,
77
90
  withSlackRetries
78
- } from "./chunk-IFAHK54X.js";
91
+ } from "./chunk-QTS66GMR.js";
79
92
  import {
80
93
  contextProvenance,
81
94
  getConversationEventStore,
@@ -85,7 +98,7 @@ import {
85
98
  instructionActors,
86
99
  instructionProvenanceFor,
87
100
  parseDestination
88
- } from "./chunk-ZRZ4SVWG.js";
101
+ } from "./chunk-LLKDNPYV.js";
89
102
  import {
90
103
  sleep
91
104
  } from "./chunk-4ZNGQH7C.js";
@@ -99,36 +112,25 @@ import {
99
112
  MODEL_HANDOFF_SUMMARY_PREFIX,
100
113
  ModelProfileNotConfiguredError,
101
114
  STANDARD_MODEL_PROFILE,
102
- TURN_CONTEXT_TAG,
103
115
  TURN_REASONING_LEVELS,
104
116
  botConfig,
105
117
  completeObject,
106
118
  completeText,
119
+ createProviderError,
107
120
  escapeXml,
108
- extractAssistantText,
109
121
  getGatewayApiKey,
110
122
  getPiGatewayApiKey,
111
- getTerminalAssistantMessages,
112
123
  hasCompactedConversationContext,
113
- hasRuntimeTurnContext,
114
- isAssistantMessage,
115
124
  isCompactionSummaryText,
116
125
  isProviderRetryError,
117
- isToolResultError,
118
- isToolResultMessage,
119
126
  modelIdForProfile,
120
127
  modelProfileSchema,
121
- nextProviderRetry,
122
128
  normalizeSlackEmojiName,
123
- normalizeToolNameFromResult,
124
129
  profileConfig,
125
130
  renderCurrentInstruction,
126
131
  resolveGatewayModel,
127
- retainRuntimeTurnContext,
128
- stripRuntimeTurnContext,
129
- trimTrailingAssistantMessages,
130
132
  unwrapCurrentInstruction
131
- } from "./chunk-NQLWOTY4.js";
133
+ } from "./chunk-RCBUZGIT.js";
132
134
  import {
133
135
  parseSlackThreadId,
134
136
  resolveConversationPrivacy,
@@ -144,17 +146,17 @@ import {
144
146
  findSkillByName,
145
147
  loadSkillsByName,
146
148
  parseSkillInvocation
147
- } from "./chunk-BTRNMS6A.js";
149
+ } from "./chunk-4WZ7YKDF.js";
148
150
  import {
149
151
  pluginCatalogRuntime
150
- } from "./chunk-WSRBFHPX.js";
152
+ } from "./chunk-LR2SKL5Y.js";
151
153
  import {
152
154
  CredentialUnavailableError,
153
155
  credentialContextSchema,
154
156
  credentialUserSubjectId,
155
157
  resolveAuthTokenPlaceholder,
156
158
  resolvePluginCommandEnv
157
- } from "./chunk-XQAYFRWT.js";
159
+ } from "./chunk-OXE5ZUTS.js";
158
160
  import {
159
161
  isUserActor
160
162
  } from "./chunk-C4MZ3GP5.js";
@@ -175,7 +177,7 @@ import {
175
177
  summarizeMessageText,
176
178
  withLogContext,
177
179
  withSpan
178
- } from "./chunk-J7APPQIJ.js";
180
+ } from "./chunk-36UJA3OD.js";
179
181
  import {
180
182
  isRecord,
181
183
  parseSlackChannelId,
@@ -274,7 +276,6 @@ function shouldPropagateSandboxEgressTrace(host, config = {}) {
274
276
 
275
277
  // src/chat/agent/index.ts
276
278
  import { Agent } from "@earendil-works/pi-agent-core";
277
- import { isRetryableAssistantError } from "@earendil-works/pi-ai";
278
279
 
279
280
  // src/chat/sandbox/skill-sandbox.ts
280
281
  import fs from "fs/promises";
@@ -613,6 +614,9 @@ function shouldEmitDevAgentTrace() {
613
614
  return process.env.NODE_ENV === "development";
614
615
  }
615
616
 
617
+ // src/chat/services/turn-result.ts
618
+ import { isRetryableAssistantError } from "@earendil-works/pi-ai";
619
+
616
620
  // src/chat/no-reply.ts
617
621
  var NO_REPLY_MARKER = "[[NO_REPLY]]";
618
622
  function isNoReplyMarker(text) {
@@ -827,7 +831,10 @@ function buildTurnResult(input) {
827
831
  usage,
828
832
  stopReason,
829
833
  errorMessage,
830
- providerError: void 0
834
+ providerError: resolvedOutcome === "provider_error" && errorMessage ? createProviderError(errorMessage, {
835
+ modelId,
836
+ retryable: lastAssistant !== void 0 && isAssistantMessage(lastAssistant) && isRetryableAssistantError(lastAssistant)
837
+ }) : void 0
831
838
  };
832
839
  return {
833
840
  text: primaryText,
@@ -838,6 +845,40 @@ function buildTurnResult(input) {
838
845
  };
839
846
  }
840
847
 
848
+ // src/chat/services/provider-retry.ts
849
+ import {
850
+ isRetryableAssistantError as isRetryableAssistantError2
851
+ } from "@earendil-works/pi-ai";
852
+ var PROVIDER_RETRY_DELAYS_MS = [2e3, 4e3, 8e3];
853
+ var MAX_PROVIDER_RETRY_DELAY_MS = 6e4;
854
+ function nextProviderRetry(args) {
855
+ const backoffMs = PROVIDER_RETRY_DELAYS_MS[args.attempt];
856
+ const errorMessage = args.failure?.errorMessage;
857
+ if (backoffMs === void 0 || !args.failure || !errorMessage) {
858
+ return void 0;
859
+ }
860
+ const providerError = createProviderError(errorMessage, {
861
+ retryable: true
862
+ });
863
+ const hasRetrySignal = isRetryableAssistantError2(args.failure) || providerError.status === 408;
864
+ if (!hasRetrySignal || !providerError.retryable) {
865
+ return void 0;
866
+ }
867
+ const delayMs = Math.min(
868
+ MAX_PROVIDER_RETRY_DELAY_MS,
869
+ Math.max(backoffMs, providerError.retryAfterMs ?? 0)
870
+ );
871
+ const messages = trimTrailingAssistantMessages(args.messages);
872
+ if (messages.length === args.messages.length) {
873
+ return void 0;
874
+ }
875
+ const tailRole = getPiMessageRole(messages.at(-1));
876
+ if (tailRole !== "user" && tailRole !== "toolResult") {
877
+ return void 0;
878
+ }
879
+ return { delayMs, messages };
880
+ }
881
+
841
882
  // src/chat/tool-support/structured-result.ts
842
883
  import { z } from "zod";
843
884
  var juniorToolContinuationSchema = z.object({
@@ -1201,7 +1242,8 @@ var AuthorizationPauseError = class extends Error {
1201
1242
  kind;
1202
1243
  provider;
1203
1244
  providerDisplayName;
1204
- constructor(kind, provider, providerDisplayName, disposition) {
1245
+ requestText;
1246
+ constructor(kind, provider, providerDisplayName, disposition, requestText) {
1205
1247
  super(
1206
1248
  kind === "mcp" ? `MCP authorization started for ${provider}` : `Plugin authorization started for ${provider}`
1207
1249
  );
@@ -1210,6 +1252,7 @@ var AuthorizationPauseError = class extends Error {
1210
1252
  this.kind = kind;
1211
1253
  this.provider = provider;
1212
1254
  this.providerDisplayName = providerDisplayName;
1255
+ this.requestText = requestText;
1213
1256
  }
1214
1257
  };
1215
1258
  var AuthPausePersistenceError = class extends Error {
@@ -8317,6 +8360,11 @@ async function deliverResourceEventSubscription(input) {
8317
8360
  // src/chat/tools/resource-events.ts
8318
8361
  var DEFAULT_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
8319
8362
  var MAX_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
8363
+ var STOP_WATCHING_TOOL_NAME = "stopWatchingResources";
8364
+ var RESOURCE_WATCH_TOOL_SOURCE = {
8365
+ id: "resource-watches",
8366
+ description: "Inspect or stop resource watches for the current conversation."
8367
+ };
8320
8368
  var subscribeInputSchema = z18.object({
8321
8369
  resourceRef: z18.string().describe("Opaque resource ref copied from a subscribable tool result."),
8322
8370
  provider: z18.string().describe("Provider that owns the resource ref."),
@@ -8332,11 +8380,6 @@ var subscribeInputSchema = z18.object({
8332
8380
  "How long to keep the subscription active. Defaults to 14 days and is capped at 30 days."
8333
8381
  ).optional()
8334
8382
  });
8335
- var cancelInputSchema = z18.object({
8336
- subscriptionId: z18.string().describe(
8337
- "Subscription id returned by subscribeToResourceEvents or listResourceEventSubscriptions."
8338
- )
8339
- });
8340
8383
  function requireConversationContext(context) {
8341
8384
  if (!context.conversationId) {
8342
8385
  throw new Error("Resource event subscriptions require a conversation");
@@ -8403,7 +8446,14 @@ function createSubscribeToResourceEventsTool(context) {
8403
8446
  subscription_status: subscription.status,
8404
8447
  resourceRef: subscription.resourceRef,
8405
8448
  events: subscription.events,
8406
- expiresAtMs: subscription.expiresAtMs
8449
+ expiresAtMs: subscription.expiresAtMs,
8450
+ stop_watching: {
8451
+ execution_tool: "executeTool",
8452
+ execution_example: {
8453
+ tool_name: STOP_WATCHING_TOOL_NAME,
8454
+ arguments: {}
8455
+ }
8456
+ }
8407
8457
  };
8408
8458
  return {
8409
8459
  ok: true,
@@ -8417,6 +8467,8 @@ function createSubscribeToResourceEventsTool(context) {
8417
8467
  function createListResourceEventSubscriptionsTool(context) {
8418
8468
  return zodTool({
8419
8469
  description: "List active resource event subscriptions for the current conversation.",
8470
+ exposure: "deferred",
8471
+ source: RESOURCE_WATCH_TOOL_SOURCE,
8420
8472
  inputSchema: z18.object({}),
8421
8473
  outputSchema: juniorToolResultSchema,
8422
8474
  async execute() {
@@ -8445,23 +8497,18 @@ function createListResourceEventSubscriptionsTool(context) {
8445
8497
  }
8446
8498
  });
8447
8499
  }
8448
- function createCancelResourceEventSubscriptionTool(context) {
8500
+ function createStopWatchingResourcesTool(context) {
8449
8501
  return zodTool({
8450
- description: "Cancel a resource event subscription for the current conversation.",
8451
- inputSchema: cancelInputSchema,
8502
+ description: "Stop every resource watch for the current conversation. Infer the user's intent from context instead of requiring a special command, and call this tool before confirming that watching stopped.",
8503
+ exposure: "deferred",
8504
+ source: RESOURCE_WATCH_TOOL_SOURCE,
8505
+ inputSchema: z18.object({}),
8452
8506
  outputSchema: juniorToolResultSchema,
8453
- async execute(input) {
8507
+ async execute() {
8454
8508
  const conversationId = requireConversationContext(context);
8455
- const subscription = await cancelResourceEventSubscription({
8456
- conversationId,
8457
- id: input.subscriptionId
8458
- });
8459
- if (!subscription) {
8460
- throw new Error("Resource event subscription was not found");
8461
- }
8509
+ await cancelSubscriptions({ conversationId });
8462
8510
  const details = {
8463
- id: subscription.id,
8464
- subscription_status: subscription.status
8511
+ watching_status: "stopped"
8465
8512
  };
8466
8513
  return {
8467
8514
  ok: true,
@@ -8472,6 +8519,16 @@ function createCancelResourceEventSubscriptionTool(context) {
8472
8519
  }
8473
8520
  });
8474
8521
  }
8522
+ function createResourceEventTools(context) {
8523
+ if (!canUseResourceEventSubscriptionTools(context)) {
8524
+ return {};
8525
+ }
8526
+ return {
8527
+ subscribeToResourceEvents: createSubscribeToResourceEventsTool(context),
8528
+ listResourceEventSubscriptions: createListResourceEventSubscriptionsTool(context),
8529
+ [STOP_WATCHING_TOOL_NAME]: createStopWatchingResourcesTool(context)
8530
+ };
8531
+ }
8475
8532
 
8476
8533
  // src/chat/slack/channel.ts
8477
8534
  async function listChannelMessages(input) {
@@ -11409,7 +11466,8 @@ function createTools(availableSkills, hooks = {}, context) {
11409
11466
  ),
11410
11467
  webFetch: createWebFetchTool(hooks, {
11411
11468
  canSendFilesToActiveConversation
11412
- })
11469
+ }),
11470
+ ...createResourceEventTools(context)
11413
11471
  };
11414
11472
  if (hooks.writeGeneratedArtifacts) {
11415
11473
  tools.imageGenerate = createImageGenerateTool(
@@ -11426,11 +11484,6 @@ function createTools(availableSkills, hooks = {}, context) {
11426
11484
  if (context.handoff) {
11427
11485
  tools.handoff = createHandoffTool(context.handoff);
11428
11486
  }
11429
- if (canUseResourceEventSubscriptionTools(context)) {
11430
- tools.subscribeToResourceEvents = createSubscribeToResourceEventsTool(context);
11431
- tools.listResourceEventSubscriptions = createListResourceEventSubscriptionsTool(context);
11432
- tools.cancelResourceEventSubscription = createCancelResourceEventSubscriptionTool(context);
11433
- }
11434
11487
  if (context.mcpToolManager) {
11435
11488
  tools.searchMcpTools = createSearchMcpToolsTool(context.mcpToolManager);
11436
11489
  tools.callMcpTool = createCallMcpToolTool(context.mcpToolManager);
@@ -11845,8 +11898,8 @@ import { PluginToolInputError } from "@sentry/junior-plugin-api";
11845
11898
 
11846
11899
  // src/chat/services/plugin-auth-orchestration.ts
11847
11900
  var PluginAuthorizationPauseError = class extends AuthorizationPauseError {
11848
- constructor(provider, providerDisplayName, disposition) {
11849
- super("plugin", provider, providerDisplayName, disposition);
11901
+ constructor(provider, providerDisplayName, disposition, requestText) {
11902
+ super("plugin", provider, providerDisplayName, disposition, requestText);
11850
11903
  }
11851
11904
  };
11852
11905
  var PluginCredentialFailureError = class extends Error {
@@ -11957,7 +12010,8 @@ function createPluginAuthOrchestration(input) {
11957
12010
  pendingPause = new PluginAuthorizationPauseError(
11958
12011
  provider,
11959
12012
  providerLabel,
11960
- reusingPendingLink ? "link_already_sent" : "link_sent"
12013
+ reusingPendingLink ? "link_already_sent" : "link_sent",
12014
+ input.userMessage
11961
12015
  );
11962
12016
  input.abortAgent();
11963
12017
  throw pendingPause;
@@ -12094,10 +12148,12 @@ import { z as z41 } from "zod";
12094
12148
  var EXECUTE_TOOL_NAME = "executeTool";
12095
12149
  function createExecuteToolTool() {
12096
12150
  return zodTool({
12097
- description: "Execute any catalog tool by exact tool_name from searchTools. Put tool-specific parameters inside arguments.",
12151
+ description: "Execute any catalog tool by exact tool_name from searchTools or a tool-result execution hint. Put tool-specific parameters inside arguments.",
12098
12152
  executionMode: "sequential",
12099
12153
  inputSchema: z41.object({
12100
- tool_name: z41.string().min(1).describe("Exact catalog tool_name returned by searchTools."),
12154
+ tool_name: z41.string().min(1).describe(
12155
+ "Exact catalog tool_name returned by searchTools or a tool-result execution hint."
12156
+ ),
12101
12157
  arguments: z41.record(z41.string(), z41.unknown()).describe(
12102
12158
  'Arguments matching the selected catalog tool schema, for example { "query": "..." }.'
12103
12159
  ).optional()
@@ -13187,8 +13243,8 @@ async function finalizeMcpAuthorization(provider, authSessionId, authorizationCo
13187
13243
 
13188
13244
  // src/chat/services/mcp-auth-orchestration.ts
13189
13245
  var McpAuthorizationPauseError = class extends AuthorizationPauseError {
13190
- constructor(provider, providerDisplayName, disposition) {
13191
- super("mcp", provider, providerDisplayName, disposition);
13246
+ constructor(provider, providerDisplayName, disposition, requestText) {
13247
+ super("mcp", provider, providerDisplayName, disposition, requestText);
13192
13248
  }
13193
13249
  };
13194
13250
  function authorizationId2(args) {
@@ -13319,7 +13375,8 @@ function createMcpAuthOrchestration(input) {
13319
13375
  pendingPause = new McpAuthorizationPauseError(
13320
13376
  provider,
13321
13377
  providerLabel,
13322
- reusingPendingLink ? "link_already_sent" : "link_sent"
13378
+ reusingPendingLink ? "link_already_sent" : "link_sent",
13379
+ input.userMessage
13323
13380
  );
13324
13381
  input.abortAgent();
13325
13382
  return true;
@@ -14408,6 +14465,7 @@ async function wireAgentTools(args) {
14408
14465
  destination: args.routing.destination,
14409
14466
  source: runSource,
14410
14467
  threadTs: args.routing.source.platform === "slack" ? args.routing.source.threadTs : void 0,
14468
+ userMessage: args.userInput,
14411
14469
  pendingAuth: args.state.pendingAuth,
14412
14470
  recordPendingAuth: args.durability.recordPendingAuth,
14413
14471
  authorizationFlowMode: args.policy.authorizationFlowMode,
@@ -14699,7 +14757,11 @@ function createResumeState(args) {
14699
14757
  if (!args.durability.shouldYield?.()) {
14700
14758
  return void 0;
14701
14759
  }
14702
- resumeMessages = this.getResumeSnapshot(currentMessages);
14760
+ const nextResumeMessages = this.getResumeSnapshot(currentMessages);
14761
+ if (!isContinuablePiBoundary(nextResumeMessages)) {
14762
+ return void 0;
14763
+ }
14764
+ resumeMessages = nextResumeMessages;
14703
14765
  return new CooperativeTurnYieldError(
14704
14766
  `Agent turn yielded at a safe boundary after ${currentDurationMs()}ms`
14705
14767
  );
@@ -14723,6 +14785,7 @@ function createResumeState(args) {
14723
14785
  return {
14724
14786
  status: "awaiting_auth",
14725
14787
  providerDisplayName: pause.providerDisplayName,
14788
+ ...pause.requestText ? { requestText: pause.requestText } : {},
14726
14789
  ...usage ? { usage } : {}
14727
14790
  };
14728
14791
  } catch (error) {
@@ -15913,8 +15976,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
15913
15976
  }
15914
15977
  const providerRetry = nextProviderRetry({
15915
15978
  attempt,
15916
- messages: agent.state.messages,
15917
- retryableFailure: lastAssistant !== void 0 && isRetryableAssistantError(lastAssistant)
15979
+ failure: lastAssistant,
15980
+ messages: agent.state.messages
15918
15981
  });
15919
15982
  if (!providerRetry) {
15920
15983
  break;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getChatConfig
3
- } from "./chunk-NQLWOTY4.js";
3
+ } from "./chunk-RCBUZGIT.js";
4
4
 
5
5
  // src/chat/state/adapter.ts
6
6
  import { createMemoryState } from "@chat-adapter/state-memory";