@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
@@ -1,787 +0,0 @@
1
- import {
2
- CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
3
- CONVERSATION_WORK_MAX_RETRIES,
4
- ackMessages,
5
- beginConversationResume,
6
- checkInConversationWork,
7
- clearConsumedConversationWake,
8
- completeConversationStop,
9
- completeConversationWork,
10
- countPendingConversationMessages,
11
- deadLetterAttempt,
12
- drainConversationMailbox,
13
- ensureConversationWake,
14
- getConversationWorkState,
15
- isFinalAttempt,
16
- isInvalidConversationRecordError,
17
- recordAttemptFailure,
18
- recordConversationRetry,
19
- releaseConversationWork,
20
- requestAnotherSlice,
21
- startConversationWork
22
- } from "./chunk-KIIEUXD3.js";
23
- import {
24
- getTurnRequestDeadline
25
- } from "./chunk-NCEBK6PH.js";
26
- import {
27
- ConversationQueueMessageRejectedError
28
- } from "./chunk-JAL3CH4G.js";
29
- import {
30
- getChatConfig,
31
- isProviderRetryError
32
- } from "./chunk-ENY6SKIU.js";
33
- import {
34
- logException,
35
- logInfo,
36
- logWarn,
37
- withLogContext
38
- } from "./chunk-WS7NAFTM.js";
39
-
40
- // src/chat/task-execution/worker.ts
41
- var CONVERSATION_WORK_DEFER_DELAY_MS = 15e3;
42
- var CONVERSATION_STOP_CHECK_INTERVAL_MS = 500;
43
- function now(options) {
44
- return options.nowMs?.() ?? Date.now();
45
- }
46
- function selectContiguousTurnBatch(messages) {
47
- const first = messages[0];
48
- if (!first) {
49
- return [];
50
- }
51
- const nextTurnIndex = messages.findIndex(
52
- (message) => message.input.authorId !== first.input.authorId || message.source !== first.source
53
- );
54
- return messages.slice(
55
- 0,
56
- nextTurnIndex === -1 ? messages.length : nextTurnIndex
57
- );
58
- }
59
- function selectAttemptMessages(work) {
60
- const messages = work.messages;
61
- const interrupts = messages.filter(
62
- (message) => message.delivery === "interrupt"
63
- );
64
- if (interrupts.length > 0) {
65
- return selectContiguousTurnBatch(interrupts);
66
- }
67
- return work.execution.status === "paused" ? [] : selectContiguousTurnBatch(messages);
68
- }
69
- function nudgeIdempotencyKey(reason, conversationId, nowMs) {
70
- return `${reason}:${conversationId}:${nowMs}`;
71
- }
72
- async function requestLostLeaseRecovery(args) {
73
- const before = await getConversationWorkState({
74
- conversationId: args.conversationId,
75
- state: args.options.state
76
- });
77
- const retry = await recordConversationRetry({
78
- conversationId: args.conversationId,
79
- leaseToken: args.leaseToken,
80
- conversationStore: args.options.conversationStore,
81
- nowMs: args.nowMs,
82
- state: args.options.state
83
- });
84
- if (retry === "lost_lease") {
85
- return;
86
- }
87
- if (retry === "stopped") {
88
- logException(
89
- new Error("Conversation work stopped after repeated failed attempts"),
90
- "conversation.work.retry.exhausted",
91
- {
92
- "app.run.id": before?.execution.runId ?? "unknown",
93
- "app.worker.last_progress_at_ms": before?.execution.lastProgressAtMs ?? before?.createdAtMs ?? 0,
94
- "app.worker.retry_count": (before?.execution.retryCount ?? 0) + 1
95
- }
96
- );
97
- return;
98
- }
99
- const sliceRequested = await requestAnotherSlice({
100
- conversationId: args.conversationId,
101
- destination: args.destination,
102
- leaseToken: args.leaseToken,
103
- conversationStore: args.options.conversationStore,
104
- nowMs: args.nowMs,
105
- state: args.options.state
106
- });
107
- if (!sliceRequested) {
108
- return;
109
- }
110
- const released = await releaseConversationWork({
111
- conversationId: args.conversationId,
112
- leaseToken: args.leaseToken,
113
- conversationStore: args.options.conversationStore,
114
- nowMs: args.nowMs,
115
- state: args.options.state
116
- });
117
- if (!released) {
118
- return;
119
- }
120
- await ensureConversationWake({
121
- conversationId: args.conversationId,
122
- conversationStore: args.options.conversationStore,
123
- idempotencyKey: nudgeIdempotencyKey(
124
- "lost_lease",
125
- args.conversationId,
126
- args.nowMs
127
- ),
128
- nowMs: args.nowMs,
129
- queue: args.options.queue,
130
- replaceExistingWake: true,
131
- state: args.options.state
132
- });
133
- }
134
- async function recordFailedDeliveryAttempt(args) {
135
- const failure = await recordAttemptFailure({
136
- conversationId: args.conversationId,
137
- inboundMessageIds: args.messageIds,
138
- leaseToken: args.leaseToken,
139
- conversationStore: args.options.conversationStore,
140
- nowMs: args.nowMs,
141
- state: args.options.state
142
- });
143
- for (const message of failure.deadLetteredMessages) {
144
- logWarn("conversation.work.dead_lettered", {
145
- "app.conversation.source": message.source,
146
- "app.inbound.attempt_count": message.attemptCount ?? 0,
147
- "app.inbound.message_id": message.inboundMessageId,
148
- "app.inbound.pending_count": failure.pendingCount
149
- });
150
- }
151
- return failure;
152
- }
153
- function isTerminalFailure(failure) {
154
- return failure.status === "recorded" && failure.deadLetteredMessages.length > 0 && failure.pendingCount === 0;
155
- }
156
- function logRetryExhausted(args) {
157
- logException(args.error, "conversation.work.retry.exhausted", {
158
- "app.run.id": args.work.execution.runId ?? "unknown",
159
- "app.worker.last_progress_at_ms": args.work.execution.lastProgressAtMs ?? args.work.createdAtMs,
160
- "app.worker.retry_count": args.retryCount
161
- });
162
- }
163
- function startLeaseCheckIn(args) {
164
- const timer = setInterval(() => {
165
- const nowMs = now(args.options);
166
- void checkInConversationWork({
167
- conversationId: args.conversationId,
168
- leaseToken: args.leaseToken,
169
- conversationStore: args.options.conversationStore,
170
- nowMs,
171
- state: args.options.state
172
- }).then(
173
- (checkedIn) => {
174
- if (!checkedIn) {
175
- args.onLostLease();
176
- logWarn("conversation.work.check_in.failed");
177
- }
178
- },
179
- (error) => {
180
- logException(error, "conversation.work.check_in.failed");
181
- }
182
- );
183
- }, args.options.checkInIntervalMs ?? CONVERSATION_WORK_CHECK_IN_INTERVAL_MS);
184
- timer.unref?.();
185
- return timer;
186
- }
187
- function createConversationStopSignal(args) {
188
- const controller = new AbortController();
189
- let checking = false;
190
- let failureCaptured = false;
191
- let listening = false;
192
- let timer;
193
- const requestStop = () => {
194
- if (!controller.signal.aborted) {
195
- controller.abort(new Error("Conversation work stopped"));
196
- }
197
- };
198
- if (args.initialStopRunId === args.runId) {
199
- requestStop();
200
- }
201
- const check = async () => {
202
- if (checking || controller.signal.aborted) return;
203
- checking = true;
204
- try {
205
- const current = await getConversationWorkState({
206
- conversationId: args.conversationId,
207
- state: args.options.state
208
- });
209
- if (current?.execution.stop?.runId === args.runId) {
210
- requestStop();
211
- }
212
- } catch (error) {
213
- if (!failureCaptured) {
214
- failureCaptured = true;
215
- logException(error, "conversation.work.stop_check.failed");
216
- }
217
- } finally {
218
- checking = false;
219
- }
220
- };
221
- return {
222
- close() {
223
- if (timer) clearInterval(timer);
224
- },
225
- isEnabled() {
226
- return listening;
227
- },
228
- wasObserved() {
229
- return listening && controller.signal.aborted;
230
- },
231
- signal() {
232
- listening = true;
233
- if (!timer && !controller.signal.aborted) {
234
- timer = setInterval(
235
- () => void check(),
236
- CONVERSATION_STOP_CHECK_INTERVAL_MS
237
- );
238
- timer.unref?.();
239
- }
240
- return controller.signal;
241
- }
242
- };
243
- }
244
- async function processConversationWork(message, options) {
245
- return withLogContext(
246
- { conversationId: message.conversationId },
247
- () => processConversationWorkInContext(message, options)
248
- );
249
- }
250
- async function processConversationWorkInContext(message, options) {
251
- const conversationId = message.conversationId;
252
- let initial;
253
- try {
254
- initial = await getConversationWorkState({
255
- conversationId,
256
- state: options.state
257
- });
258
- } catch (error) {
259
- if (isInvalidConversationRecordError(error)) {
260
- throw new ConversationQueueMessageRejectedError(
261
- "invalid_record",
262
- `Conversation record failed validation for ${conversationId}`,
263
- { conversationId }
264
- );
265
- }
266
- throw error;
267
- }
268
- if (!initial || countPendingConversationMessages(initial) === 0 && initial.execution.status === "idle" && !initial.execution.lease) {
269
- if (initial) {
270
- await clearConsumedConversationWake({
271
- conversationId,
272
- conversationStore: options.conversationStore,
273
- nowMs: now(options),
274
- state: options.state
275
- });
276
- }
277
- return { status: "no_work" };
278
- }
279
- let destination = initial.destination;
280
- if (!destination && options.conversationStore) {
281
- const stored = await options.conversationStore.get({ conversationId });
282
- if (stored && !stored.parentConversationId) {
283
- destination = stored.destination;
284
- }
285
- }
286
- const lease = await startConversationWork({
287
- conversationId,
288
- conversationStore: options.conversationStore,
289
- nowMs: now(options),
290
- state: options.state
291
- });
292
- if (lease.status === "no_work") {
293
- await clearConsumedConversationWake({
294
- conversationId,
295
- conversationStore: options.conversationStore,
296
- nowMs: now(options),
297
- state: options.state
298
- });
299
- return { status: "no_work" };
300
- }
301
- if (lease.status === "active") {
302
- const nudgeNowMs = now(options);
303
- await ensureConversationWake({
304
- conversationId,
305
- conversationStore: options.conversationStore,
306
- delayMs: CONVERSATION_WORK_DEFER_DELAY_MS,
307
- idempotencyKey: nudgeIdempotencyKey("active", conversationId, nudgeNowMs),
308
- nowMs: nudgeNowMs,
309
- queue: options.queue,
310
- replaceExistingWake: true,
311
- state: options.state
312
- });
313
- logInfo("conversation.work.nudge.deferred", {
314
- "app.lease.expires_at_ms": lease.leaseExpiresAtMs
315
- });
316
- return { status: "active" };
317
- }
318
- const startedAtMs = now(options);
319
- const softYieldDeadlineMs = startedAtMs + (options.softYieldAfterMs ?? getChatConfig().conversationWorkSoftYieldAfterMs);
320
- let attemptMessageIds = [];
321
- let attemptSelectedMessageIds = /* @__PURE__ */ new Set();
322
- let attemptStartMessageIds = /* @__PURE__ */ new Set();
323
- let failedWithoutProgress = false;
324
- let leaseLost = false;
325
- const markLeaseLost = () => {
326
- leaseLost = true;
327
- };
328
- const timer = startLeaseCheckIn({
329
- conversationId,
330
- leaseToken: lease.leaseToken,
331
- onLostLease: markLeaseLost,
332
- options
333
- });
334
- logInfo("conversation.work.lease.acquired", {
335
- "app.lease.expires_at_ms": lease.leaseExpiresAtMs,
336
- "app.worker.soft_yield_deadline_ms": softYieldDeadlineMs
337
- });
338
- const drain = (handle) => drainConversationMailbox({
339
- conversationId,
340
- leaseToken: lease.leaseToken,
341
- conversationStore: options.conversationStore,
342
- handle: async (messages) => {
343
- const candidates = messages.filter(
344
- (message2) => message2.delivery === "interrupt" && (attemptSelectedMessageIds.has(message2.inboundMessageId) || !attemptStartMessageIds.has(message2.inboundMessageId))
345
- );
346
- if (candidates.length === 0) {
347
- return [];
348
- }
349
- return await handle(candidates) ?? candidates.map((message2) => message2.inboundMessageId);
350
- },
351
- nowMs: now(options),
352
- state: options.state
353
- });
354
- const requestDeadlineAtMs = getTurnRequestDeadline()?.deadlineAtMs;
355
- const shouldYield = () => (
356
- // Lease ownership is no longer confirmed, so this worker must stop.
357
- leaseLost || // The worker soft limit reserves time to persist state and release the lease.
358
- now(options) >= softYieldDeadlineMs || // Nested work can inherit an older host request deadline. Stop after that
359
- // absolute deadline, even if this worker acquired its lease later.
360
- requestDeadlineAtMs !== void 0 && Date.now() >= requestDeadlineAtMs
361
- );
362
- const checkIn = async () => {
363
- const checkedIn = await checkInConversationWork({
364
- conversationId,
365
- leaseToken: lease.leaseToken,
366
- conversationStore: options.conversationStore,
367
- nowMs: now(options),
368
- state: options.state
369
- });
370
- if (!checkedIn) {
371
- markLeaseLost();
372
- }
373
- return checkedIn;
374
- };
375
- const yieldWork = async () => {
376
- const yieldNowMs = now(options);
377
- await ensureConversationWake({
378
- conversationId,
379
- conversationStore: options.conversationStore,
380
- idempotencyKey: nudgeIdempotencyKey("yield", conversationId, yieldNowMs),
381
- nowMs: yieldNowMs,
382
- queue: options.queue,
383
- replaceExistingWake: true,
384
- state: options.state
385
- });
386
- const released = await releaseConversationWork({
387
- conversationId,
388
- leaseToken: lease.leaseToken,
389
- conversationStore: options.conversationStore,
390
- nowMs: yieldNowMs,
391
- state: options.state
392
- });
393
- if (!released) {
394
- return { status: "lost_lease" };
395
- }
396
- logInfo("conversation.work.yielded", {
397
- "app.worker.elapsed_ms": now(options) - startedAtMs,
398
- "app.worker.soft_yield_deadline_ms": softYieldDeadlineMs
399
- });
400
- return { status: "yielded" };
401
- };
402
- try {
403
- let hasRun = false;
404
- let resumeIfStopped = false;
405
- while (true) {
406
- attemptMessageIds = [];
407
- const leasedWork = await getConversationWorkState({
408
- conversationId,
409
- state: options.state
410
- });
411
- if (!leasedWork || leasedWork.lease?.leaseToken !== lease.leaseToken || leaseLost) {
412
- markLeaseLost();
413
- await requestLostLeaseRecovery({
414
- conversationId,
415
- destination,
416
- leaseToken: lease.leaseToken,
417
- nowMs: now(options),
418
- options
419
- });
420
- return { status: "lost_lease" };
421
- }
422
- const resumePending = leasedWork.execution.status === "paused";
423
- const attemptMessages = selectAttemptMessages(leasedWork);
424
- const runId = leasedWork.execution.runId;
425
- if (!runId) {
426
- throw new Error(`Conversation run is missing for ${conversationId}`);
427
- }
428
- attemptStartMessageIds = new Set(
429
- leasedWork.messages.map((message2) => message2.inboundMessageId)
430
- );
431
- if (hasRun && shouldYield()) {
432
- if (resumePending) {
433
- return await yieldWork();
434
- }
435
- break;
436
- }
437
- if (resumePending && attemptMessages.length === 0) {
438
- const resumeStarted = await beginConversationResume({
439
- conversationId,
440
- leaseToken: lease.leaseToken,
441
- conversationStore: options.conversationStore,
442
- nowMs: now(options),
443
- state: options.state
444
- });
445
- if (!resumeStarted) {
446
- markLeaseLost();
447
- await requestLostLeaseRecovery({
448
- conversationId,
449
- destination,
450
- leaseToken: lease.leaseToken,
451
- nowMs: now(options),
452
- options
453
- });
454
- return { status: "lost_lease" };
455
- }
456
- }
457
- attemptMessageIds = attemptMessages.map(
458
- (message2) => message2.inboundMessageId
459
- );
460
- attemptSelectedMessageIds = new Set(attemptMessageIds);
461
- const ack = async () => {
462
- const acknowledged = await ackMessages({
463
- conversationId,
464
- inboundMessageIds: attemptMessageIds,
465
- leaseToken: lease.leaseToken,
466
- conversationStore: options.conversationStore,
467
- nowMs: now(options),
468
- state: options.state
469
- });
470
- if (!acknowledged) {
471
- markLeaseLost();
472
- throw new Error(
473
- `Conversation work lease lost before inbox ack for ${conversationId}`
474
- );
475
- }
476
- };
477
- const stop = createConversationStopSignal({
478
- conversationId,
479
- initialStopRunId: leasedWork.execution.stop?.runId,
480
- options,
481
- runId
482
- });
483
- const workerContext = {
484
- attempt: {
485
- ack,
486
- conversationId,
487
- destination,
488
- drain,
489
- isFinalAttempt: attemptMessages.some(
490
- (message2) => isFinalAttempt(message2)
491
- ),
492
- messages: attemptMessages
493
- },
494
- conversationId,
495
- destination,
496
- shouldYield,
497
- stopSignal: stop.signal,
498
- checkIn
499
- };
500
- let result;
501
- try {
502
- result = await options.run(workerContext);
503
- } finally {
504
- stop.close();
505
- }
506
- resumeIfStopped ||= stop.isEnabled();
507
- hasRun = true;
508
- if (result.status === "lost_lease") {
509
- await requestLostLeaseRecovery({
510
- conversationId,
511
- destination,
512
- leaseToken: lease.leaseToken,
513
- nowMs: now(options),
514
- options
515
- });
516
- return { status: "lost_lease" };
517
- }
518
- if (leaseLost) {
519
- await requestLostLeaseRecovery({
520
- conversationId,
521
- destination,
522
- leaseToken: lease.leaseToken,
523
- nowMs: now(options),
524
- options
525
- });
526
- return { status: "lost_lease" };
527
- }
528
- if (result.status === "completed" && stop.wasObserved()) {
529
- const stopped = await completeConversationStop({
530
- conversationId,
531
- conversationStore: options.conversationStore,
532
- leaseToken: lease.leaseToken,
533
- nowMs: now(options),
534
- runId,
535
- state: options.state
536
- });
537
- if (stopped.status === "lost_lease") {
538
- markLeaseLost();
539
- await requestLostLeaseRecovery({
540
- conversationId,
541
- destination,
542
- leaseToken: lease.leaseToken,
543
- nowMs: now(options),
544
- options
545
- });
546
- return { status: "lost_lease" };
547
- }
548
- }
549
- if (result.status === "yielded") {
550
- const sliceRequested = await requestAnotherSlice({
551
- conversationId,
552
- destination,
553
- leaseToken: lease.leaseToken,
554
- conversationStore: options.conversationStore,
555
- nowMs: now(options),
556
- state: options.state
557
- });
558
- if (!sliceRequested) {
559
- return { status: "lost_lease" };
560
- }
561
- return await yieldWork();
562
- }
563
- if (result.status === "deferred") {
564
- const deferredNowMs = now(options);
565
- const released = await releaseConversationWork({
566
- conversationId,
567
- leaseToken: lease.leaseToken,
568
- conversationStore: options.conversationStore,
569
- nowMs: deferredNowMs,
570
- state: options.state
571
- });
572
- if (!released) {
573
- return { status: "lost_lease" };
574
- }
575
- const wake = await ensureConversationWake({
576
- conversationId,
577
- conversationStore: options.conversationStore,
578
- idempotencyKey: nudgeIdempotencyKey(
579
- "deferred",
580
- conversationId,
581
- deferredNowMs
582
- ),
583
- nowMs: deferredNowMs,
584
- queue: options.queue,
585
- state: options.state
586
- });
587
- return wake.status === "enqueued" ? { status: "pending_requeued" } : { status: "completed" };
588
- }
589
- if (attemptMessageIds.length > 0) {
590
- const failure = await recordFailedDeliveryAttempt({
591
- conversationId,
592
- leaseToken: lease.leaseToken,
593
- nowMs: now(options),
594
- messageIds: attemptMessageIds,
595
- options
596
- });
597
- if (isTerminalFailure(failure)) {
598
- if (failure.retryCount >= CONVERSATION_WORK_MAX_RETRIES) {
599
- logRetryExhausted({
600
- error: new Error(
601
- "Conversation work stopped after repeated failed attempts"
602
- ),
603
- retryCount: failure.retryCount,
604
- work: leasedWork
605
- });
606
- }
607
- await deadLetterAttempt({
608
- conversationId,
609
- leaseToken: lease.leaseToken,
610
- conversationStore: options.conversationStore,
611
- nowMs: now(options),
612
- state: options.state
613
- });
614
- return { status: "failed" };
615
- }
616
- if (failure.status === "lost_lease") {
617
- return { status: "lost_lease" };
618
- }
619
- if (failure.status === "recorded") {
620
- failedWithoutProgress = true;
621
- break;
622
- }
623
- }
624
- if (result.status === "paused") {
625
- break;
626
- }
627
- const next = await getConversationWorkState({
628
- conversationId,
629
- state: options.state
630
- });
631
- if (!next || next.lease?.leaseToken !== lease.leaseToken) {
632
- return { status: "lost_lease" };
633
- }
634
- if (next.execution.status !== "paused" && countPendingConversationMessages(next) === 0) {
635
- break;
636
- }
637
- }
638
- const completion = await completeConversationWork({
639
- conversationId,
640
- leaseToken: lease.leaseToken,
641
- madeProgress: !failedWithoutProgress,
642
- // A stop that raced an external pause must reach the paused Turn.
643
- resumeIfStopped,
644
- conversationStore: options.conversationStore,
645
- nowMs: now(options),
646
- state: options.state
647
- });
648
- if (completion === "lost_lease") {
649
- return { status: "lost_lease" };
650
- }
651
- if (completion === "pending") {
652
- const nudgeNowMs = now(options);
653
- const wake = await ensureConversationWake({
654
- conversationId,
655
- conversationStore: options.conversationStore,
656
- idempotencyKey: nudgeIdempotencyKey(
657
- "pending",
658
- conversationId,
659
- nudgeNowMs
660
- ),
661
- nowMs: nudgeNowMs,
662
- queue: options.queue,
663
- state: options.state
664
- });
665
- return wake.status === "enqueued" ? { status: "pending_requeued" } : { status: "completed" };
666
- }
667
- logInfo("conversation.work.completed", {
668
- "app.worker.elapsed_ms": now(options) - startedAtMs
669
- });
670
- return { status: "completed" };
671
- } catch (error) {
672
- const errorNowMs = now(options);
673
- let recoveryRecorded = false;
674
- try {
675
- const failure = attemptMessageIds.length > 0 ? await recordFailedDeliveryAttempt({
676
- conversationId,
677
- leaseToken: lease.leaseToken,
678
- nowMs: errorNowMs,
679
- messageIds: attemptMessageIds,
680
- options
681
- }) : void 0;
682
- if (failure && isTerminalFailure(failure)) {
683
- if (failure.retryCount >= CONVERSATION_WORK_MAX_RETRIES) {
684
- logRetryExhausted({
685
- error,
686
- retryCount: failure.retryCount,
687
- work: initial
688
- });
689
- }
690
- await deadLetterAttempt({
691
- conversationId,
692
- leaseToken: lease.leaseToken,
693
- conversationStore: options.conversationStore,
694
- nowMs: errorNowMs,
695
- state: options.state
696
- });
697
- } else if (failure?.status === "recorded") {
698
- await releaseConversationWork({
699
- conversationId,
700
- leaseToken: lease.leaseToken,
701
- conversationStore: options.conversationStore,
702
- nowMs: errorNowMs,
703
- state: options.state
704
- });
705
- await ensureConversationWake({
706
- conversationId,
707
- conversationStore: options.conversationStore,
708
- idempotencyKey: nudgeIdempotencyKey(
709
- "error",
710
- conversationId,
711
- errorNowMs
712
- ),
713
- nowMs: errorNowMs,
714
- queue: options.queue,
715
- replaceExistingWake: true,
716
- state: options.state
717
- });
718
- } else {
719
- const retry = failure ? failure.status : await recordConversationRetry({
720
- conversationId,
721
- leaseToken: lease.leaseToken,
722
- conversationStore: options.conversationStore,
723
- nowMs: errorNowMs,
724
- state: options.state
725
- });
726
- if (retry === "stopped") {
727
- logException(error, "conversation.work.retry.exhausted", {
728
- "app.run.id": initial.execution.runId ?? "unknown",
729
- "app.worker.last_progress_at_ms": initial.execution.lastProgressAtMs ?? initial.createdAtMs,
730
- "app.worker.retry_count": failure?.retryCount ?? (initial.execution.retryCount ?? 0) + 1
731
- });
732
- recoveryRecorded = true;
733
- return { status: "failed" };
734
- }
735
- const sliceRequested = await requestAnotherSlice({
736
- conversationId,
737
- destination,
738
- leaseToken: lease.leaseToken,
739
- conversationStore: options.conversationStore,
740
- nowMs: errorNowMs,
741
- state: options.state
742
- });
743
- if (sliceRequested) {
744
- await ensureConversationWake({
745
- conversationId,
746
- conversationStore: options.conversationStore,
747
- idempotencyKey: nudgeIdempotencyKey(
748
- "error",
749
- conversationId,
750
- errorNowMs
751
- ),
752
- nowMs: errorNowMs,
753
- queue: options.queue,
754
- replaceExistingWake: true,
755
- state: options.state
756
- });
757
- }
758
- await releaseConversationWork({
759
- conversationId,
760
- leaseToken: lease.leaseToken,
761
- conversationStore: options.conversationStore,
762
- nowMs: errorNowMs,
763
- state: options.state
764
- });
765
- }
766
- recoveryRecorded = true;
767
- } catch (recoveryError) {
768
- logException(recoveryError, "conversation.work.requeue.failed");
769
- }
770
- if (!isProviderRetryError(error)) {
771
- logException(error, "conversation.work.failed", {
772
- "app.worker.elapsed_ms": now(options) - startedAtMs
773
- });
774
- }
775
- if (!recoveryRecorded) {
776
- throw error;
777
- }
778
- return { status: "failed" };
779
- } finally {
780
- clearInterval(timer);
781
- }
782
- }
783
-
784
- export {
785
- CONVERSATION_WORK_DEFER_DELAY_MS,
786
- processConversationWork
787
- };