@sentry/junior 0.203.0 → 0.205.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 (174) hide show
  1. package/dist/agent-D4nu8MQV.js +17521 -0
  2. package/dist/agent-hooks-DXHpTJ4m.js +4042 -0
  3. package/dist/agent-runner-C04colea.js +678 -0
  4. package/dist/api/schema.d.ts +2736 -2639
  5. package/dist/api/schema.js +4 -169
  6. package/dist/api.d.ts +23 -17
  7. package/dist/api.js +3881 -5326
  8. package/dist/app-Cb776lL8.d.ts +247 -0
  9. package/dist/app.d.ts +4 -520
  10. package/dist/app.js +9524 -11875
  11. package/dist/auth-pause-state-C2P3guS1.js +168 -0
  12. package/dist/catalog-runtime-CXw3asJD.js +7 -0
  13. package/dist/checkpoint-CrViJ8Ps.js +2450 -0
  14. package/dist/cli/chat.d.ts +20 -0
  15. package/dist/cli/chat.js +229 -336
  16. package/dist/cli/check.d.ts +8 -0
  17. package/dist/cli/check.js +513 -806
  18. package/dist/cli/env.d.ts +13 -0
  19. package/dist/cli/env.js +63 -12
  20. package/dist/cli/init.d.ts +3 -0
  21. package/dist/cli/init.js +90 -159
  22. package/dist/cli/main.d.ts +6 -0
  23. package/dist/cli/main.js +43 -64
  24. package/dist/cli/plugins.d.ts +13 -0
  25. package/dist/cli/plugins.js +148 -227
  26. package/dist/cli/run.d.ts +16 -0
  27. package/dist/cli/run.js +52 -8
  28. package/dist/cli/snapshot-create.d.ts +4 -0
  29. package/dist/cli/snapshot-create.js +71 -125
  30. package/dist/cli/upgrade.d.ts +15 -0
  31. package/dist/cli/upgrade.js +232 -335
  32. package/dist/config-BOtJQ7Pc.js +941 -0
  33. package/dist/context-B45_WqVX.js +298 -0
  34. package/dist/conversation-privacy-BZRA6Pes.js +182 -0
  35. package/dist/conversation-work-C6y3T5Hx.js +51 -0
  36. package/dist/credential-sync-Bep34IB_.js +2661 -0
  37. package/dist/db-BeyXKJOI.d.ts +5 -0
  38. package/dist/destinations-BeBiJeEM.js +29 -0
  39. package/dist/execution-stats-B6lgWxCK.js +373 -0
  40. package/dist/executor-BlUhFL7_.js +721 -0
  41. package/dist/experimental-CIXf7Uye.js +46 -0
  42. package/dist/history-ClE4toxe.d.ts +32 -0
  43. package/dist/history-CqTuSAdI.js +441 -0
  44. package/dist/instrumentation.d.ts +3 -3
  45. package/dist/instrumentation.js +130 -176
  46. package/dist/job-queue-DLMqIK74.js +63 -0
  47. package/dist/logging-BMJzdDlP.js +1210 -0
  48. package/dist/model-profile-CZmVoGdX.js +49 -0
  49. package/dist/nitro.d.ts +31 -36
  50. package/dist/nitro.js +275 -456
  51. package/dist/oauth-callback-server-WwG5_Zgm.js +130 -0
  52. package/dist/oauth-relay-CdCnu80W.js +62 -0
  53. package/dist/package-discovery-7a9YqLhE.js +455 -0
  54. package/dist/pending-auth-CUbXq06G.js +185 -0
  55. package/dist/plugin-module-BKGOXca2.js +81 -0
  56. package/dist/plugins-BI9A1vKA.d.ts +95 -0
  57. package/dist/plugins-egKWjgue.js +99 -0
  58. package/dist/private-trace-result-BLvBjy_e.js +16 -0
  59. package/dist/profile-T0tXE4zu.js +861 -0
  60. package/dist/registry-BA0__8ai.js +1419 -0
  61. package/dist/reporting-schema-DosTN__Q.js +105 -0
  62. package/dist/resolve-bvD1ORdv.js +546 -0
  63. package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
  64. package/dist/runner-BXYxfIUL.js +392 -0
  65. package/dist/sandbox-egress-signals-ngEPjSEW.js +46 -0
  66. package/dist/schema-Rn8-XEaN.js +1140 -0
  67. package/dist/sentry-CD3SdJl-.js +26 -0
  68. package/dist/skills-DJOlYdBs.js +316 -0
  69. package/dist/spawn-h0R1bTEo.js +29 -0
  70. package/dist/stats-3YZn-Swi.js +2648 -0
  71. package/dist/store-C5qxF2ac.d.ts +208 -0
  72. package/dist/task-queue-CoXwd2eq.js +136 -0
  73. package/dist/task-runner-B2_mJZj0.js +639 -0
  74. package/dist/thread-state-CqZ1m-es.js +431 -0
  75. package/dist/turn-execution-fI6PZ0iI.js +47 -0
  76. package/dist/turn-lifecycle-CcnwrOcp.js +54 -0
  77. package/dist/usage-B5SfMb3H.js +296 -0
  78. package/dist/usage-schema-CKaDkH_j.js +20 -0
  79. package/dist/validation-DfWcvhuS.js +40 -0
  80. package/dist/vercel-queue-DIkVcfK4.js +167 -0
  81. package/dist/vercel.d.ts +6 -6
  82. package/dist/vercel.js +14 -6
  83. package/dist/version-CnXZ614E.d.ts +5 -0
  84. package/dist/version-oD-oPrbO.js +8 -0
  85. package/dist/version.d.ts +2 -4
  86. package/dist/version.js +2 -6
  87. package/dist/web-authorization-Crbzlmzo.js +76 -0
  88. package/dist/web-input-BOuq3oKK.js +494 -0
  89. package/dist/work-B91LQKHr.js +509 -0
  90. package/dist/worker-BcRRTe6k.js +625 -0
  91. package/package.json +9 -9
  92. package/dist/agent-hooks-GB2VPTNA.js +0 -51
  93. package/dist/catalog-runtime-UBLIWD3O.js +0 -14
  94. package/dist/chunk-2LYHWMR4.js +0 -46
  95. package/dist/chunk-352OWAZH.js +0 -320
  96. package/dist/chunk-3Y47VMHV.js +0 -6
  97. package/dist/chunk-3YJSKOWF.js +0 -164
  98. package/dist/chunk-4KSSKTQ5.js +0 -229
  99. package/dist/chunk-4UO6FK4G.js +0 -64
  100. package/dist/chunk-5AHX53NQ.js +0 -717
  101. package/dist/chunk-5J3E5FWA.js +0 -700
  102. package/dist/chunk-5PDAG6O3.js +0 -206
  103. package/dist/chunk-6Y5B5PEX.js +0 -80
  104. package/dist/chunk-7GWQ5S5R.js +0 -2086
  105. package/dist/chunk-7H2VZTWN.js +0 -103
  106. package/dist/chunk-7NL7T6VU.js +0 -406
  107. package/dist/chunk-A5L27LE4.js +0 -387
  108. package/dist/chunk-ADIAWL34.js +0 -81
  109. package/dist/chunk-ASTEMBKJ.js +0 -519
  110. package/dist/chunk-CEMMLV5L.js +0 -98
  111. package/dist/chunk-CM5HNV2W.js +0 -131
  112. package/dist/chunk-CRTRBBRI.js +0 -105
  113. package/dist/chunk-DA2KGZZI.js +0 -13
  114. package/dist/chunk-DIB4GX3G.js +0 -8
  115. package/dist/chunk-DKIJ2RP5.js +0 -68
  116. package/dist/chunk-DWPN6SCH.js +0 -172
  117. package/dist/chunk-EDKUFGPL.js +0 -64
  118. package/dist/chunk-ENY6SKIU.js +0 -1228
  119. package/dist/chunk-F4MGCZOX.js +0 -2943
  120. package/dist/chunk-FA6POGLH.js +0 -70
  121. package/dist/chunk-FSUR7GTG.js +0 -20475
  122. package/dist/chunk-GKEOHJL5.js +0 -1856
  123. package/dist/chunk-GMCB6W5Y.js +0 -333
  124. package/dist/chunk-IE2VPG7O.js +0 -1135
  125. package/dist/chunk-IZ5B5IHQ.js +0 -3656
  126. package/dist/chunk-JAL3CH4G.js +0 -27
  127. package/dist/chunk-KIIEUXD3.js +0 -1764
  128. package/dist/chunk-KXU4NIL7.js +0 -692
  129. package/dist/chunk-MTM5IFCY.js +0 -1190
  130. package/dist/chunk-N7TMSOZH.js +0 -235
  131. package/dist/chunk-NCEBK6PH.js +0 -36
  132. package/dist/chunk-NHJU2ZAL.js +0 -56
  133. package/dist/chunk-P6KTRNVC.js +0 -321
  134. package/dist/chunk-PDO5BLNM.js +0 -22
  135. package/dist/chunk-PDRNLLFT.js +0 -3295
  136. package/dist/chunk-PEQXYSSE.js +0 -45
  137. package/dist/chunk-PKEX2AQX.js +0 -198
  138. package/dist/chunk-PSJCGIGO.js +0 -1163
  139. package/dist/chunk-PZUSUL55.js +0 -506
  140. package/dist/chunk-R45M4TUS.js +0 -37
  141. package/dist/chunk-RC745GGZ.js +0 -122
  142. package/dist/chunk-SP3QKZXJ.js +0 -820
  143. package/dist/chunk-TXKUKMVO.js +0 -417
  144. package/dist/chunk-UE4GPWSD.js +0 -931
  145. package/dist/chunk-UIE3R5XU.js +0 -17
  146. package/dist/chunk-UXPG6ZIN.js +0 -84
  147. package/dist/chunk-VFUK3X5B.js +0 -50
  148. package/dist/chunk-VNMJWREK.js +0 -787
  149. package/dist/chunk-VZ7CSOX2.js +0 -706
  150. package/dist/chunk-WCNQJKFT.js +0 -10
  151. package/dist/chunk-WDZR3QQM.js +0 -135
  152. package/dist/chunk-WLYVJCHV.js +0 -1433
  153. package/dist/chunk-WS7NAFTM.js +0 -1520
  154. package/dist/chunk-X6GDDWQH.js +0 -60
  155. package/dist/chunk-XPDEYNQI.js +0 -102
  156. package/dist/chunk-XRW44VGM.js +0 -58
  157. package/dist/chunk-Y2CM7HXH.js +0 -111
  158. package/dist/chunk-Y7X25LFY.js +0 -15
  159. package/dist/conversation-work-VIOQ5ZF3.js +0 -54
  160. package/dist/db-NGDJV7YH.js +0 -26
  161. package/dist/discovery-DWVDM7UK.js +0 -44
  162. package/dist/experimental-P5FZM4CU.js +0 -12
  163. package/dist/oauth-callback-server-YFY7YEGK.js +0 -243
  164. package/dist/oauth-relay-5XPVRPYB.js +0 -8
  165. package/dist/plugins-YTYJMMJF.js +0 -14
  166. package/dist/runner-ORTNSB2Q.js +0 -522
  167. package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
  168. package/dist/sentry-MB3NL3IR.js +0 -42
  169. package/dist/skills-H376WQOH.js +0 -27
  170. package/dist/spawn-T43WHLOS.js +0 -42
  171. package/dist/task-runner-LBZWF32V.js +0 -36
  172. package/dist/validation-REJLRKI6.js +0 -17
  173. package/dist/work-3KJ3RE76.js +0 -51
  174. package/dist/worker-QFEBU72E.js +0 -24
@@ -0,0 +1,625 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
2
+ import { P as isProviderRetryError, i as getChatConfig } from "./config-BOtJQ7Pc.js";
3
+ import { S as withLogContext, d as logInfo, f as logWarn, u as logException } from "./logging-BMJzdDlP.js";
4
+ import { At as recordConversationRetry, Bt as isFinalAttempt, Ct as drainConversationMailbox, Et as getConversationWorkState, Ft as startConversationWork, Nt as requestAnotherSlice, St as deadLetterAttempt, Vt as isInvalidConversationRecordError, _t as clearConsumedConversationWake, bt as completeConversationWork, dt as ackMessages, gt as checkInConversationWork, jt as releaseConversationWork, kt as recordAttemptFailure, mt as beginConversationResume, wt as ensureConversationWake, xt as countPendingConversationMessages, yt as completeConversationStop } from "./stats-3YZn-Swi.js";
5
+ import { c as ConversationQueueMessageRejectedError } from "./vercel-queue-DIkVcfK4.js";
6
+ import { a as getTurnRequestDeadline } from "./job-queue-DLMqIK74.js";
7
+ //#region src/chat/task-execution/worker.ts
8
+ var worker_exports = /* @__PURE__ */ __exportAll({
9
+ CONVERSATION_WORK_DEFER_DELAY_MS: () => CONVERSATION_WORK_DEFER_DELAY_MS,
10
+ processConversationWork: () => processConversationWork
11
+ });
12
+ const CONVERSATION_WORK_DEFER_DELAY_MS = 15e3;
13
+ const CONVERSATION_STOP_CHECK_INTERVAL_MS = 500;
14
+ function now(options) {
15
+ return options.nowMs?.() ?? Date.now();
16
+ }
17
+ function selectContiguousTurnBatch(messages) {
18
+ const first = messages[0];
19
+ if (!first) return [];
20
+ const nextTurnIndex = messages.findIndex((message) => message.input.authorId !== first.input.authorId || message.source !== first.source);
21
+ return messages.slice(0, nextTurnIndex === -1 ? messages.length : nextTurnIndex);
22
+ }
23
+ /** Prioritize interrupts while keeping each attempt to one Actor and Source. */
24
+ function selectAttemptMessages(work) {
25
+ const messages = work.messages;
26
+ const interrupts = messages.filter((message) => message.delivery === "interrupt");
27
+ if (interrupts.length > 0) return selectContiguousTurnBatch(interrupts);
28
+ return work.execution.status === "paused" ? [] : selectContiguousTurnBatch(messages);
29
+ }
30
+ function nudgeIdempotencyKey(reason, conversationId, nowMs) {
31
+ return `${reason}:${conversationId}:${nowMs}`;
32
+ }
33
+ async function requestLostLeaseRecovery(args) {
34
+ const before = await getConversationWorkState({
35
+ conversationId: args.conversationId,
36
+ state: args.options.state
37
+ });
38
+ const retry = await recordConversationRetry({
39
+ conversationId: args.conversationId,
40
+ leaseToken: args.leaseToken,
41
+ conversationStore: args.options.conversationStore,
42
+ nowMs: args.nowMs,
43
+ state: args.options.state
44
+ });
45
+ if (retry === "lost_lease") return;
46
+ if (retry === "stopped") {
47
+ logException(/* @__PURE__ */ new Error("Conversation work stopped after repeated failed attempts"), "conversation.work.retry.exhausted", {
48
+ "app.run.id": before?.execution.runId ?? "unknown",
49
+ "app.worker.last_progress_at_ms": before?.execution.lastProgressAtMs ?? before?.createdAtMs ?? 0,
50
+ "app.worker.retry_count": (before?.execution.retryCount ?? 0) + 1
51
+ });
52
+ return;
53
+ }
54
+ if (!await requestAnotherSlice({
55
+ conversationId: args.conversationId,
56
+ destination: args.destination,
57
+ leaseToken: args.leaseToken,
58
+ conversationStore: args.options.conversationStore,
59
+ nowMs: args.nowMs,
60
+ state: args.options.state
61
+ })) return;
62
+ if (!await releaseConversationWork({
63
+ conversationId: args.conversationId,
64
+ leaseToken: args.leaseToken,
65
+ conversationStore: args.options.conversationStore,
66
+ nowMs: args.nowMs,
67
+ state: args.options.state
68
+ })) return;
69
+ await ensureConversationWake({
70
+ conversationId: args.conversationId,
71
+ conversationStore: args.options.conversationStore,
72
+ idempotencyKey: nudgeIdempotencyKey("lost_lease", args.conversationId, args.nowMs),
73
+ nowMs: args.nowMs,
74
+ queue: args.options.queue,
75
+ replaceExistingWake: true,
76
+ state: args.options.state
77
+ });
78
+ }
79
+ /**
80
+ * Record one failed delivery attempt and surface dead-lettered messages.
81
+ *
82
+ * Consumption is logged here so every dead-lettered message leaves a
83
+ * `conversation.work.dead_lettered` trail with its terminal attempt count.
84
+ */
85
+ async function recordFailedDeliveryAttempt(args) {
86
+ const failure = await recordAttemptFailure({
87
+ conversationId: args.conversationId,
88
+ inboundMessageIds: args.messageIds,
89
+ leaseToken: args.leaseToken,
90
+ conversationStore: args.options.conversationStore,
91
+ nowMs: args.nowMs,
92
+ state: args.options.state
93
+ });
94
+ for (const message of failure.deadLetteredMessages) logWarn("conversation.work.dead_lettered", {
95
+ "app.conversation.source": message.source,
96
+ "app.inbound.attempt_count": message.attemptCount ?? 0,
97
+ "app.inbound.message_id": message.inboundMessageId,
98
+ "app.inbound.pending_count": failure.pendingCount
99
+ });
100
+ return failure;
101
+ }
102
+ /** True only when this attempt dead-lettered messages and left no further pending work. */
103
+ function isTerminalFailure(failure) {
104
+ return failure.status === "recorded" && failure.deadLetteredMessages.length > 0 && failure.pendingCount === 0;
105
+ }
106
+ function logRetryExhausted(args) {
107
+ logException(args.error, "conversation.work.retry.exhausted", {
108
+ "app.run.id": args.work.execution.runId ?? "unknown",
109
+ "app.worker.last_progress_at_ms": args.work.execution.lastProgressAtMs ?? args.work.createdAtMs,
110
+ "app.worker.retry_count": args.retryCount
111
+ });
112
+ }
113
+ function startLeaseCheckIn(args) {
114
+ const timer = setInterval(() => {
115
+ const nowMs = now(args.options);
116
+ checkInConversationWork({
117
+ conversationId: args.conversationId,
118
+ leaseToken: args.leaseToken,
119
+ conversationStore: args.options.conversationStore,
120
+ nowMs,
121
+ state: args.options.state
122
+ }).then((checkedIn) => {
123
+ if (!checkedIn) {
124
+ args.onLostLease();
125
+ logWarn("conversation.work.check_in.failed");
126
+ }
127
+ }, (error) => {
128
+ logException(error, "conversation.work.check_in.failed");
129
+ });
130
+ }, args.options.checkInIntervalMs ?? 15e3);
131
+ timer.unref?.();
132
+ return timer;
133
+ }
134
+ /** Poll shared state only when a worker adapter asks to observe remote stops. */
135
+ function createConversationStopSignal(args) {
136
+ const controller = new AbortController();
137
+ let checking = false;
138
+ let failureCaptured = false;
139
+ let listening = false;
140
+ let timer;
141
+ const requestStop = () => {
142
+ if (!controller.signal.aborted) controller.abort(/* @__PURE__ */ new Error("Conversation work stopped"));
143
+ };
144
+ if (args.initialStopRunId === args.runId) requestStop();
145
+ const check = async () => {
146
+ if (checking || controller.signal.aborted) return;
147
+ checking = true;
148
+ try {
149
+ if ((await getConversationWorkState({
150
+ conversationId: args.conversationId,
151
+ state: args.options.state
152
+ }))?.execution.stop?.runId === args.runId) requestStop();
153
+ } catch (error) {
154
+ if (!failureCaptured) {
155
+ failureCaptured = true;
156
+ logException(error, "conversation.work.stop_check.failed");
157
+ }
158
+ } finally {
159
+ checking = false;
160
+ }
161
+ };
162
+ return {
163
+ close() {
164
+ if (timer) clearInterval(timer);
165
+ },
166
+ isEnabled() {
167
+ return listening;
168
+ },
169
+ wasObserved() {
170
+ return listening && controller.signal.aborted;
171
+ },
172
+ signal() {
173
+ listening = true;
174
+ if (!timer && !controller.signal.aborted) {
175
+ timer = setInterval(() => void check(), CONVERSATION_STOP_CHECK_INTERVAL_MS);
176
+ timer.unref?.();
177
+ }
178
+ return controller.signal;
179
+ }
180
+ };
181
+ }
182
+ /** Process one queue wake-up for a conversation. */
183
+ async function processConversationWork(message, options) {
184
+ return withLogContext({ conversationId: message.conversationId }, () => processConversationWorkInContext(message, options));
185
+ }
186
+ async function processConversationWorkInContext(message, options) {
187
+ const conversationId = message.conversationId;
188
+ let initial;
189
+ try {
190
+ initial = await getConversationWorkState({
191
+ conversationId,
192
+ state: options.state
193
+ });
194
+ } catch (error) {
195
+ if (isInvalidConversationRecordError(error)) throw new ConversationQueueMessageRejectedError("invalid_record", `Conversation record failed validation for ${conversationId}`, { conversationId });
196
+ throw error;
197
+ }
198
+ if (!initial || countPendingConversationMessages(initial) === 0 && initial.execution.status === "idle" && !initial.execution.lease) {
199
+ if (initial) await clearConsumedConversationWake({
200
+ conversationId,
201
+ conversationStore: options.conversationStore,
202
+ nowMs: now(options),
203
+ state: options.state
204
+ });
205
+ return { status: "no_work" };
206
+ }
207
+ let destination = initial.destination;
208
+ if (!destination && options.conversationStore) {
209
+ const stored = await options.conversationStore.get({ conversationId });
210
+ if (stored && !stored.parentConversationId) destination = stored.destination;
211
+ }
212
+ const lease = await startConversationWork({
213
+ conversationId,
214
+ conversationStore: options.conversationStore,
215
+ nowMs: now(options),
216
+ state: options.state
217
+ });
218
+ if (lease.status === "no_work") {
219
+ await clearConsumedConversationWake({
220
+ conversationId,
221
+ conversationStore: options.conversationStore,
222
+ nowMs: now(options),
223
+ state: options.state
224
+ });
225
+ return { status: "no_work" };
226
+ }
227
+ if (lease.status === "active") {
228
+ const nudgeNowMs = now(options);
229
+ await ensureConversationWake({
230
+ conversationId,
231
+ conversationStore: options.conversationStore,
232
+ delayMs: CONVERSATION_WORK_DEFER_DELAY_MS,
233
+ idempotencyKey: nudgeIdempotencyKey("active", conversationId, nudgeNowMs),
234
+ nowMs: nudgeNowMs,
235
+ queue: options.queue,
236
+ replaceExistingWake: true,
237
+ state: options.state
238
+ });
239
+ logInfo("conversation.work.nudge.deferred", { "app.lease.expires_at_ms": lease.leaseExpiresAtMs });
240
+ return { status: "active" };
241
+ }
242
+ const startedAtMs = now(options);
243
+ const softYieldDeadlineMs = startedAtMs + (options.softYieldAfterMs ?? getChatConfig().conversationWorkSoftYieldAfterMs);
244
+ let attemptMessageIds = [];
245
+ let attemptSelectedMessageIds = /* @__PURE__ */ new Set();
246
+ let attemptStartMessageIds = /* @__PURE__ */ new Set();
247
+ let failedWithoutProgress = false;
248
+ let leaseLost = false;
249
+ const markLeaseLost = () => {
250
+ leaseLost = true;
251
+ };
252
+ const timer = startLeaseCheckIn({
253
+ conversationId,
254
+ leaseToken: lease.leaseToken,
255
+ onLostLease: markLeaseLost,
256
+ options
257
+ });
258
+ logInfo("conversation.work.lease.acquired", {
259
+ "app.lease.expires_at_ms": lease.leaseExpiresAtMs,
260
+ "app.worker.soft_yield_deadline_ms": softYieldDeadlineMs
261
+ });
262
+ const drain = (handle) => drainConversationMailbox({
263
+ conversationId,
264
+ leaseToken: lease.leaseToken,
265
+ conversationStore: options.conversationStore,
266
+ handle: async (messages) => {
267
+ const candidates = messages.filter((message) => message.delivery === "interrupt" && (attemptSelectedMessageIds.has(message.inboundMessageId) || !attemptStartMessageIds.has(message.inboundMessageId)));
268
+ if (candidates.length === 0) return [];
269
+ return await handle(candidates) ?? candidates.map((message) => message.inboundMessageId);
270
+ },
271
+ nowMs: now(options),
272
+ state: options.state
273
+ });
274
+ const requestDeadlineAtMs = getTurnRequestDeadline()?.deadlineAtMs;
275
+ const shouldYield = () => leaseLost || now(options) >= softYieldDeadlineMs || requestDeadlineAtMs !== void 0 && Date.now() >= requestDeadlineAtMs;
276
+ const checkIn = async () => {
277
+ const checkedIn = await checkInConversationWork({
278
+ conversationId,
279
+ leaseToken: lease.leaseToken,
280
+ conversationStore: options.conversationStore,
281
+ nowMs: now(options),
282
+ state: options.state
283
+ });
284
+ if (!checkedIn) markLeaseLost();
285
+ return checkedIn;
286
+ };
287
+ const yieldWork = async () => {
288
+ const yieldNowMs = now(options);
289
+ await ensureConversationWake({
290
+ conversationId,
291
+ conversationStore: options.conversationStore,
292
+ idempotencyKey: nudgeIdempotencyKey("yield", conversationId, yieldNowMs),
293
+ nowMs: yieldNowMs,
294
+ queue: options.queue,
295
+ replaceExistingWake: true,
296
+ state: options.state
297
+ });
298
+ if (!await releaseConversationWork({
299
+ conversationId,
300
+ leaseToken: lease.leaseToken,
301
+ conversationStore: options.conversationStore,
302
+ nowMs: yieldNowMs,
303
+ state: options.state
304
+ })) return { status: "lost_lease" };
305
+ logInfo("conversation.work.yielded", {
306
+ "app.worker.elapsed_ms": now(options) - startedAtMs,
307
+ "app.worker.soft_yield_deadline_ms": softYieldDeadlineMs
308
+ });
309
+ return { status: "yielded" };
310
+ };
311
+ try {
312
+ let hasRun = false;
313
+ let resumeIfStopped = false;
314
+ while (true) {
315
+ attemptMessageIds = [];
316
+ const leasedWork = await getConversationWorkState({
317
+ conversationId,
318
+ state: options.state
319
+ });
320
+ if (!leasedWork || leasedWork.lease?.leaseToken !== lease.leaseToken || leaseLost) {
321
+ markLeaseLost();
322
+ await requestLostLeaseRecovery({
323
+ conversationId,
324
+ destination,
325
+ leaseToken: lease.leaseToken,
326
+ nowMs: now(options),
327
+ options
328
+ });
329
+ return { status: "lost_lease" };
330
+ }
331
+ const resumePending = leasedWork.execution.status === "paused";
332
+ const attemptMessages = selectAttemptMessages(leasedWork);
333
+ const runId = leasedWork.execution.runId;
334
+ if (!runId) throw new Error(`Conversation run is missing for ${conversationId}`);
335
+ attemptStartMessageIds = new Set(leasedWork.messages.map((message) => message.inboundMessageId));
336
+ if (hasRun && shouldYield()) {
337
+ if (resumePending) return await yieldWork();
338
+ break;
339
+ }
340
+ if (resumePending && attemptMessages.length === 0) {
341
+ if (!await beginConversationResume({
342
+ conversationId,
343
+ leaseToken: lease.leaseToken,
344
+ conversationStore: options.conversationStore,
345
+ nowMs: now(options),
346
+ state: options.state
347
+ })) {
348
+ markLeaseLost();
349
+ await requestLostLeaseRecovery({
350
+ conversationId,
351
+ destination,
352
+ leaseToken: lease.leaseToken,
353
+ nowMs: now(options),
354
+ options
355
+ });
356
+ return { status: "lost_lease" };
357
+ }
358
+ }
359
+ attemptMessageIds = attemptMessages.map((message) => message.inboundMessageId);
360
+ attemptSelectedMessageIds = new Set(attemptMessageIds);
361
+ const ack = async () => {
362
+ if (!await ackMessages({
363
+ conversationId,
364
+ inboundMessageIds: attemptMessageIds,
365
+ leaseToken: lease.leaseToken,
366
+ conversationStore: options.conversationStore,
367
+ nowMs: now(options),
368
+ state: options.state
369
+ })) {
370
+ markLeaseLost();
371
+ throw new Error(`Conversation work lease lost before inbox ack for ${conversationId}`);
372
+ }
373
+ };
374
+ const stop = createConversationStopSignal({
375
+ conversationId,
376
+ initialStopRunId: leasedWork.execution.stop?.runId,
377
+ options,
378
+ runId
379
+ });
380
+ const workerContext = {
381
+ attempt: {
382
+ ack,
383
+ conversationId,
384
+ destination,
385
+ drain,
386
+ isFinalAttempt: attemptMessages.some((message) => isFinalAttempt(message)),
387
+ messages: attemptMessages
388
+ },
389
+ conversationId,
390
+ destination,
391
+ shouldYield,
392
+ stopSignal: stop.signal,
393
+ checkIn
394
+ };
395
+ let result;
396
+ try {
397
+ result = await options.run(workerContext);
398
+ } finally {
399
+ stop.close();
400
+ }
401
+ resumeIfStopped ||= stop.isEnabled();
402
+ hasRun = true;
403
+ if (result.status === "lost_lease") {
404
+ await requestLostLeaseRecovery({
405
+ conversationId,
406
+ destination,
407
+ leaseToken: lease.leaseToken,
408
+ nowMs: now(options),
409
+ options
410
+ });
411
+ return { status: "lost_lease" };
412
+ }
413
+ if (leaseLost) {
414
+ await requestLostLeaseRecovery({
415
+ conversationId,
416
+ destination,
417
+ leaseToken: lease.leaseToken,
418
+ nowMs: now(options),
419
+ options
420
+ });
421
+ return { status: "lost_lease" };
422
+ }
423
+ if (result.status === "completed" && stop.wasObserved()) {
424
+ if ((await completeConversationStop({
425
+ conversationId,
426
+ conversationStore: options.conversationStore,
427
+ leaseToken: lease.leaseToken,
428
+ nowMs: now(options),
429
+ runId,
430
+ state: options.state
431
+ })).status === "lost_lease") {
432
+ markLeaseLost();
433
+ await requestLostLeaseRecovery({
434
+ conversationId,
435
+ destination,
436
+ leaseToken: lease.leaseToken,
437
+ nowMs: now(options),
438
+ options
439
+ });
440
+ return { status: "lost_lease" };
441
+ }
442
+ }
443
+ if (result.status === "yielded") {
444
+ if (!await requestAnotherSlice({
445
+ conversationId,
446
+ destination,
447
+ leaseToken: lease.leaseToken,
448
+ conversationStore: options.conversationStore,
449
+ nowMs: now(options),
450
+ state: options.state
451
+ })) return { status: "lost_lease" };
452
+ return await yieldWork();
453
+ }
454
+ if (result.status === "deferred") {
455
+ const deferredNowMs = now(options);
456
+ if (!await releaseConversationWork({
457
+ conversationId,
458
+ leaseToken: lease.leaseToken,
459
+ conversationStore: options.conversationStore,
460
+ nowMs: deferredNowMs,
461
+ state: options.state
462
+ })) return { status: "lost_lease" };
463
+ return (await ensureConversationWake({
464
+ conversationId,
465
+ conversationStore: options.conversationStore,
466
+ idempotencyKey: nudgeIdempotencyKey("deferred", conversationId, deferredNowMs),
467
+ nowMs: deferredNowMs,
468
+ queue: options.queue,
469
+ state: options.state
470
+ })).status === "enqueued" ? { status: "pending_requeued" } : { status: "completed" };
471
+ }
472
+ if (attemptMessageIds.length > 0) {
473
+ const failure = await recordFailedDeliveryAttempt({
474
+ conversationId,
475
+ leaseToken: lease.leaseToken,
476
+ nowMs: now(options),
477
+ messageIds: attemptMessageIds,
478
+ options
479
+ });
480
+ if (isTerminalFailure(failure)) {
481
+ if (failure.retryCount >= 5) logRetryExhausted({
482
+ error: /* @__PURE__ */ new Error("Conversation work stopped after repeated failed attempts"),
483
+ retryCount: failure.retryCount,
484
+ work: leasedWork
485
+ });
486
+ await deadLetterAttempt({
487
+ conversationId,
488
+ leaseToken: lease.leaseToken,
489
+ conversationStore: options.conversationStore,
490
+ nowMs: now(options),
491
+ state: options.state
492
+ });
493
+ return { status: "failed" };
494
+ }
495
+ if (failure.status === "lost_lease") return { status: "lost_lease" };
496
+ if (failure.status === "recorded") {
497
+ failedWithoutProgress = true;
498
+ break;
499
+ }
500
+ }
501
+ if (result.status === "paused") break;
502
+ const next = await getConversationWorkState({
503
+ conversationId,
504
+ state: options.state
505
+ });
506
+ if (!next || next.lease?.leaseToken !== lease.leaseToken) return { status: "lost_lease" };
507
+ if (next.execution.status !== "paused" && countPendingConversationMessages(next) === 0) break;
508
+ }
509
+ const completion = await completeConversationWork({
510
+ conversationId,
511
+ leaseToken: lease.leaseToken,
512
+ madeProgress: !failedWithoutProgress,
513
+ resumeIfStopped,
514
+ conversationStore: options.conversationStore,
515
+ nowMs: now(options),
516
+ state: options.state
517
+ });
518
+ if (completion === "lost_lease") return { status: "lost_lease" };
519
+ if (completion === "pending") {
520
+ const nudgeNowMs = now(options);
521
+ return (await ensureConversationWake({
522
+ conversationId,
523
+ conversationStore: options.conversationStore,
524
+ idempotencyKey: nudgeIdempotencyKey("pending", conversationId, nudgeNowMs),
525
+ nowMs: nudgeNowMs,
526
+ queue: options.queue,
527
+ state: options.state
528
+ })).status === "enqueued" ? { status: "pending_requeued" } : { status: "completed" };
529
+ }
530
+ logInfo("conversation.work.completed", { "app.worker.elapsed_ms": now(options) - startedAtMs });
531
+ return { status: "completed" };
532
+ } catch (error) {
533
+ const errorNowMs = now(options);
534
+ let recoveryRecorded = false;
535
+ try {
536
+ const failure = attemptMessageIds.length > 0 ? await recordFailedDeliveryAttempt({
537
+ conversationId,
538
+ leaseToken: lease.leaseToken,
539
+ nowMs: errorNowMs,
540
+ messageIds: attemptMessageIds,
541
+ options
542
+ }) : void 0;
543
+ if (failure && isTerminalFailure(failure)) {
544
+ if (failure.retryCount >= 5) logRetryExhausted({
545
+ error,
546
+ retryCount: failure.retryCount,
547
+ work: initial
548
+ });
549
+ await deadLetterAttempt({
550
+ conversationId,
551
+ leaseToken: lease.leaseToken,
552
+ conversationStore: options.conversationStore,
553
+ nowMs: errorNowMs,
554
+ state: options.state
555
+ });
556
+ } else if (failure?.status === "recorded") {
557
+ await releaseConversationWork({
558
+ conversationId,
559
+ leaseToken: lease.leaseToken,
560
+ conversationStore: options.conversationStore,
561
+ nowMs: errorNowMs,
562
+ state: options.state
563
+ });
564
+ await ensureConversationWake({
565
+ conversationId,
566
+ conversationStore: options.conversationStore,
567
+ idempotencyKey: nudgeIdempotencyKey("error", conversationId, errorNowMs),
568
+ nowMs: errorNowMs,
569
+ queue: options.queue,
570
+ replaceExistingWake: true,
571
+ state: options.state
572
+ });
573
+ } else {
574
+ if ((failure ? failure.status : await recordConversationRetry({
575
+ conversationId,
576
+ leaseToken: lease.leaseToken,
577
+ conversationStore: options.conversationStore,
578
+ nowMs: errorNowMs,
579
+ state: options.state
580
+ })) === "stopped") {
581
+ logException(error, "conversation.work.retry.exhausted", {
582
+ "app.run.id": initial.execution.runId ?? "unknown",
583
+ "app.worker.last_progress_at_ms": initial.execution.lastProgressAtMs ?? initial.createdAtMs,
584
+ "app.worker.retry_count": failure?.retryCount ?? (initial.execution.retryCount ?? 0) + 1
585
+ });
586
+ recoveryRecorded = true;
587
+ return { status: "failed" };
588
+ }
589
+ if (await requestAnotherSlice({
590
+ conversationId,
591
+ destination,
592
+ leaseToken: lease.leaseToken,
593
+ conversationStore: options.conversationStore,
594
+ nowMs: errorNowMs,
595
+ state: options.state
596
+ })) await ensureConversationWake({
597
+ conversationId,
598
+ conversationStore: options.conversationStore,
599
+ idempotencyKey: nudgeIdempotencyKey("error", conversationId, errorNowMs),
600
+ nowMs: errorNowMs,
601
+ queue: options.queue,
602
+ replaceExistingWake: true,
603
+ state: options.state
604
+ });
605
+ await releaseConversationWork({
606
+ conversationId,
607
+ leaseToken: lease.leaseToken,
608
+ conversationStore: options.conversationStore,
609
+ nowMs: errorNowMs,
610
+ state: options.state
611
+ });
612
+ }
613
+ recoveryRecorded = true;
614
+ } catch (recoveryError) {
615
+ logException(recoveryError, "conversation.work.requeue.failed");
616
+ }
617
+ if (!isProviderRetryError(error)) logException(error, "conversation.work.failed", { "app.worker.elapsed_ms": now(options) - startedAtMs });
618
+ if (!recoveryRecorded) throw error;
619
+ return { status: "failed" };
620
+ } finally {
621
+ clearInterval(timer);
622
+ }
623
+ }
624
+ //#endregion
625
+ export { worker_exports as n, processConversationWork as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior",
3
- "version": "0.203.0",
3
+ "version": "0.205.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -85,7 +85,7 @@
85
85
  "pg": "^8.16.3",
86
86
  "yaml": "^2.9.0",
87
87
  "zod": "^4.5.4",
88
- "@sentry/junior-plugin-api": "0.203.0"
88
+ "@sentry/junior-plugin-api": "0.205.0"
89
89
  },
90
90
  "devDependencies": {
91
91
  "@emnapi/core": "^1.10.0",
@@ -100,20 +100,20 @@
100
100
  "msw": "^2.14.6",
101
101
  "nitro": "3.0.260522-beta",
102
102
  "oxlint": "^1.79.0",
103
- "tsup": "^8.5.1",
103
+ "tsdown": "0.23.0",
104
104
  "typescript": "^6.0.3",
105
105
  "vercel": "^54.4.0",
106
106
  "vitest": "^4.1.7",
107
- "@sentry/junior-github": "0.203.0",
108
- "@sentry/junior-memory": "0.203.0",
109
- "@sentry/junior-testing": "0.0.0"
107
+ "@sentry/junior-testing": "0.0.0",
108
+ "@sentry/junior-memory": "0.205.0",
109
+ "@sentry/junior-github": "0.205.0"
110
110
  },
111
111
  "scripts": {
112
- "build": "tsup",
112
+ "build": "tsdown",
113
113
  "acp:smoke": "pnpm exec tsx scripts/acp-smoke.ts",
114
114
  "db:generate": "pnpm exec drizzle-kit generate --config drizzle.config.ts",
115
- "lint": "oxlint --config .oxlintrc.json --deny-warnings src tests scripts bin tsup.config.ts && depcruise --config .dependency-cruiser.mjs src/chat",
116
- "lint:fix": "oxlint --config .oxlintrc.json --deny-warnings --fix src tests scripts bin tsup.config.ts",
115
+ "lint": "oxlint --config .oxlintrc.json --deny-warnings src tests scripts bin tsdown.config.ts && depcruise --config .dependency-cruiser.mjs src/chat",
116
+ "lint:fix": "oxlint --config .oxlintrc.json --deny-warnings --fix src tests scripts bin tsdown.config.ts",
117
117
  "test": "vitest run --maxWorkers=4",
118
118
  "test:watch": "vitest",
119
119
  "typecheck": "tsc --noEmit",