@sentry/junior 0.184.0 → 0.186.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 (129) hide show
  1. package/dist/{agent-hooks-XTZVALGQ.js → agent-hooks-4B3Z4WRK.js} +13 -11
  2. package/dist/api/acp/schema.d.ts +20 -2
  3. package/dist/api/code/overview.d.ts +39 -0
  4. package/dist/api/locations/detail.d.ts +1 -1
  5. package/dist/api/people/code.d.ts +22 -0
  6. package/dist/api/schema/code.d.ts +46 -0
  7. package/dist/api/schema/conversation.d.ts +108 -20
  8. package/dist/api/schema/location.d.ts +1 -1
  9. package/dist/api/schema/person.d.ts +1 -1
  10. package/dist/api/schema.d.ts +4 -4
  11. package/dist/api/schema.js +12 -1
  12. package/dist/api.js +368 -78
  13. package/dist/app.js +1412 -538
  14. package/dist/{catalog-runtime-5357XR4F.js → catalog-runtime-AFJCAOHC.js} +4 -4
  15. package/dist/chat/api-turns/accepted-reply.d.ts +11 -0
  16. package/dist/chat/api-turns/cancellation.d.ts +3 -5
  17. package/dist/chat/api-turns/mailbox-input.d.ts +7 -0
  18. package/dist/chat/api-turns/routing.d.ts +18 -3
  19. package/dist/chat/api-turns/work.d.ts +4 -9
  20. package/dist/chat/app/conversation-work.d.ts +1 -1
  21. package/dist/chat/app/factory.d.ts +4 -0
  22. package/dist/chat/app/services.d.ts +4 -3
  23. package/dist/chat/conversations/history.d.ts +83 -9
  24. package/dist/chat/conversations/turn-lifecycle.d.ts +6 -3
  25. package/dist/chat/providers/slack/input.d.ts +32 -0
  26. package/dist/chat/{runtime → providers/slack}/processing-reaction.d.ts +6 -8
  27. package/dist/chat/{runtime/slack-resume.d.ts → providers/slack/resume.d.ts} +16 -19
  28. package/dist/chat/providers/slack/runtime.d.ts +1 -12
  29. package/dist/chat/providers/slack/turn.d.ts +10 -25
  30. package/dist/chat/resource-events/actor.d.ts +7 -2
  31. package/dist/chat/resource-events/app-publisher.d.ts +18 -0
  32. package/dist/chat/resource-events/catalog.d.ts +19 -0
  33. package/dist/chat/resource-events/ingest.d.ts +0 -1
  34. package/dist/chat/resource-events/notification.d.ts +28 -3
  35. package/dist/chat/resource-events/runtime-catalog.d.ts +7 -2
  36. package/dist/chat/resource-events/store.d.ts +2 -14
  37. package/dist/chat/resource-events/tool-support.d.ts +0 -5
  38. package/dist/chat/resource-events/workspace.d.ts +7 -3
  39. package/dist/chat/runtime/turn-execution.d.ts +7 -2
  40. package/dist/chat/sandbox/egress/credentials.d.ts +5 -4
  41. package/dist/chat/sandbox/egress/session.d.ts +10 -11
  42. package/dist/chat/sandbox/errors.d.ts +1 -1
  43. package/dist/chat/sandbox/ref.d.ts +1 -1
  44. package/dist/chat/sandbox/snapshot/events.d.ts +8 -1
  45. package/dist/chat/sandbox/snapshot/not-ready-error.d.ts +6 -1
  46. package/dist/chat/scheduled-tasks/tool-support.d.ts +5 -5
  47. package/dist/chat/scheduled-tasks/tools/create.d.ts +2 -2
  48. package/dist/chat/scheduled-tasks/tools/delete.d.ts +2 -2
  49. package/dist/chat/scheduled-tasks/tools/list.d.ts +2 -2
  50. package/dist/chat/scheduled-tasks/tools/run-now.d.ts +2 -2
  51. package/dist/chat/scheduled-tasks/tools/update.d.ts +2 -2
  52. package/dist/chat/scheduled-tasks/types.d.ts +1 -1
  53. package/dist/chat/sentry-links.d.ts +2 -0
  54. package/dist/chat/services/provider-retry.d.ts +2 -0
  55. package/dist/chat/services/turn-failure-response.d.ts +4 -0
  56. package/dist/chat/services/turn-session-routing.d.ts +20 -5
  57. package/dist/chat/task-execution/paused-turn.d.ts +0 -2
  58. package/dist/chat/task-execution/slack-resource-event.d.ts +47 -0
  59. package/dist/chat/task-execution/slack-work.d.ts +0 -21
  60. package/dist/chat/task-execution/state.d.ts +2 -2
  61. package/dist/chat/task-execution/store.d.ts +1 -1
  62. package/dist/chat/task-execution/turn-wake.d.ts +12 -0
  63. package/dist/chat/tool-support/action-review.d.ts +1 -1
  64. package/dist/chat/tools/event-tasks.d.ts +1 -1
  65. package/dist/chat/tools/resource-events.d.ts +2 -2
  66. package/dist/chat/tools/search-conversation-events.d.ts +1 -1
  67. package/dist/chat/tools/types.d.ts +1 -1
  68. package/dist/chat/tools/watch-resource-events.d.ts +2 -2
  69. package/dist/{chunk-Z3QAXJR7.js → chunk-2IBDVE62.js} +12 -9
  70. package/dist/{chunk-4RONS3WR.js → chunk-2U7EPTRZ.js} +11 -5
  71. package/dist/{chunk-3S7ULUWW.js → chunk-3CVEE6LA.js} +1 -1
  72. package/dist/{chunk-IZDYYYGP.js → chunk-43LODHJM.js} +24 -384
  73. package/dist/{chunk-LHXIZLFF.js → chunk-64WF2GQ3.js} +1 -1
  74. package/dist/{chunk-YKX6MTLU.js → chunk-7EOWT62G.js} +1 -1
  75. package/dist/{chunk-UBOIHNTH.js → chunk-7EU4YSZ4.js} +362 -188
  76. package/dist/{chunk-UF6BUA5W.js → chunk-ACGWTJ74.js} +3 -3
  77. package/dist/{chunk-6UDPINOX.js → chunk-AD64YMEC.js} +19 -44
  78. package/dist/{chunk-MLSQX2EX.js → chunk-BRKB5R7P.js} +1 -1
  79. package/dist/{chunk-E57WPXWY.js → chunk-CM6RTYSO.js} +5 -5
  80. package/dist/{chunk-MAPJFUMV.js → chunk-CV5CPRVG.js} +3 -3
  81. package/dist/chunk-D4YV5TDV.js +45 -0
  82. package/dist/{chunk-HIPUIPJM.js → chunk-DHYZ4VKG.js} +383 -254
  83. package/dist/{chunk-DUKIDPF6.js → chunk-DOP3FIQC.js} +1 -1
  84. package/dist/{chunk-BT53RIGJ.js → chunk-EWRPUXE3.js} +12 -50
  85. package/dist/{chunk-BHYRYYLY.js → chunk-FFYDRLXW.js} +1 -1
  86. package/dist/chunk-GFBR4S3Q.js +406 -0
  87. package/dist/chunk-GQMQCY7H.js +58 -0
  88. package/dist/{chunk-JNO2GUDS.js → chunk-GSB3NTNS.js} +926 -1856
  89. package/dist/{chunk-2ZQPVX7C.js → chunk-H7X2G2KS.js} +25 -12
  90. package/dist/{chunk-WQFEWULF.js → chunk-HKFLRIBD.js} +2 -2
  91. package/dist/{chunk-SHJK75Z2.js → chunk-HWXP6RHG.js} +38 -4
  92. package/dist/{chunk-RF6J3DIO.js → chunk-INQHUE72.js} +84 -1
  93. package/dist/{chunk-4CNDGK25.js → chunk-JFPY6XFF.js} +911 -993
  94. package/dist/{chunk-6WGC3SO4.js → chunk-MCLWOBPN.js} +80 -18
  95. package/dist/{chunk-PJPRXO2T.js → chunk-NRMAOGRS.js} +1 -1
  96. package/dist/{chunk-ACPDVEJO.js → chunk-O6GQO7VP.js} +201 -218
  97. package/dist/{chunk-M5YWNMTE.js → chunk-OZG7E22Y.js} +24 -6
  98. package/dist/{chunk-WVIA7V3M.js → chunk-PFAZSRGR.js} +29 -1
  99. package/dist/{chunk-LCP4EDKR.js → chunk-PZZOGHVR.js} +14 -4
  100. package/dist/{chunk-QABCY33S.js → chunk-QBL2AVFF.js} +2 -2
  101. package/dist/{chunk-FKEZZMXS.js → chunk-QU3URVWG.js} +9 -94
  102. package/dist/{chunk-M3QYTBQ6.js → chunk-STOCCPWH.js} +11 -2
  103. package/dist/{chunk-K7VDC2QW.js → chunk-TXLBLGNQ.js} +6 -6
  104. package/dist/{chunk-JA43DV4Y.js → chunk-VOGOTEW7.js} +1 -1
  105. package/dist/{chunk-HUXFMDBZ.js → chunk-VQIWBJOP.js} +1 -1
  106. package/dist/{chunk-JM2COLGC.js → chunk-VQZYIVYN.js} +6 -6
  107. package/dist/{chunk-BCHYQS4B.js → chunk-VXL2LBPK.js} +1 -1
  108. package/dist/{chunk-6VOYP4M6.js → chunk-YXSBZRP7.js} +1 -1
  109. package/dist/cli/chat.js +35 -33
  110. package/dist/cli/check.js +5 -5
  111. package/dist/cli/plugins.js +14 -12
  112. package/dist/cli/snapshot-create.js +10 -9
  113. package/dist/cli/upgrade.js +7 -6
  114. package/dist/{db-MA52H62H.js → db-7XL4UPAE.js} +8 -6
  115. package/dist/instrumentation.js +3 -3
  116. package/dist/nitro.js +7 -6
  117. package/dist/{oauth-callback-server-DXGHKN6S.js → oauth-callback-server-RAOYHWDI.js} +30 -27
  118. package/dist/{runner-4IXUAQNK.js → runner-KMPBWRPM.js} +24 -19
  119. package/dist/{skills-X3DY7AXO.js → skills-IPCALGLQ.js} +5 -5
  120. package/dist/spawn-OSOWTMBG.js +41 -0
  121. package/dist/task-runner-IQNBA3RY.js +34 -0
  122. package/dist/{validation-Z6JXSTJS.js → validation-BSRCCX6N.js} +5 -5
  123. package/dist/version.js +1 -1
  124. package/dist/{work-OKWRFBDW.js → work-T6UFTOJY.js} +24 -19
  125. package/dist/worker-L35OG7VA.js +24 -0
  126. package/package.json +5 -5
  127. package/dist/spawn-43WGS6CH.js +0 -37
  128. package/dist/task-runner-VDRKITPV.js +0 -32
  129. package/dist/worker-B236AE72.js +0 -22
package/dist/app.js CHANGED
@@ -1,20 +1,21 @@
1
1
  import {
2
2
  processConversationWork
3
- } from "./chunk-4RONS3WR.js";
3
+ } from "./chunk-2U7EPTRZ.js";
4
4
  import {
5
5
  bindSpawnAgent
6
- } from "./chunk-QABCY33S.js";
6
+ } from "./chunk-QBL2AVFF.js";
7
7
  import {
8
8
  createAgentInvocationWorker,
9
9
  enqueueAgentInvocation,
10
10
  listPendingAgentInvocationMailboxAppends,
11
11
  routeAgentInvocationWork
12
- } from "./chunk-BT53RIGJ.js";
12
+ } from "./chunk-EWRPUXE3.js";
13
13
  import {
14
14
  GET as GET2,
15
15
  GET2 as GET3,
16
16
  buildAuthPauseResponse,
17
17
  buildSlackOutputMessage,
18
+ createPausedTurns,
18
19
  createSlackAdapterAssistantStatusSession,
19
20
  getAssistantThreadContext,
20
21
  getChannelId,
@@ -33,10 +34,10 @@ import {
33
34
  sendSlackReply,
34
35
  shouldKeepProcessingReactionForToolInvocation,
35
36
  splitSlackReplyText,
36
- startSlackProcessingReaction,
37
+ startProcessingReaction,
37
38
  stripLeadingBotMention,
38
39
  wakePausedTurn
39
- } from "./chunk-ACPDVEJO.js";
40
+ } from "./chunk-O6GQO7VP.js";
40
41
  import "./chunk-FA6POGLH.js";
41
42
  import {
42
43
  GET,
@@ -47,14 +48,19 @@ import {
47
48
  createApiTurnWorker,
48
49
  createVercelAttachmentStorage,
49
50
  getAuthPausedApiTurnId,
51
+ lookupSlackUser,
50
52
  readConversationAccessFromSql,
51
53
  recordApiConversationActivity,
52
54
  resolveSlackChannelTypeFromMessage,
53
55
  resolveSlackConversationContext,
54
56
  routeApiTurnWork,
55
57
  webActorFromEmail
56
- } from "./chunk-UBOIHNTH.js";
57
- import "./chunk-LCP4EDKR.js";
58
+ } from "./chunk-7EU4YSZ4.js";
59
+ import "./chunk-PZZOGHVR.js";
60
+ import {
61
+ AgentRunError,
62
+ executeTurn
63
+ } from "./chunk-GQMQCY7H.js";
58
64
  import {
59
65
  buildDeliveredTurnStatePatch,
60
66
  completeAuthPauseTurn,
@@ -65,7 +71,7 @@ import {
65
71
  getTurnUserSlackMessageTs,
66
72
  persistAuthPauseTurnState,
67
73
  requireTurnFailureEventId
68
- } from "./chunk-M5YWNMTE.js";
74
+ } from "./chunk-OZG7E22Y.js";
69
75
  import {
70
76
  claimDispatchMailboxAppend,
71
77
  confirmDispatchMailboxAppend,
@@ -83,12 +89,13 @@ import {
83
89
  markDispatchFailed,
84
90
  markDispatchRunning,
85
91
  recordTaskExecution,
92
+ resolveConversationRouting,
86
93
  resolveTurnSessionRouting,
87
94
  scheduleSessionCompletedPluginTasks
88
- } from "./chunk-6WGC3SO4.js";
95
+ } from "./chunk-MCLWOBPN.js";
89
96
  import {
90
- ConversationTurnLifecycleService
91
- } from "./chunk-M3QYTBQ6.js";
97
+ getTurnLifecycle
98
+ } from "./chunk-STOCCPWH.js";
92
99
  import {
93
100
  coerceThreadConversationState,
94
101
  getLocationConfigurationService,
@@ -97,17 +104,17 @@ import {
97
104
  persistThreadRuntimeState,
98
105
  persistThreadState,
99
106
  persistThreadStateById
100
- } from "./chunk-E57WPXWY.js";
107
+ } from "./chunk-CM6RTYSO.js";
101
108
  import "./chunk-UTL3MHPC.js";
102
109
  import {
103
110
  createVercelPluginTaskCallback,
104
111
  queueCallback,
105
112
  registerVercelPluginTaskDevConsumer
106
- } from "./chunk-UF6BUA5W.js";
113
+ } from "./chunk-ACGWTJ74.js";
107
114
  import {
108
115
  validatePluginEgressCredentialHooks,
109
116
  validatePluginRegistrations
110
- } from "./chunk-HUXFMDBZ.js";
117
+ } from "./chunk-VQIWBJOP.js";
111
118
  import {
112
119
  defineJuniorPlugins,
113
120
  pluginCatalogConfigFromEnv,
@@ -115,28 +122,20 @@ import {
115
122
  pluginRuntimeRegistrationsFromPluginSet
116
123
  } from "./chunk-CM5HNV2W.js";
117
124
  import {
118
- RESOURCE_EVENT_SYSTEM_ACTOR,
119
125
  SANDBOX_EGRESS_PROXY_PATH,
120
- buildSlackInboundMessage,
121
126
  buildSteeringPiMessage,
122
127
  clearSandboxEgressSignals,
123
128
  consumeSandboxEgressAuthRequiredSignal,
124
129
  consumeSandboxEgressPermissionDeniedSignal,
125
130
  createContextCompactor,
126
- createSlackConversationWorker,
127
- ensureSlackMessageActorIdentity,
128
131
  executeAgentRun,
129
132
  executeCredentialedEgressRequest,
130
133
  getConfigDefaults,
131
- getMessageActorIdentity,
132
134
  getNextRunAtMs,
133
135
  ingestResourceEvent,
134
- isResourceEventConversationMessage,
135
- isResourceEventSlackMessage,
136
136
  latestReportedProgress,
137
137
  listThreadReplies,
138
138
  logScheduledTaskRunSkipped,
139
- normalizeIncomingSlackThreadId,
140
139
  normalizeSandboxEgressTracePropagationDomains,
141
140
  parseSandboxEgressCredentialToken,
142
141
  processWorkspaceSnapshotJob,
@@ -146,50 +145,41 @@ import {
146
145
  renderBlockText,
147
146
  resolveDestinationVisibility,
148
147
  resolveSandboxEgressProviderForHost,
149
- runWithSlackInstallation,
150
148
  scheduledTaskRunAttributes,
151
149
  setConfigDefaults,
152
150
  shouldEmitDevAgentTrace,
153
151
  shouldPropagateSandboxEgressTrace,
154
- stripLeadingSteeringOverride,
155
- unpublishedArtifactHeaders,
156
- verifySlackSignature,
157
- withNormalizedThreadId
158
- } from "./chunk-JNO2GUDS.js";
152
+ unpublishedArtifactHeaders
153
+ } from "./chunk-GSB3NTNS.js";
159
154
  import {
160
155
  AuthorizationFlowDisabledError,
161
156
  PluginCredentialFailureError
162
- } from "./chunk-K7VDC2QW.js";
157
+ } from "./chunk-TXLBLGNQ.js";
163
158
  import "./chunk-6Y5B5PEX.js";
164
159
  import "./chunk-DIB4GX3G.js";
165
160
  import {
166
- createAgentRunner,
167
161
  createUserTokenStore,
168
162
  deleteMcpAuthSessionsForUserProvider,
169
163
  deleteMcpServerSessionId,
170
164
  deleteMcpStoredOAuthCredentials
171
- } from "./chunk-FKEZZMXS.js";
172
- import {
173
- RetryableDeliveryError
174
- } from "./chunk-RF6J3DIO.js";
165
+ } from "./chunk-QU3URVWG.js";
175
166
  import {
176
167
  formatProviderLabel,
177
168
  postSlackMessage,
178
169
  startOAuthFlow
179
- } from "./chunk-JM2COLGC.js";
180
- import {
181
- getExperimentalFeatures,
182
- isExperimentalFeatureEnabled,
183
- setExperimentalFeatures
184
- } from "./chunk-2LYHWMR4.js";
170
+ } from "./chunk-VQZYIVYN.js";
185
171
  import {
172
+ RESOURCE_EVENT_AUTHOR_ID,
173
+ RESOURCE_EVENT_SYSTEM_ACTOR,
186
174
  collectAttachmentGarbage,
187
175
  collectEventTaskMatchKeys,
188
176
  findMatchingEventTasks,
189
177
  getResourceEventCatalog,
178
+ isResourceEventConversationMessage,
179
+ isResourceEventMailboxMetadata,
180
+ isResourceEventSlackMessage,
190
181
  listScheduledTasks,
191
182
  listScheduledTasksForTeam,
192
- lookupSlackUser,
193
183
  readScheduledTask,
194
184
  requestAttachmentDeletion,
195
185
  resourceEventGuidance,
@@ -197,10 +187,14 @@ import {
197
187
  scheduledRunId,
198
188
  scheduledRunSchema,
199
189
  withScheduledTaskLock
200
- } from "./chunk-HIPUIPJM.js";
190
+ } from "./chunk-DHYZ4VKG.js";
201
191
  import {
202
192
  parseSlackThreadId
203
- } from "./chunk-YKX6MTLU.js";
193
+ } from "./chunk-7EOWT62G.js";
194
+ import {
195
+ RetryableDeliveryError,
196
+ createAgentRunner
197
+ } from "./chunk-INQHUE72.js";
204
198
  import {
205
199
  CONVERSATION_WORK_STALE_ENQUEUE_MS,
206
200
  appendAndEnqueueInboundMessage,
@@ -215,7 +209,7 @@ import {
215
209
  removeActiveConversation,
216
210
  requestConversationWork,
217
211
  stopConversationWork
218
- } from "./chunk-Z3QAXJR7.js";
212
+ } from "./chunk-2IBDVE62.js";
219
213
  import {
220
214
  ConversationTurnBoundaryError,
221
215
  CooperativeTurnYieldError,
@@ -233,7 +227,7 @@ import {
233
227
  markTurnCompleted,
234
228
  markTurnFailed,
235
229
  startActiveTurn
236
- } from "./chunk-JA43DV4Y.js";
230
+ } from "./chunk-VOGOTEW7.js";
237
231
  import {
238
232
  abandonTurnRecord,
239
233
  appendThreadContextMessages,
@@ -269,11 +263,16 @@ import {
269
263
  trimTrailingAssistantMessages,
270
264
  turnHasReply,
271
265
  upsertConversationMessage
272
- } from "./chunk-2ZQPVX7C.js";
266
+ } from "./chunk-H7X2G2KS.js";
267
+ import {
268
+ getExperimentalFeatures,
269
+ isExperimentalFeatureEnabled,
270
+ setExperimentalFeatures
271
+ } from "./chunk-2LYHWMR4.js";
273
272
  import {
274
273
  getSandboxResourceConfig,
275
274
  setSandboxResourceConfig
276
- } from "./chunk-MAPJFUMV.js";
275
+ } from "./chunk-CV5CPRVG.js";
277
276
  import "./chunk-PDO5BLNM.js";
278
277
  import "./chunk-UIE3R5XU.js";
279
278
  import {
@@ -292,7 +291,7 @@ import {
292
291
  import "./chunk-7H2VZTWN.js";
293
292
  import {
294
293
  getTurnRequestDeadline
295
- } from "./chunk-MLSQX2EX.js";
294
+ } from "./chunk-BRKB5R7P.js";
296
295
  import {
297
296
  SlackActionError,
298
297
  bindEventTaskCredentialSubject,
@@ -302,7 +301,6 @@ import {
302
301
  collectResourceEventMatchKeys,
303
302
  createPluginLogger,
304
303
  createPluginState,
305
- createResourceEventTeamIdResolver,
306
304
  downloadPrivateSlackFile,
307
305
  getPluginApiRoutes,
308
306
  getPluginRoutes,
@@ -311,6 +309,7 @@ import {
311
309
  getWorkspaceTeamId,
312
310
  isDmChannel,
313
311
  normalizeSlackConversationId,
312
+ runWithSlackInstallationToken,
314
313
  runWithWorkspaceTeamId,
315
314
  setDashboardConversationLinkOptions,
316
315
  setPlugins,
@@ -318,20 +317,19 @@ import {
318
317
  verifyEventTaskCredentialSubject,
319
318
  verifyScheduledTaskCredentialSubject,
320
319
  verifySlackDirectCredentialSubject
321
- } from "./chunk-4CNDGK25.js";
320
+ } from "./chunk-JFPY6XFF.js";
322
321
  import "./chunk-3Y47VMHV.js";
323
322
  import {
324
- contextProvenance,
323
+ createSlackDestination,
325
324
  deleteProviderIdentityForSlackUser,
326
325
  getConversationEventStore,
327
326
  getConversationStore,
328
327
  getDb,
329
328
  getSqlExecutor,
330
- instructionProvenanceFor,
331
329
  requireSlackDestination,
332
330
  withConversationEventLock,
333
331
  withConversationMutationLock
334
- } from "./chunk-IZDYYYGP.js";
332
+ } from "./chunk-43LODHJM.js";
335
333
  import {
336
334
  juniorAgentBindings,
337
335
  juniorAgentInvocations,
@@ -339,13 +337,17 @@ import {
339
337
  juniorConversations,
340
338
  juniorSchedulerRuns,
341
339
  juniorSchedulerTasks
342
- } from "./chunk-BCHYQS4B.js";
343
- import "./chunk-SHJK75Z2.js";
340
+ } from "./chunk-VXL2LBPK.js";
341
+ import "./chunk-HWXP6RHG.js";
344
342
  import {
345
343
  acquireActiveLock,
346
344
  getStateAdapter,
347
345
  withActiveLock
348
- } from "./chunk-DUKIDPF6.js";
346
+ } from "./chunk-DOP3FIQC.js";
347
+ import {
348
+ contextProvenance,
349
+ instructionProvenanceFor
350
+ } from "./chunk-GFBR4S3Q.js";
349
351
  import {
350
352
  juniorDestinations
351
353
  } from "./chunk-VFUK3X5B.js";
@@ -354,7 +356,6 @@ import {
354
356
  completeObject,
355
357
  completeText,
356
358
  configureFunctionMaxDurationSeconds,
357
- defaultModelId,
358
359
  escapeXml,
359
360
  getChatConfig,
360
361
  getSlackBotToken,
@@ -363,16 +364,19 @@ import {
363
364
  getSlackReactionConfig,
364
365
  getSlackSigningSecret,
365
366
  isProviderRetryError,
366
- modelIdForProfile,
367
367
  setProfiles,
368
368
  setSlackReactionConfig
369
- } from "./chunk-6UDPINOX.js";
370
- import "./chunk-BHYRYYLY.js";
371
- import "./chunk-WQFEWULF.js";
369
+ } from "./chunk-AD64YMEC.js";
370
+ import {
371
+ defaultModelId,
372
+ modelIdForProfile
373
+ } from "./chunk-D4YV5TDV.js";
374
+ import "./chunk-FFYDRLXW.js";
375
+ import "./chunk-HKFLRIBD.js";
372
376
  import {
373
377
  pluginCatalogRuntime
374
- } from "./chunk-PJPRXO2T.js";
375
- import "./chunk-LHXIZLFF.js";
378
+ } from "./chunk-NRMAOGRS.js";
379
+ import "./chunk-64WF2GQ3.js";
376
380
  import {
377
381
  credentialContextForActor
378
382
  } from "./chunk-CEMMLV5L.js";
@@ -380,6 +384,7 @@ import {
380
384
  createActor,
381
385
  createSlackActor,
382
386
  createSlackResumeActor,
387
+ isActorUserId,
383
388
  parseActorUserId,
384
389
  parseSlackChannelId,
385
390
  parseSlackMessageTs
@@ -407,13 +412,13 @@ import {
407
412
  withContext,
408
413
  withLogContext,
409
414
  withSpan
410
- } from "./chunk-3S7ULUWW.js";
415
+ } from "./chunk-3CVEE6LA.js";
411
416
  import {
412
417
  continueTrace
413
418
  } from "./chunk-PEQXYSSE.js";
414
419
  import {
415
420
  JUNIOR_VERSION
416
- } from "./chunk-6VOYP4M6.js";
421
+ } from "./chunk-YXSBZRP7.js";
417
422
 
418
423
  // src/app.ts
419
424
  import { createRequire } from "module";
@@ -2741,9 +2746,831 @@ async function GET6(request) {
2741
2746
  // src/chat/ingress/slack-webhook.ts
2742
2747
  import {
2743
2748
  ChannelImpl,
2744
- ThreadImpl
2749
+ ThreadImpl as ThreadImpl3
2745
2750
  } from "chat";
2746
2751
 
2752
+ // src/chat/task-execution/slack-work.ts
2753
+ import {
2754
+ Message as Message3,
2755
+ ThreadImpl as ThreadImpl2
2756
+ } from "chat";
2757
+ import { z as z3 } from "zod";
2758
+
2759
+ // src/chat/ingress/message-router.ts
2760
+ import { Message } from "chat";
2761
+ function withNormalizedThreadId(message, threadId) {
2762
+ if (message.threadId === threadId) {
2763
+ return message;
2764
+ }
2765
+ return new Message({
2766
+ attachments: message.attachments,
2767
+ author: message.author,
2768
+ formatted: message.formatted,
2769
+ id: message.id,
2770
+ isMention: message.isMention,
2771
+ links: message.links,
2772
+ metadata: message.metadata,
2773
+ raw: message.raw,
2774
+ text: message.text,
2775
+ threadId
2776
+ });
2777
+ }
2778
+ function normalizeIncomingSlackThreadId(threadId, message) {
2779
+ if (!threadId.startsWith("slack:")) {
2780
+ return threadId;
2781
+ }
2782
+ if (!message || typeof message !== "object") {
2783
+ return threadId;
2784
+ }
2785
+ const raw = message.raw;
2786
+ if (!raw || typeof raw !== "object") {
2787
+ return threadId;
2788
+ }
2789
+ const channelId = nonEmptyString(raw.channel);
2790
+ const threadTs = nonEmptyString(raw.thread_ts) ?? nonEmptyString(raw.ts);
2791
+ if (!channelId || !threadTs) {
2792
+ return threadId;
2793
+ }
2794
+ return `slack:${channelId}:${threadTs}`;
2795
+ }
2796
+ function nonEmptyString(value) {
2797
+ if (typeof value !== "string") return void 0;
2798
+ const trimmed = value.trim();
2799
+ return trimmed || void 0;
2800
+ }
2801
+
2802
+ // src/chat/slack/attachment-fetchers.ts
2803
+ function rehydrateAttachmentFetchers(message, downloadPrivateSlackFile2 = downloadPrivateSlackFile) {
2804
+ for (const attachment of message.attachments) {
2805
+ if (!attachment.fetchData && attachment.url) {
2806
+ attachment.fetchData = () => downloadPrivateSlackFile2(attachment.url);
2807
+ }
2808
+ }
2809
+ }
2810
+
2811
+ // src/chat/slack/adapter-context.ts
2812
+ var initializedAdapters = /* @__PURE__ */ new WeakSet();
2813
+ async function getConnectedState(stateAdapter) {
2814
+ const state = stateAdapter ?? getStateAdapter();
2815
+ await state.connect();
2816
+ return state;
2817
+ }
2818
+ async function ensureSlackAdapterInitialized(args) {
2819
+ if (initializedAdapters.has(args.adapter)) {
2820
+ return;
2821
+ }
2822
+ const state = await getConnectedState(args.state);
2823
+ await args.adapter.initialize({
2824
+ getState: () => state
2825
+ });
2826
+ const internals = args.adapter;
2827
+ if (internals.defaultBotTokenProvider && !args.adapter.botUserId) {
2828
+ throw new Error("Slack adapter initialized without a resolved bot user id");
2829
+ }
2830
+ initializedAdapters.add(args.adapter);
2831
+ }
2832
+ function verifySlackSignature(args) {
2833
+ const internals = args.adapter;
2834
+ const verifySignature = internals.verifySignature;
2835
+ if (!verifySignature) {
2836
+ throw new Error("Slack adapter does not expose signature verification");
2837
+ }
2838
+ return verifySignature.call(
2839
+ args.adapter,
2840
+ args.body,
2841
+ args.request.headers.get("x-slack-request-timestamp"),
2842
+ args.request.headers.get("x-slack-signature")
2843
+ );
2844
+ }
2845
+ async function runWithSlackInstallation(args) {
2846
+ await ensureSlackAdapterInitialized({
2847
+ adapter: args.adapter,
2848
+ state: args.state
2849
+ });
2850
+ const internals = args.adapter;
2851
+ if (internals.defaultBotTokenProvider) {
2852
+ return await args.task();
2853
+ }
2854
+ const installationId = args.installation.isEnterpriseInstall ? args.installation.enterpriseId : args.installation.teamId;
2855
+ if (!installationId) {
2856
+ throw new Error("Slack installation context is missing team id");
2857
+ }
2858
+ if (!internals.resolveTokenForTeam || !internals.requestContext) {
2859
+ throw new Error("Slack adapter cannot resolve workspace installations");
2860
+ }
2861
+ const tokenContext = await internals.resolveTokenForTeam.call(
2862
+ args.adapter,
2863
+ installationId,
2864
+ args.installation.isEnterpriseInstall
2865
+ );
2866
+ if (!tokenContext) {
2867
+ throw new Error(
2868
+ `Slack installation token was not found for ${installationId}`
2869
+ );
2870
+ }
2871
+ return await internals.requestContext.run(
2872
+ {
2873
+ ...tokenContext,
2874
+ enterpriseId: args.installation.enterpriseId,
2875
+ isEnterpriseInstall: args.installation.isEnterpriseInstall
2876
+ },
2877
+ () => runWithSlackInstallationToken(tokenContext.token, args.task)
2878
+ );
2879
+ }
2880
+
2881
+ // src/chat/services/message-actor-identity.ts
2882
+ var messageActors = /* @__PURE__ */ new WeakMap();
2883
+ function canonicalUserId(author, actor) {
2884
+ const authorUserId = parseActorUserId(author.userId);
2885
+ if (authorUserId && authorUserId !== actor.userId) {
2886
+ throw new Error("Message actor user id mismatch");
2887
+ }
2888
+ const userId = authorUserId ?? actor.userId;
2889
+ if (!userId) {
2890
+ throw new Error("Message actor requires a user id");
2891
+ }
2892
+ return userId;
2893
+ }
2894
+ function actorFromAuthor(author) {
2895
+ const userId = parseActorUserId(author.userId);
2896
+ return userId ? { userId } : void 0;
2897
+ }
2898
+ function applyActorToAuthor(author, actor) {
2899
+ if (!isActorUserId(actor.userId)) {
2900
+ throw new Error("Message actor requires a user id");
2901
+ }
2902
+ author.userId = actor.userId;
2903
+ author.userName = actor.userName ?? "";
2904
+ author.fullName = actor.fullName ?? "";
2905
+ }
2906
+ function bindMessageActorIdentity(message, actor) {
2907
+ const userId = canonicalUserId(message.author, actor);
2908
+ const currentActor = createActor(actor, {
2909
+ platform: actor.platform,
2910
+ ...actor.platform === "slack" ? { teamId: actor.teamId } : void 0,
2911
+ userId
2912
+ });
2913
+ if (!currentActor) {
2914
+ throw new Error("Message actor requires a user id");
2915
+ }
2916
+ messageActors.set(message, currentActor);
2917
+ applyActorToAuthor(message.author, currentActor);
2918
+ return currentActor;
2919
+ }
2920
+ function getMessageActorIdentity(message) {
2921
+ return messageActors.get(message) ?? actorFromAuthor(message.author);
2922
+ }
2923
+ async function ensureSlackMessageActorIdentity(message, teamId, lookupSlackUser2) {
2924
+ const existing = messageActors.get(message);
2925
+ if (existing) {
2926
+ if (existing.platform !== "slack") {
2927
+ throw new Error("Slack message actor identity requires a Slack actor");
2928
+ }
2929
+ return existing;
2930
+ }
2931
+ const userId = parseActorUserId(message.author.userId);
2932
+ if (!userId) {
2933
+ throw new Error("Slack message actor identity requires a user id");
2934
+ }
2935
+ const actor = bindMessageActorIdentity(
2936
+ message,
2937
+ createSlackActor(teamId, userId, await lookupSlackUser2(teamId, userId))
2938
+ );
2939
+ if (actor.platform !== "slack") {
2940
+ throw new Error("Slack message actor identity requires a Slack actor");
2941
+ }
2942
+ return actor;
2943
+ }
2944
+
2945
+ // src/chat/task-execution/slack-resource-event.ts
2946
+ import { Message as Message2, ThreadImpl } from "chat";
2947
+ async function resolveSlackResourceEventThread(args) {
2948
+ const routing = await resolveConversationRouting({
2949
+ conversationId: args.conversationId,
2950
+ conversationStore: args.conversationStore
2951
+ });
2952
+ const destination = requireSlackDestination(
2953
+ routing?.destination ?? args.destination,
2954
+ "Slack resource-event turn"
2955
+ );
2956
+ const threadTs = routing?.source?.platform === "slack" ? routing.source.threadTs?.trim() : void 0;
2957
+ if (!threadTs) {
2958
+ throw new Error(
2959
+ `Conversation ${args.conversationId} is missing a Slack thread for resource-event delivery`
2960
+ );
2961
+ }
2962
+ return { destination, threadTs };
2963
+ }
2964
+ function isPlainResourceEventRecord(record) {
2965
+ return record.source === "resource_event" && isResourceEventMailboxMetadata(record.input.metadata) && !hasSlackConversationMetadata(record.input.metadata);
2966
+ }
2967
+ function hasSlackConversationMetadata(value) {
2968
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2969
+ return false;
2970
+ }
2971
+ const record = value;
2972
+ return record.platform === "slack" && typeof record.thread === "object" && record.thread !== null && typeof record.message === "object" && record.message !== null;
2973
+ }
2974
+ function buildResourceEventSlackMessage(args) {
2975
+ if (!isResourceEventMailboxMetadata(args.record.input.metadata)) {
2976
+ throw new Error(
2977
+ "Resource-event Slack turn requires resource-event metadata"
2978
+ );
2979
+ }
2980
+ const event = args.record.input.metadata.resourceEvent;
2981
+ const messageId = `resource-event-${event.subscriptionId}-${event.eventKey}`;
2982
+ const threadId = `slack:${args.channelId}:${args.threadTs}`;
2983
+ return new Message2({
2984
+ id: messageId,
2985
+ threadId,
2986
+ text: args.record.input.text,
2987
+ author: {
2988
+ userId: RESOURCE_EVENT_AUTHOR_ID,
2989
+ userName: "junior-event",
2990
+ fullName: "Junior event",
2991
+ isBot: true,
2992
+ isMe: false
2993
+ },
2994
+ isMention: false,
2995
+ attachments: [],
2996
+ metadata: {
2997
+ dateSent: new Date(args.record.createdAtMs),
2998
+ edited: false
2999
+ },
3000
+ formatted: { type: "root", children: [] },
3001
+ raw: {
3002
+ channel: args.channelId,
3003
+ event_type: "resource_event",
3004
+ resource_event_type: event.eventType,
3005
+ thread_ts: args.threadTs,
3006
+ type: "message",
3007
+ user: RESOURCE_EVENT_AUTHOR_ID
3008
+ }
3009
+ });
3010
+ }
3011
+ function buildResourceEventSlackThread(args) {
3012
+ const threadId = normalizeIncomingSlackThreadId(
3013
+ `slack:${args.channelId}:${args.threadTs}`,
3014
+ args.message
3015
+ );
3016
+ const message = withNormalizedThreadId(args.message, threadId);
3017
+ return new ThreadImpl({
3018
+ adapter: args.adapter,
3019
+ stateAdapter: args.state,
3020
+ id: threadId,
3021
+ channelId: args.channelId,
3022
+ currentMessage: message,
3023
+ initialMessage: message,
3024
+ isDM: args.channelId.startsWith("D"),
3025
+ isSubscribedContext: true
3026
+ });
3027
+ }
3028
+
3029
+ // src/chat/slack/message-control.ts
3030
+ var LEADING_MENTION_BEFORE_STEERING_RE = /^(\s*(?:<@[^>]+>|@[A-Za-z0-9._-]+\b)[\s,:-]*)!!\s*/;
3031
+ function stripLeadingSteeringOverride(text) {
3032
+ return text.replace(LEADING_MENTION_BEFORE_STEERING_RE, "$1").replace(/^\s*!!\s*/, "");
3033
+ }
3034
+
3035
+ // src/chat/task-execution/slack-work.ts
3036
+ var slackConversationRouteSchema = z3.enum(["mention", "subscribed"]);
3037
+ function hasSteeringOverride(text) {
3038
+ return stripLeadingSteeringOverride(text) !== text;
3039
+ }
3040
+ var serializedDateSchema = z3.iso.datetime();
3041
+ var mdastPointSchema = z3.object({
3042
+ column: z3.number().int().positive(),
3043
+ line: z3.number().int().positive(),
3044
+ offset: z3.number().int().nonnegative().optional()
3045
+ }).strict();
3046
+ var mdastPositionSchema = z3.object({
3047
+ end: mdastPointSchema,
3048
+ start: mdastPointSchema
3049
+ }).strict();
3050
+ function isOptionalNullableString(value) {
3051
+ return value === void 0 || value === null || typeof value === "string";
3052
+ }
3053
+ function isOptionalNullableBoolean(value) {
3054
+ return value === void 0 || value === null || typeof value === "boolean";
3055
+ }
3056
+ function hasValidMdastBase(node, fields) {
3057
+ const allowed = /* @__PURE__ */ new Set(["data", "position", "type", ...fields]);
3058
+ return Object.keys(node).every((key) => allowed.has(key)) && (node.data === void 0 || typeof node.data === "object" && node.data !== null && !Array.isArray(node.data)) && (node.position === void 0 || mdastPositionSchema.safeParse(node.position).success);
3059
+ }
3060
+ var mdastPhrasingTypes = /* @__PURE__ */ new Set([
3061
+ "break",
3062
+ "delete",
3063
+ "emphasis",
3064
+ "footnoteReference",
3065
+ "html",
3066
+ "image",
3067
+ "imageReference",
3068
+ "inlineCode",
3069
+ "link",
3070
+ "linkReference",
3071
+ "strong",
3072
+ "text"
3073
+ ]);
3074
+ var mdastBlockOrDefinitionTypes = /* @__PURE__ */ new Set([
3075
+ "blockquote",
3076
+ "code",
3077
+ "definition",
3078
+ "footnoteDefinition",
3079
+ "heading",
3080
+ "html",
3081
+ "list",
3082
+ "paragraph",
3083
+ "table",
3084
+ "thematicBreak"
3085
+ ]);
3086
+ var mdastListItemTypes = /* @__PURE__ */ new Set(["listItem"]);
3087
+ var mdastTableCellTypes = /* @__PURE__ */ new Set(["tableCell"]);
3088
+ var mdastTableRowTypes = /* @__PURE__ */ new Set(["tableRow"]);
3089
+ function hasMdastChildren(node, allowedTypes) {
3090
+ return Array.isArray(node.children) && node.children.every(
3091
+ (child) => isFormattedContentNode(child) && (!allowedTypes || typeof child === "object" && child !== null && !Array.isArray(child) && allowedTypes.has(String(child.type)))
3092
+ );
3093
+ }
3094
+ function isFormattedContentNode(value) {
3095
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3096
+ return false;
3097
+ }
3098
+ const node = value;
3099
+ switch (node.type) {
3100
+ case "break":
3101
+ case "thematicBreak":
3102
+ return hasValidMdastBase(node, []);
3103
+ case "html":
3104
+ case "inlineCode":
3105
+ case "text":
3106
+ case "yaml":
3107
+ return hasValidMdastBase(node, ["value"]) && typeof node.value === "string";
3108
+ case "code":
3109
+ return hasValidMdastBase(node, ["lang", "meta", "value"]) && typeof node.value === "string" && isOptionalNullableString(node.lang) && isOptionalNullableString(node.meta);
3110
+ case "delete":
3111
+ case "emphasis":
3112
+ case "paragraph":
3113
+ case "strong":
3114
+ case "tableCell":
3115
+ return hasValidMdastBase(node, ["children"]) && hasMdastChildren(node, mdastPhrasingTypes);
3116
+ case "blockquote":
3117
+ return hasValidMdastBase(node, ["children"]) && hasMdastChildren(node, mdastBlockOrDefinitionTypes);
3118
+ case "tableRow":
3119
+ return hasValidMdastBase(node, ["children"]) && hasMdastChildren(node, mdastTableCellTypes);
3120
+ case "heading":
3121
+ return hasValidMdastBase(node, ["children", "depth"]) && hasMdastChildren(node, mdastPhrasingTypes) && Number.isInteger(node.depth) && Number(node.depth) >= 1 && Number(node.depth) <= 6;
3122
+ case "list":
3123
+ return hasValidMdastBase(node, ["children", "ordered", "spread", "start"]) && hasMdastChildren(node, mdastListItemTypes) && isOptionalNullableBoolean(node.ordered) && isOptionalNullableBoolean(node.spread) && (node.start === void 0 || node.start === null || typeof node.start === "number" && Number.isFinite(node.start));
3124
+ case "listItem":
3125
+ return hasValidMdastBase(node, ["checked", "children", "spread"]) && hasMdastChildren(node, mdastBlockOrDefinitionTypes) && isOptionalNullableBoolean(node.checked) && isOptionalNullableBoolean(node.spread);
3126
+ case "table":
3127
+ return hasValidMdastBase(node, ["align", "children"]) && hasMdastChildren(node, mdastTableRowTypes) && (node.align === void 0 || node.align === null || Array.isArray(node.align) && node.align.every(
3128
+ (align) => align === null || align === "center" || align === "left" || align === "right"
3129
+ ));
3130
+ case "definition":
3131
+ return hasValidMdastBase(node, ["identifier", "label", "title", "url"]) && typeof node.identifier === "string" && typeof node.url === "string" && isOptionalNullableString(node.label) && isOptionalNullableString(node.title);
3132
+ case "footnoteDefinition":
3133
+ return hasValidMdastBase(node, ["children", "identifier", "label"]) && hasMdastChildren(node, mdastBlockOrDefinitionTypes) && typeof node.identifier === "string" && isOptionalNullableString(node.label);
3134
+ case "footnoteReference":
3135
+ return hasValidMdastBase(node, ["identifier", "label"]) && typeof node.identifier === "string" && isOptionalNullableString(node.label);
3136
+ case "image":
3137
+ return hasValidMdastBase(node, ["alt", "title", "url"]) && typeof node.url === "string" && isOptionalNullableString(node.alt) && isOptionalNullableString(node.title);
3138
+ case "imageReference":
3139
+ return hasValidMdastBase(node, [
3140
+ "alt",
3141
+ "identifier",
3142
+ "label",
3143
+ "referenceType"
3144
+ ]) && typeof node.identifier === "string" && isOptionalNullableString(node.alt) && isOptionalNullableString(node.label) && (node.referenceType === "collapsed" || node.referenceType === "full" || node.referenceType === "shortcut");
3145
+ case "link":
3146
+ return hasValidMdastBase(node, ["children", "title", "url"]) && hasMdastChildren(node, mdastPhrasingTypes) && typeof node.url === "string" && isOptionalNullableString(node.title);
3147
+ case "linkReference":
3148
+ return hasValidMdastBase(node, [
3149
+ "children",
3150
+ "identifier",
3151
+ "label",
3152
+ "referenceType"
3153
+ ]) && hasMdastChildren(node, mdastPhrasingTypes) && typeof node.identifier === "string" && isOptionalNullableString(node.label) && (node.referenceType === "collapsed" || node.referenceType === "full" || node.referenceType === "shortcut");
3154
+ default:
3155
+ return false;
3156
+ }
3157
+ }
3158
+ var formattedContentSchema = z3.custom(
3159
+ (value) => {
3160
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3161
+ return false;
3162
+ }
3163
+ const root = value;
3164
+ return root.type === "root" && hasValidMdastBase(root, ["children"]) && hasMdastChildren(root);
3165
+ },
3166
+ "must be a valid formatted-content root"
3167
+ );
3168
+ var serializedMessageSchema = z3.object({
3169
+ _type: z3.literal("chat:Message"),
3170
+ attachments: z3.array(
3171
+ z3.object({
3172
+ type: z3.enum(["image", "file", "video", "audio"]),
3173
+ url: z3.string().optional(),
3174
+ name: z3.string().optional(),
3175
+ mimeType: z3.string().optional(),
3176
+ size: z3.number().finite().optional(),
3177
+ width: z3.number().finite().optional(),
3178
+ height: z3.number().finite().optional(),
3179
+ fetchMetadata: z3.record(z3.string(), z3.string()).optional()
3180
+ }).strict()
3181
+ ),
3182
+ author: z3.object({
3183
+ userId: z3.string(),
3184
+ userName: z3.string(),
3185
+ fullName: z3.string(),
3186
+ isBot: z3.union([z3.boolean(), z3.literal("unknown")]),
3187
+ isMe: z3.boolean()
3188
+ }).strict(),
3189
+ formatted: formattedContentSchema,
3190
+ id: z3.string().min(1),
3191
+ isMention: z3.boolean().optional(),
3192
+ links: z3.array(
3193
+ z3.object({
3194
+ url: z3.string(),
3195
+ title: z3.string().optional(),
3196
+ description: z3.string().optional(),
3197
+ imageUrl: z3.string().optional(),
3198
+ siteName: z3.string().optional()
3199
+ }).strict()
3200
+ ).optional(),
3201
+ metadata: z3.object({
3202
+ dateSent: serializedDateSchema,
3203
+ edited: z3.boolean(),
3204
+ editedAt: serializedDateSchema.optional()
3205
+ }).strict(),
3206
+ raw: z3.unknown(),
3207
+ text: z3.string(),
3208
+ threadId: z3.string().min(1)
3209
+ }).strict();
3210
+ var serializedThreadSchema = z3.object({
3211
+ _type: z3.literal("chat:Thread"),
3212
+ adapterName: z3.literal("slack"),
3213
+ channelId: z3.string().min(1),
3214
+ channelVisibility: z3.enum(["private", "workspace", "external", "unknown"]).optional(),
3215
+ currentMessage: serializedMessageSchema.optional(),
3216
+ id: z3.string().min(1),
3217
+ isDM: z3.boolean()
3218
+ }).strict();
3219
+ var slackInstallationSchema = z3.object({
3220
+ enterpriseId: z3.string().optional(),
3221
+ isEnterpriseInstall: z3.boolean().optional(),
3222
+ teamId: z3.string().optional()
3223
+ }).strict();
3224
+ var slackConversationMessageMetadataBaseSchema = z3.object({
3225
+ installation: slackInstallationSchema.optional(),
3226
+ message: serializedMessageSchema,
3227
+ platform: z3.literal("slack"),
3228
+ route: slackConversationRouteSchema,
3229
+ thread: serializedThreadSchema
3230
+ });
3231
+ var slackConversationMessageMetadataSchema = z3.union([
3232
+ slackConversationMessageMetadataBaseSchema.strict(),
3233
+ slackConversationMessageMetadataBaseSchema.extend({
3234
+ kind: z3.literal("resource_event"),
3235
+ resourceEvent: z3.object({
3236
+ eventKey: z3.string(),
3237
+ eventType: z3.string(),
3238
+ namespace: z3.string(),
3239
+ identifier: z3.string(),
3240
+ subscriptionId: z3.string()
3241
+ }).strict()
3242
+ }).strict()
3243
+ ]);
3244
+ function requireSlackAuthorId(message) {
3245
+ const authorId = parseActorUserId(message.author.userId);
3246
+ if (!authorId) {
3247
+ throw new Error("Slack message requires an actor user id");
3248
+ }
3249
+ return authorId;
3250
+ }
3251
+ function getConnectedState2(stateAdapter) {
3252
+ return stateAdapter ?? getStateAdapter();
3253
+ }
3254
+ function parseSlackMetadata(value) {
3255
+ const parsed = slackConversationMessageMetadataSchema.safeParse(value);
3256
+ return parsed.success ? parsed.data : void 0;
3257
+ }
3258
+ function compareInboundMessages(left, right) {
3259
+ return left.createdAtMs - right.createdAtMs || left.receivedAtMs - right.receivedAtMs || left.inboundMessageId.localeCompare(right.inboundMessageId);
3260
+ }
3261
+ function routeForRecords(records) {
3262
+ return records.some((record) => {
3263
+ if (isPlainResourceEventRecord(record)) {
3264
+ return false;
3265
+ }
3266
+ const metadata = parseSlackMetadata(record.input.metadata);
3267
+ if (!metadata) {
3268
+ throw new Error("Conversation mailbox record is not Slack metadata");
3269
+ }
3270
+ return metadata.route === "mention";
3271
+ }) ? "mention" : "subscribed";
3272
+ }
3273
+ function restoreMessage(args) {
3274
+ if (isPlainResourceEventRecord(args.record)) {
3275
+ if (!args.threadTs) {
3276
+ throw new Error(
3277
+ "Resource-event Slack turn requires a thread timestamp"
3278
+ );
3279
+ }
3280
+ return buildResourceEventSlackMessage({
3281
+ channelId: args.channelId,
3282
+ record: args.record,
3283
+ threadTs: args.threadTs
3284
+ });
3285
+ }
3286
+ const metadata = parseSlackMetadata(args.record.input.metadata);
3287
+ if (!metadata) {
3288
+ throw new Error("Conversation mailbox record is not a Slack message");
3289
+ }
3290
+ const message = Message3.fromJSON(metadata.message);
3291
+ message.attachments = message.attachments.map(
3292
+ (attachment) => args.adapter.rehydrateAttachment(attachment)
3293
+ );
3294
+ rehydrateAttachmentFetchers(message);
3295
+ return message;
3296
+ }
3297
+ async function bindSlackActorIdentities(args) {
3298
+ const byAuthorId = /* @__PURE__ */ new Map();
3299
+ for (const message of args.messages) {
3300
+ if (isResourceEventSlackMessage(message)) {
3301
+ continue;
3302
+ }
3303
+ const authorId = requireSlackAuthorId(message);
3304
+ byAuthorId.set(authorId, [...byAuthorId.get(authorId) ?? [], message]);
3305
+ }
3306
+ await Promise.all(
3307
+ [...byAuthorId].map(async ([authorId, messages]) => {
3308
+ const profile = await args.lookupSlackUser(args.teamId, authorId);
3309
+ await Promise.all(
3310
+ messages.map(
3311
+ (message) => ensureSlackMessageActorIdentity(
3312
+ message,
3313
+ args.teamId,
3314
+ async () => profile
3315
+ )
3316
+ )
3317
+ );
3318
+ })
3319
+ );
3320
+ }
3321
+ function restoreThread(args) {
3322
+ const threadId = normalizeIncomingSlackThreadId(
3323
+ args.threadJson.id,
3324
+ args.message
3325
+ );
3326
+ const message = withNormalizedThreadId(args.message, threadId);
3327
+ return new ThreadImpl2({
3328
+ adapter: args.adapter,
3329
+ stateAdapter: args.state,
3330
+ id: threadId,
3331
+ channelId: args.threadJson.channelId,
3332
+ channelVisibility: args.threadJson.channelVisibility,
3333
+ currentMessage: message,
3334
+ initialMessage: message,
3335
+ isDM: args.threadJson.isDM,
3336
+ isSubscribedContext: args.isSubscribedContext
3337
+ });
3338
+ }
3339
+ function getInstallation(records) {
3340
+ for (let index = records.length - 1; index >= 0; index -= 1) {
3341
+ const metadata = parseSlackMetadata(records[index]?.input.metadata);
3342
+ if (metadata?.installation) {
3343
+ return metadata.installation;
3344
+ }
3345
+ }
3346
+ return {};
3347
+ }
3348
+ function getPendingRecords(work) {
3349
+ if (!work) {
3350
+ return [];
3351
+ }
3352
+ return work.execution.pendingMessages.sort(compareInboundMessages);
3353
+ }
3354
+ function createSlackConversationWorker(options) {
3355
+ const crossActorMidRunMode = options.crossActorMidRunMode ?? botConfig.crossActorMidRunMode;
3356
+ return async (context) => {
3357
+ const adapter = options.getSlackAdapter();
3358
+ const actorLookup = options.lookupSlackUser ?? lookupSlackUser;
3359
+ const state = getConnectedState2(options.state);
3360
+ await state.connect();
3361
+ const records = getPendingRecords({
3362
+ execution: { pendingMessages: [...context.attempt.messages] }
3363
+ });
3364
+ if (records.length === 0) {
3365
+ const destination = requireSlackDestination(
3366
+ context.destination,
3367
+ "Slack paused-turn recovery"
3368
+ );
3369
+ try {
3370
+ await runWithSlackInstallation({
3371
+ adapter,
3372
+ installation: { teamId: destination.teamId },
3373
+ state,
3374
+ task: async () => {
3375
+ await options.runNextPausedTurn(context.conversationId, {
3376
+ shouldYield: context.shouldYield
3377
+ });
3378
+ }
3379
+ });
3380
+ } catch (error) {
3381
+ if (isCooperativeTurnYieldError(error)) {
3382
+ return { status: "yielded" };
3383
+ }
3384
+ throw error;
3385
+ }
3386
+ return { status: "completed" };
3387
+ }
3388
+ const latestRecord = records[records.length - 1];
3389
+ if (!latestRecord) {
3390
+ return { status: "completed" };
3391
+ }
3392
+ const hasPlainResourceEvent = records.some(isPlainResourceEventRecord);
3393
+ const publishExternally = hasPlainResourceEvent ? true : latestRecord.publishExternally ?? context.publishExternally;
3394
+ const latestMetadata = isPlainResourceEventRecord(latestRecord) ? void 0 : parseSlackMetadata(latestRecord.input.metadata);
3395
+ if (!isPlainResourceEventRecord(latestRecord) && !latestMetadata) {
3396
+ throw new Error(
3397
+ "Latest conversation mailbox record is not Slack metadata"
3398
+ );
3399
+ }
3400
+ if (!await context.checkIn()) {
3401
+ return { status: "lost_lease" };
3402
+ }
3403
+ const resourceEventThread = hasPlainResourceEvent ? await resolveSlackResourceEventThread({
3404
+ conversationId: context.conversationId,
3405
+ conversationStore: options.conversationStore,
3406
+ destination: context.destination
3407
+ }) : void 0;
3408
+ const turnResult = await runWithSlackInstallation({
3409
+ adapter,
3410
+ installation: resourceEventThread ? { teamId: resourceEventThread.destination.teamId } : getInstallation(records),
3411
+ state,
3412
+ task: async () => {
3413
+ const destination = resourceEventThread?.destination ?? requireSlackDestination(
3414
+ context.destination,
3415
+ "Slack conversation work"
3416
+ );
3417
+ const threadTs = resourceEventThread?.threadTs;
3418
+ const messages = records.map(
3419
+ (record) => restoreMessage({
3420
+ adapter,
3421
+ channelId: destination.channelId,
3422
+ record,
3423
+ ...threadTs ? { threadTs } : void 0
3424
+ })
3425
+ );
3426
+ await bindSlackActorIdentities({
3427
+ lookupSlackUser: actorLookup,
3428
+ messages,
3429
+ teamId: destination.teamId
3430
+ });
3431
+ const latestMessage = messages[messages.length - 1];
3432
+ if (!latestMessage) {
3433
+ return;
3434
+ }
3435
+ const route = routeForRecords(records);
3436
+ const thread = isPlainResourceEventRecord(latestRecord) && threadTs ? buildResourceEventSlackThread({
3437
+ adapter,
3438
+ channelId: destination.channelId,
3439
+ message: latestMessage,
3440
+ state,
3441
+ threadTs
3442
+ }) : restoreThread({
3443
+ adapter,
3444
+ isSubscribedContext: route === "subscribed",
3445
+ message: latestMessage,
3446
+ state,
3447
+ threadJson: latestMetadata.thread
3448
+ });
3449
+ const skipped = messages.slice(0, -1);
3450
+ const messageContext = {
3451
+ skipped,
3452
+ totalSinceLastHandler: messages.length
3453
+ };
3454
+ const activeAuthorId = isResourceEventSlackMessage(latestMessage) ? RESOURCE_EVENT_AUTHOR_ID : requireSlackAuthorId(latestMessage);
3455
+ let initialMessagesAcked = false;
3456
+ const ack = async () => {
3457
+ if (initialMessagesAcked) {
3458
+ return;
3459
+ }
3460
+ try {
3461
+ await context.attempt.ack();
3462
+ initialMessagesAcked = true;
3463
+ } catch {
3464
+ throw new TurnInputCommitLostError(
3465
+ `Conversation work lease lost before Slack inbox ack for ${context.conversationId}`
3466
+ );
3467
+ }
3468
+ };
3469
+ const drainSteeringMessages = async (accept) => {
3470
+ await context.attempt.drain(async (pendingRecords) => {
3471
+ const candidates = pendingRecords.filter(
3472
+ (record) => isPlainResourceEventRecord(record) ? publishExternally : record.publishExternally === publishExternally
3473
+ ).map((record) => ({
3474
+ inboundMessageId: record.inboundMessageId,
3475
+ message: restoreMessage({
3476
+ adapter,
3477
+ channelId: destination.channelId,
3478
+ record,
3479
+ ...threadTs ? { threadTs } : void 0
3480
+ })
3481
+ })).filter(
3482
+ (candidate) => crossActorMidRunMode === "steer" || isResourceEventSlackMessage(candidate.message) || requireSlackAuthorId(candidate.message) === activeAuthorId || hasSteeringOverride(candidate.message.text)
3483
+ );
3484
+ return candidates.length > 0 ? await accept(candidates) : [];
3485
+ });
3486
+ };
3487
+ try {
3488
+ if (route === "mention") {
3489
+ await options.runtime.handleNewMention(thread, latestMessage, {
3490
+ conversationId: context.conversationId,
3491
+ destination,
3492
+ publishExternally,
3493
+ messageContext,
3494
+ drainSteeringMessages,
3495
+ ack,
3496
+ isFinalAttempt: context.attempt.isFinalAttempt,
3497
+ shouldYield: context.shouldYield
3498
+ });
3499
+ } else {
3500
+ await options.runtime.handleSubscribedMessage(
3501
+ thread,
3502
+ latestMessage,
3503
+ {
3504
+ conversationId: context.conversationId,
3505
+ destination,
3506
+ publishExternally,
3507
+ messageContext,
3508
+ drainSteeringMessages,
3509
+ ack,
3510
+ isFinalAttempt: context.attempt.isFinalAttempt,
3511
+ shouldYield: context.shouldYield
3512
+ }
3513
+ );
3514
+ }
3515
+ } catch (error) {
3516
+ if (isTurnInputDeferredError(error)) {
3517
+ return { status: "deferred" };
3518
+ }
3519
+ if (isCooperativeTurnYieldError(error)) {
3520
+ return { status: "yielded" };
3521
+ }
3522
+ if (isTurnInputCommitLostError(error)) {
3523
+ return { status: "lost_lease" };
3524
+ }
3525
+ throw error;
3526
+ }
3527
+ }
3528
+ });
3529
+ if (turnResult?.status === "deferred" || turnResult?.status === "yielded" || turnResult?.status === "lost_lease") {
3530
+ return turnResult;
3531
+ }
3532
+ return { status: "completed" };
3533
+ };
3534
+ }
3535
+ function buildSlackInboundMessage(args) {
3536
+ const authorId = requireSlackAuthorId(args.message);
3537
+ const destination = createSlackDestination({
3538
+ channelId: args.thread.channelId,
3539
+ teamId: args.installation?.teamId
3540
+ });
3541
+ if (!destination) {
3542
+ throw new Error("Slack inbound message requires destination context");
3543
+ }
3544
+ const hasInterruptOverride = hasSteeringOverride(args.message.text);
3545
+ return {
3546
+ conversationId: args.conversationId,
3547
+ destination,
3548
+ inboundMessageId: [
3549
+ "slack",
3550
+ args.installation?.teamId ?? args.installation?.enterpriseId ?? "unknown",
3551
+ args.conversationId,
3552
+ args.message.id
3553
+ ].join(":"),
3554
+ delivery: args.message.isMention || hasInterruptOverride ? "interrupt" : "defer",
3555
+ source: "slack",
3556
+ createdAtMs: args.message.metadata.dateSent.getTime(),
3557
+ receivedAtMs: args.receivedAtMs,
3558
+ publishExternally: true,
3559
+ input: {
3560
+ text: args.message.text || " ",
3561
+ authorId,
3562
+ attachments: args.message.attachments,
3563
+ metadata: {
3564
+ platform: "slack",
3565
+ route: args.route,
3566
+ installation: args.installation,
3567
+ thread: serializedThreadSchema.parse(args.thread.toJSON()),
3568
+ message: args.message.toJSON()
3569
+ }
3570
+ }
3571
+ };
3572
+ }
3573
+
2747
3574
  // src/chat/ingress/bot-mention.ts
2748
3575
  function escapeRegExp(value) {
2749
3576
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -2810,7 +3637,7 @@ function textMentionsBot(text, botUserId) {
2810
3637
  }
2811
3638
 
2812
3639
  // src/chat/ingress/message-changed.ts
2813
- import { Message } from "chat";
3640
+ import { Message as Message4 } from "chat";
2814
3641
  function getEditedMentionMessageId(messageTs) {
2815
3642
  return `${messageTs}:message_changed_mention`;
2816
3643
  }
@@ -2877,7 +3704,7 @@ function extractMessageChangedMention(body, botUserId, adapter) {
2877
3704
  ...sourceTeam ? { source_team: sourceTeam } : void 0,
2878
3705
  ...botId ? { bot_id: botId } : void 0
2879
3706
  };
2880
- const message = new Message({
3707
+ const message = new Message4({
2881
3708
  id: getEditedMentionMessageId(messageTs),
2882
3709
  threadId,
2883
3710
  text: newText,
@@ -3116,7 +3943,7 @@ function normalizeMessageThreadId(message) {
3116
3943
  }
3117
3944
  async function buildThread(args) {
3118
3945
  const normalized = normalizeMessageThreadId(args.message);
3119
- return new ThreadImpl({
3946
+ return new ThreadImpl3({
3120
3947
  adapter: args.adapter,
3121
3948
  stateAdapter: args.state,
3122
3949
  id: normalized.threadId,
@@ -3745,7 +4572,7 @@ function registerVercelWorkspaceSnapshotJobDevConsumer() {
3745
4572
  }
3746
4573
 
3747
4574
  // src/chat/services/subscribed-decision.ts
3748
- import { z as z3 } from "zod";
4575
+ import { z as z4 } from "zod";
3749
4576
 
3750
4577
  // src/chat/services/subscribed-reply-router-policy.ts
3751
4578
  function buildSubscribedReplyRouterPolicy(assistantName) {
@@ -3790,13 +4617,13 @@ Assess conversation floor ownership and whether the latest message continues wor
3790
4617
  }
3791
4618
 
3792
4619
  // src/chat/services/subscribed-decision.ts
3793
- var replyDecisionSchema = z3.object({
3794
- should_reply: z3.boolean().describe("Whether Junior should respond to this thread message."),
3795
- should_unsubscribe: z3.boolean().describe(
4620
+ var replyDecisionSchema = z4.object({
4621
+ should_reply: z4.boolean().describe("Whether Junior should respond to this thread message."),
4622
+ should_unsubscribe: z4.boolean().describe(
3796
4623
  "Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
3797
4624
  ),
3798
- confidence: z3.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
3799
- reason: z3.string().describe("Short reason for the decision; use an empty string if none.")
4625
+ confidence: z4.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
4626
+ reason: z4.string().describe("Short reason for the decision; use an empty string if none.")
3800
4627
  }).strict();
3801
4628
  var ROUTER_CONFIDENCE_THRESHOLD = 0.7;
3802
4629
  var ROUTER_CLASSIFIER_MAX_TOKENS = 400;
@@ -4218,9 +5045,10 @@ function shouldRethrowTurnControlError(error) {
4218
5045
  function getQueuedMessages(context, options) {
4219
5046
  return (context?.skipped ?? []).map((message) => {
4220
5047
  const content = parseContent(message);
4221
- const stripped = options.stripLeadingBotMention(
5048
+ const stripped = stripLeadingBotMention(
4222
5049
  stripLeadingSteeringOverride(content.topLevelText),
4223
5050
  {
5051
+ botUserId: options.botUserId,
4224
5052
  stripLeadingSlackMentionToken: options.explicitMention || Boolean(message.isMention)
4225
5053
  }
4226
5054
  );
@@ -4283,6 +5111,7 @@ function shouldPublishExternally(publishExternally) {
4283
5111
  return publishExternally !== false;
4284
5112
  }
4285
5113
  function createSlackTurnRuntime(deps) {
5114
+ const turnLifecycle = getTurnLifecycle();
4286
5115
  const logContext = (args) => buildLogContext(deps, args);
4287
5116
  const maybeHandleThreadOptOutDecision = async (args) => {
4288
5117
  if (!args.decision?.shouldUnsubscribe) {
@@ -4295,11 +5124,11 @@ function createSlackTurnRuntime(deps) {
4295
5124
  return true;
4296
5125
  };
4297
5126
  const failConversationTurn = async (args) => {
4298
- const conversationId = deps.getThreadId(args.thread, args.message) ?? deps.getRunId(args.thread, args.message);
5127
+ const conversationId = getThreadId(args.thread, args.message) ?? getRunId(args.thread, args.message);
4299
5128
  if (!conversationId) {
4300
5129
  return;
4301
5130
  }
4302
- await deps.failConversationTurn({
5131
+ await turnLifecycle.fail({
4303
5132
  conversationId,
4304
5133
  createdAtMs: deps.now(),
4305
5134
  eventId: args.eventId,
@@ -4328,7 +5157,7 @@ function createSlackTurnRuntime(deps) {
4328
5157
  const processingReactionByMessage = /* @__PURE__ */ new Map();
4329
5158
  return {
4330
5159
  start: async (context, targetMessage) => {
4331
- const channelId = deps.getChannelId(thread, targetMessage);
5160
+ const channelId = getChannelId(thread, targetMessage);
4332
5161
  const messageTs = getMessageTs(targetMessage);
4333
5162
  const reactionKey = channelId && messageTs ? `${channelId}:${messageTs}` : void 0;
4334
5163
  if (reactionKey) {
@@ -4337,10 +5166,9 @@ function createSlackTurnRuntime(deps) {
4337
5166
  return existing;
4338
5167
  }
4339
5168
  }
4340
- const started = await startSlackProcessingReaction({
5169
+ const started = await startProcessingReaction({
4341
5170
  thread,
4342
- message: targetMessage,
4343
- logException: deps.logException
5171
+ message: targetMessage
4344
5172
  });
4345
5173
  processingReactions.push(started);
4346
5174
  if (reactionKey) {
@@ -4356,7 +5184,7 @@ function createSlackTurnRuntime(deps) {
4356
5184
  try {
4357
5185
  await args.thread.post(buildTurnFailureResponse(args.eventId));
4358
5186
  } catch (postError) {
4359
- deps.logException(postError, args.postFailureEventName, {
5187
+ logException(postError, args.postFailureEventName, {
4360
5188
  "app.slack.reply_stage": "error_fallback_post",
4361
5189
  "app.error.original_event_id": args.eventId,
4362
5190
  ...getSlackErrorObservabilityAttributes(postError)
@@ -4367,15 +5195,16 @@ function createSlackTurnRuntime(deps) {
4367
5195
  const decideSteeringMessage = async (thread, candidate, conversationContext) => {
4368
5196
  const { message } = candidate;
4369
5197
  const context = {
4370
- threadId: deps.getThreadId(thread, message),
5198
+ threadId: getThreadId(thread, message),
4371
5199
  actorId: message.author.userId,
4372
- channelId: deps.getChannelId(thread, message),
4373
- runId: deps.getRunId(thread, message)
5200
+ channelId: getChannelId(thread, message),
5201
+ runId: getRunId(thread, message)
4374
5202
  };
4375
5203
  const content = parseContent(message);
4376
- const strippedUserText = deps.stripLeadingBotMention(
5204
+ const strippedUserText = stripLeadingBotMention(
4377
5205
  stripLeadingSteeringOverride(content.topLevelText),
4378
5206
  {
5207
+ botUserId: deps.getBotUserId(),
4379
5208
  stripLeadingSlackMentionToken: Boolean(message.isMention)
4380
5209
  }
4381
5210
  );
@@ -4407,7 +5236,7 @@ function createSlackTurnRuntime(deps) {
4407
5236
  runId: args.context.runId
4408
5237
  }),
4409
5238
  () => {
4410
- deps.logWarn("subscribed_message.reply.skipped", {
5239
+ logWarn("subscribed_message.reply.skipped", {
4411
5240
  "app.decision.reason": args.decision.reason
4412
5241
  });
4413
5242
  }
@@ -4503,7 +5332,7 @@ function createSlackTurnRuntime(deps) {
4503
5332
  }
4504
5333
  } catch (error) {
4505
5334
  withLogContext(args.context, () => {
4506
- deps.logException(error, "agent.turn.steering_flush.failed");
5335
+ logException(error, "agent.turn.steering_flush.failed");
4507
5336
  });
4508
5337
  }
4509
5338
  };
@@ -4520,18 +5349,18 @@ function createSlackTurnRuntime(deps) {
4520
5349
  thread,
4521
5350
  pending: skippedSteeringMessages,
4522
5351
  context: logContext({
4523
- threadId: deps.getThreadId(thread, message),
5352
+ threadId: getThreadId(thread, message),
4524
5353
  actorId: message.author.userId,
4525
5354
  actorUserName: actorUserName(message),
4526
- channelId: deps.getChannelId(thread, message),
4527
- runId: deps.getRunId(thread, message)
5355
+ channelId: getChannelId(thread, message),
5356
+ runId: getRunId(thread, message)
4528
5357
  })
4529
5358
  });
4530
5359
  };
4531
5360
  try {
4532
- const threadId = deps.getThreadId(thread, message);
4533
- const channelId = deps.getChannelId(thread, message);
4534
- const runId = deps.getRunId(thread, message);
5361
+ const threadId = getThreadId(thread, message);
5362
+ const channelId = getChannelId(thread, message);
5363
+ const runId = getRunId(thread, message);
4535
5364
  const context = logContext({
4536
5365
  threadId,
4537
5366
  channelId,
@@ -4544,11 +5373,11 @@ function createSlackTurnRuntime(deps) {
4544
5373
  processingReaction,
4545
5374
  hooks
4546
5375
  );
4547
- await deps.withSpan("chat.turn", "chat.turn", context, async () => {
5376
+ await withSpan("chat.turn", "chat.turn", context, async () => {
4548
5377
  await thread.subscribe();
4549
5378
  const queuedMessages = getQueuedMessages(hooks.messageContext, {
4550
- explicitMention: true,
4551
- stripLeadingBotMention: deps.stripLeadingBotMention
5379
+ botUserId: deps.getBotUserId(),
5380
+ explicitMention: true
4552
5381
  });
4553
5382
  let queuedProcessingReactionsStarted = false;
4554
5383
  const startQueuedProcessingReactions = async () => {
@@ -4568,6 +5397,7 @@ function createSlackTurnRuntime(deps) {
4568
5397
  await startQueuedProcessingReactions();
4569
5398
  };
4570
5399
  const drainSteeringMessages = createAcceptedSteeringDrain(hooks, {
5400
+ botUserId: deps.getBotUserId(),
4571
5401
  explicitMention: true,
4572
5402
  onAcceptedForProcessing: async (messages) => {
4573
5403
  await Promise.all(
@@ -4586,8 +5416,7 @@ function createSlackTurnRuntime(deps) {
4586
5416
  conversationContext: drainContext?.conversationContext,
4587
5417
  messages,
4588
5418
  thread
4589
- }),
4590
- stripLeadingBotMention: deps.stripLeadingBotMention
5419
+ })
4591
5420
  });
4592
5421
  await deps.executeSlackTurn(thread, message, {
4593
5422
  explicitMention: true,
@@ -4606,11 +5435,11 @@ function createSlackTurnRuntime(deps) {
4606
5435
  });
4607
5436
  } catch (error) {
4608
5437
  const failureLogContext = logContext({
4609
- threadId: deps.getThreadId(thread, message),
5438
+ threadId: getThreadId(thread, message),
4610
5439
  actorId: message.author.userId,
4611
5440
  actorUserName: actorUserName(message),
4612
- channelId: deps.getChannelId(thread, message),
4613
- runId: deps.getRunId(thread, message)
5441
+ channelId: getChannelId(thread, message),
5442
+ runId: getRunId(thread, message)
4614
5443
  });
4615
5444
  const classifiedFailure = getConversationTurnBoundaryError(error);
4616
5445
  const failureCause = classifiedFailure?.cause ?? error;
@@ -4623,7 +5452,7 @@ function createSlackTurnRuntime(deps) {
4623
5452
  const failureCode = classifiedFailure?.failureCode ?? "agent_run_failed";
4624
5453
  if (failureCause instanceof SlackActionError && failureCause.code === "read_only_channel") {
4625
5454
  withLogContext(failureLogContext, () => {
4626
- deps.logWarn("mention.handler.skipped", {
5455
+ logWarn("mention.handler.skipped", {
4627
5456
  "app.decision.reason": "read_only_channel"
4628
5457
  });
4629
5458
  });
@@ -4631,7 +5460,7 @@ function createSlackTurnRuntime(deps) {
4631
5460
  }
4632
5461
  const eventId = classifiedFailure?.eventId ?? withLogContext(
4633
5462
  failureLogContext,
4634
- () => deps.logException(failureCause, "mention.handler.failed")
5463
+ () => logException(failureCause, "mention.handler.failed")
4635
5464
  );
4636
5465
  if (!acked && hooks.isFinalAttempt === false) {
4637
5466
  return;
@@ -4669,11 +5498,11 @@ function createSlackTurnRuntime(deps) {
4669
5498
  thread,
4670
5499
  pending: skippedSteeringMessages,
4671
5500
  context: logContext({
4672
- threadId: deps.getThreadId(thread, message),
5501
+ threadId: getThreadId(thread, message),
4673
5502
  actorId: message.author.userId,
4674
5503
  actorUserName: actorUserName(message),
4675
- channelId: deps.getChannelId(thread, message),
4676
- runId: deps.getRunId(thread, message)
5504
+ channelId: getChannelId(thread, message),
5505
+ runId: getRunId(thread, message)
4677
5506
  })
4678
5507
  });
4679
5508
  await processingReactions.stopAll();
@@ -4692,18 +5521,18 @@ function createSlackTurnRuntime(deps) {
4692
5521
  thread,
4693
5522
  pending: skippedSteeringMessages,
4694
5523
  context: logContext({
4695
- threadId: deps.getThreadId(thread, message),
5524
+ threadId: getThreadId(thread, message),
4696
5525
  actorId: message.author.userId,
4697
5526
  actorUserName: actorUserName(message),
4698
- channelId: deps.getChannelId(thread, message),
4699
- runId: deps.getRunId(thread, message)
5527
+ channelId: getChannelId(thread, message),
5528
+ runId: getRunId(thread, message)
4700
5529
  })
4701
5530
  });
4702
5531
  };
4703
5532
  try {
4704
- const threadId = deps.getThreadId(thread, message);
4705
- const channelId = deps.getChannelId(thread, message);
4706
- const runId = deps.getRunId(thread, message);
5533
+ const threadId = getThreadId(thread, message);
5534
+ const channelId = getChannelId(thread, message);
5535
+ const runId = getRunId(thread, message);
4707
5536
  const isResourceEventNotification = isResourceEventSlackMessage(message);
4708
5537
  const actorId = isResourceEventNotification ? void 0 : message.author.userId;
4709
5538
  const turnContext = logContext({
@@ -4713,11 +5542,12 @@ function createSlackTurnRuntime(deps) {
4713
5542
  channelId,
4714
5543
  runId
4715
5544
  });
4716
- await deps.withSpan("chat.turn", "chat.turn", turnContext, async () => {
5545
+ await withSpan("chat.turn", "chat.turn", turnContext, async () => {
4717
5546
  const content = parseContent(message);
4718
- const strippedUserText = deps.stripLeadingBotMention(
5547
+ const strippedUserText = stripLeadingBotMention(
4719
5548
  stripLeadingSteeringOverride(content.topLevelText),
4720
5549
  {
5550
+ botUserId: deps.getBotUserId(),
4721
5551
  stripLeadingSlackMentionToken: Boolean(message.isMention)
4722
5552
  }
4723
5553
  );
@@ -4732,8 +5562,8 @@ function createSlackTurnRuntime(deps) {
4732
5562
  runId
4733
5563
  };
4734
5564
  const queuedMessages = getQueuedMessages(hooks.messageContext, {
4735
- explicitMention: Boolean(message.isMention),
4736
- stripLeadingBotMention: deps.stripLeadingBotMention
5565
+ botUserId: deps.getBotUserId(),
5566
+ explicitMention: Boolean(message.isMention)
4737
5567
  });
4738
5568
  const combinedText = combineTurnText(queuedMessages, currentText);
4739
5569
  const turnIsExplicitMention = Boolean(message.isMention) || queuedMessages.some((queued) => queued.explicitMention);
@@ -4833,6 +5663,7 @@ function createSlackTurnRuntime(deps) {
4833
5663
  }
4834
5664
  const conversationContext = deps.getPreparedConversationContext(preparedState);
4835
5665
  const drainSteeringMessages = createAcceptedSteeringDrain(hooks, {
5666
+ botUserId: deps.getBotUserId(),
4836
5667
  explicitMention: Boolean(message.isMention),
4837
5668
  onAcceptedForProcessing: async (messages) => {
4838
5669
  await Promise.all(
@@ -4851,8 +5682,7 @@ function createSlackTurnRuntime(deps) {
4851
5682
  conversationContext: drainContext?.conversationContext ?? conversationContext,
4852
5683
  messages,
4853
5684
  thread
4854
- }),
4855
- stripLeadingBotMention: deps.stripLeadingBotMention
5685
+ })
4856
5686
  });
4857
5687
  processingReaction = await processingReactions.start(
4858
5688
  turnContext,
@@ -4897,11 +5727,11 @@ function createSlackTurnRuntime(deps) {
4897
5727
  });
4898
5728
  } catch (error) {
4899
5729
  const failureLogContext = logContext({
4900
- threadId: deps.getThreadId(thread, message),
5730
+ threadId: getThreadId(thread, message),
4901
5731
  actorId: message.author.userId,
4902
5732
  actorUserName: actorUserName(message),
4903
- channelId: deps.getChannelId(thread, message),
4904
- runId: deps.getRunId(thread, message)
5733
+ channelId: getChannelId(thread, message),
5734
+ runId: getRunId(thread, message)
4905
5735
  });
4906
5736
  const classifiedFailure = getConversationTurnBoundaryError(error);
4907
5737
  const failureCause = classifiedFailure?.cause ?? error;
@@ -4914,7 +5744,7 @@ function createSlackTurnRuntime(deps) {
4914
5744
  const failureCode = classifiedFailure?.failureCode ?? "agent_run_failed";
4915
5745
  if (failureCause instanceof SlackActionError && failureCause.code === "read_only_channel") {
4916
5746
  withLogContext(failureLogContext, () => {
4917
- deps.logWarn("subscribed_message.handler.skipped", {
5747
+ logWarn("subscribed_message.handler.skipped", {
4918
5748
  "app.decision.reason": "read_only_channel"
4919
5749
  });
4920
5750
  });
@@ -4922,10 +5752,7 @@ function createSlackTurnRuntime(deps) {
4922
5752
  }
4923
5753
  const eventId = classifiedFailure?.eventId ?? withLogContext(
4924
5754
  failureLogContext,
4925
- () => deps.logException(
4926
- failureCause,
4927
- "subscribed_message.handler.failed"
4928
- )
5755
+ () => logException(failureCause, "subscribed_message.handler.failed")
4929
5756
  );
4930
5757
  if (!acked && hooks.isFinalAttempt === false) {
4931
5758
  return;
@@ -4963,11 +5790,11 @@ function createSlackTurnRuntime(deps) {
4963
5790
  thread,
4964
5791
  pending: skippedSteeringMessages,
4965
5792
  context: logContext({
4966
- threadId: deps.getThreadId(thread, message),
5793
+ threadId: getThreadId(thread, message),
4967
5794
  actorId: message.author.userId,
4968
5795
  actorUserName: actorUserName(message),
4969
- channelId: deps.getChannelId(thread, message),
4970
- runId: deps.getRunId(thread, message)
5796
+ channelId: getChannelId(thread, message),
5797
+ runId: getRunId(thread, message)
4971
5798
  })
4972
5799
  });
4973
5800
  await processingReactions.stopAll();
@@ -4990,7 +5817,7 @@ function createSlackTurnRuntime(deps) {
4990
5817
  sourceChannelId: event.context?.channelId
4991
5818
  });
4992
5819
  } catch (error) {
4993
- deps.logException(error, "assistant.thread.initialization.failed");
5820
+ logException(error, "assistant.thread.initialization.failed");
4994
5821
  }
4995
5822
  }
4996
5823
  );
@@ -5011,7 +5838,7 @@ function createSlackTurnRuntime(deps) {
5011
5838
  sourceChannelId: event.context?.channelId
5012
5839
  });
5013
5840
  } catch (error) {
5014
- deps.logException(error, "assistant.context.refresh.failed");
5841
+ logException(error, "assistant.context.refresh.failed");
5015
5842
  }
5016
5843
  }
5017
5844
  );
@@ -5493,24 +6320,14 @@ function createJuniorRuntimeServices(overrides = {}) {
5493
6320
  listThreadReplies: overrides.visionContext?.listThreadReplies ?? listThreadReplies,
5494
6321
  downloadFile: overrides.visionContext?.downloadFile ?? downloadPrivateSlackFile
5495
6322
  });
5496
- const agentRunner = overrides.replyExecutor?.agentRunner ?? createAgentRunner(executeAgentRun, {
6323
+ const agentRunner = overrides.agentRunner ?? createAgentRunner(executeAgentRun, {
5497
6324
  bindSpawnAgent: (request) => bindSpawnAgent(request, { queue: getVercelConversationWorkQueue }),
5498
6325
  tracePropagation: overrides.sandbox?.tracePropagation
5499
6326
  });
5500
6327
  return {
5501
6328
  conversationMemory,
5502
6329
  contextCompactor,
5503
- replyExecutor: {
5504
- contextCompactor: overrides.replyExecutor?.contextCompactor ?? contextCompactor,
5505
- agentRunner,
5506
- getPausedTurnRequest: overrides.replyExecutor?.getPausedTurnRequest ?? getPausedTurnRequest,
5507
- lookupSlackUser: overrides.replyExecutor?.lookupSlackUser ?? lookupSlackUser,
5508
- wakePausedTurn: overrides.replyExecutor?.wakePausedTurn ?? wakePausedTurn,
5509
- scheduleSessionCompletedPluginTasks: overrides.replyExecutor?.scheduleSessionCompletedPluginTasks ?? (async (params) => {
5510
- await scheduleSessionCompletedPluginTasks(params);
5511
- }),
5512
- turnLifecycle: overrides.replyExecutor?.turnLifecycle ?? new ConversationTurnLifecycleService(getConversationEventStore())
5513
- },
6330
+ executeTurn: async (run, saveResult, timeoutMs) => await executeTurn(agentRunner, run, saveResult, timeoutMs),
5514
6331
  subscribedReplyPolicy: createSubscribedReplyPolicy({
5515
6332
  completeObject: overrides.subscribedReplyPolicy?.completeObject ?? completeObject
5516
6333
  }),
@@ -5534,11 +6351,11 @@ function getMessageTimestamp(message) {
5534
6351
  }
5535
6352
 
5536
6353
  // src/chat/slack/action-token.ts
5537
- import { z as z4 } from "zod";
5538
- var slackActionTokenSchema = z4.string().trim().min(1).brand();
5539
- var slackMessageEnvelopeSchema = z4.object({
5540
- raw: z4.object({
5541
- action_token: z4.unknown().optional()
6354
+ import { z as z5 } from "zod";
6355
+ var slackActionTokenSchema = z5.string().trim().min(1).brand();
6356
+ var slackMessageEnvelopeSchema = z5.object({
6357
+ raw: z5.object({
6358
+ action_token: z5.unknown().optional()
5542
6359
  }).optional()
5543
6360
  });
5544
6361
  function readSlackActionToken(message) {
@@ -5616,11 +6433,8 @@ async function maybeApplyProviderDefaultConfigRequest(args) {
5616
6433
  };
5617
6434
  }
5618
6435
 
5619
- // src/chat/providers/slack/turn.ts
5620
- async function persistThreadRuntimeStateWithRetry(thread, patch) {
5621
- await persistWithRetry(() => persistThreadRuntimeState(thread, patch));
5622
- }
5623
- function parkedInputKey(message) {
6436
+ // src/chat/providers/slack/input.ts
6437
+ function steeringMessageKey(message) {
5624
6438
  if (message.role !== "user") {
5625
6439
  return void 0;
5626
6440
  }
@@ -5629,19 +6443,19 @@ function parkedInputKey(message) {
5629
6443
  return `${message.timestamp}:${text}`;
5630
6444
  }
5631
6445
  function renderRecentThreadMessageLines(conversationContext, messages) {
5632
- const passiveMessages = messages.filter((queued) => {
6446
+ const messagesForContext = messages.filter((queued) => {
5633
6447
  if (queued.explicitMention) {
5634
6448
  return false;
5635
6449
  }
5636
- const slackTs = queuedInstructionActor(queued)?.slackTs;
6450
+ const slackTs = inboundMessageActor(queued)?.slackTs;
5637
6451
  return !slackTs || !conversationContext?.includes(`slack_ts="${slackTs}"`);
5638
6452
  });
5639
- if (passiveMessages.length === 0) {
6453
+ if (messagesForContext.length === 0) {
5640
6454
  return [];
5641
6455
  }
5642
6456
  const lines = [];
5643
- for (const queued of passiveMessages) {
5644
- const actor = queuedInstructionActor(queued);
6457
+ for (const queued of messagesForContext) {
6458
+ const actor = inboundMessageActor(queued);
5645
6459
  const author = escapeXml(actor?.authorName ?? "user");
5646
6460
  const attrs = [
5647
6461
  `role="user"`,
@@ -5658,14 +6472,13 @@ function renderRecentThreadMessageLines(conversationContext, messages) {
5658
6472
  }
5659
6473
  return lines;
5660
6474
  }
5661
- function appendRecentThreadMessagesToContext(conversationContext, messages, options) {
5662
- const baseContext = options?.includeConversationContext === false ? void 0 : conversationContext;
6475
+ function appendRecentMessagesToContext(conversationContext, messages) {
5663
6476
  return appendThreadContextMessages(
5664
- baseContext,
6477
+ conversationContext,
5665
6478
  renderRecentThreadMessageLines(conversationContext, messages)
5666
6479
  );
5667
6480
  }
5668
- function queuedInstructionActor(queued) {
6481
+ function inboundMessageActor(queued) {
5669
6482
  const actor = getMessageActorIdentity(queued.message);
5670
6483
  const authorId = actor?.userId ?? parseActorUserId(queued.message.author.userId);
5671
6484
  const authorName = actor?.fullName ?? actor?.userName;
@@ -5676,7 +6489,7 @@ function queuedInstructionActor(queued) {
5676
6489
  ...slackTs ? { slackTs } : void 0
5677
6490
  };
5678
6491
  }
5679
- function queuedInstructionProvenance(queued, teamId) {
6492
+ function inboundMessageProvenance(queued, teamId) {
5680
6493
  if (isResourceEventSlackMessage(queued.message)) {
5681
6494
  return contextProvenance;
5682
6495
  }
@@ -5703,12 +6516,57 @@ async function resolveChannelName(thread) {
5703
6516
  return void 0;
5704
6517
  }
5705
6518
  }
5706
- function collectTurnAttachments(message, queuedMessages) {
6519
+ function collectAttachments(message, batchedMessages) {
5707
6520
  return [
5708
- ...(queuedMessages ?? []).flatMap((queued) => queued.message.attachments),
6521
+ ...(batchedMessages ?? []).flatMap((queued) => queued.message.attachments),
5709
6522
  ...message.attachments
5710
6523
  ];
5711
6524
  }
6525
+ async function saveSteeringMessages(args) {
6526
+ if (args.messages.length === 0) {
6527
+ return true;
6528
+ }
6529
+ const state = getStateAdapter();
6530
+ await state.connect();
6531
+ const lock = await acquireActiveLock(state, args.conversationId);
6532
+ if (!lock) {
6533
+ return false;
6534
+ }
6535
+ try {
6536
+ const projection = await loadConversationProjection({
6537
+ conversationId: args.conversationId
6538
+ });
6539
+ const savedKeys = new Set(
6540
+ projection.messages.map(steeringMessageKey).filter((key) => key !== void 0)
6541
+ );
6542
+ const missing = args.messages.filter((entry) => {
6543
+ const key = steeringMessageKey(entry.message);
6544
+ return key === void 0 || !savedKeys.has(key);
6545
+ });
6546
+ if (missing.length === 0) {
6547
+ return true;
6548
+ }
6549
+ await commitMessages({
6550
+ conversationId: args.conversationId,
6551
+ messages: [
6552
+ ...projection.messages,
6553
+ ...missing.map((entry) => entry.message)
6554
+ ],
6555
+ provenance: [
6556
+ ...projection.provenance,
6557
+ ...missing.map((entry) => entry.provenance)
6558
+ ]
6559
+ });
6560
+ return true;
6561
+ } finally {
6562
+ await state.releaseLock(lock);
6563
+ }
6564
+ }
6565
+
6566
+ // src/chat/providers/slack/turn.ts
6567
+ async function persistThreadRuntimeStateWithRetry(thread, patch) {
6568
+ await persistWithRetry(() => persistThreadRuntimeState(thread, patch));
6569
+ }
5712
6570
  async function loadPiMessagesForTurn(args) {
5713
6571
  if (!args.conversationId) {
5714
6572
  return {};
@@ -5742,6 +6600,7 @@ function shouldPublishExternally2(publishExternally) {
5742
6600
  return publishExternally !== false;
5743
6601
  }
5744
6602
  function createSlackTurn(deps) {
6603
+ const turnLifecycle = getTurnLifecycle();
5745
6604
  return async function executeSlackTurn(thread, message, options) {
5746
6605
  if (message.author.isMe) {
5747
6606
  return;
@@ -5810,7 +6669,7 @@ function createSlackTurn(deps) {
5810
6669
  (queued) => ensureSlackMessageActorIdentity(
5811
6670
  queued.message,
5812
6671
  teamId,
5813
- deps.services.lookupSlackUser
6672
+ lookupSlackUser
5814
6673
  )
5815
6674
  )
5816
6675
  );
@@ -5827,7 +6686,7 @@ function createSlackTurn(deps) {
5827
6686
  executionActor = await ensureSlackMessageActorIdentity(
5828
6687
  message,
5829
6688
  teamId,
5830
- deps.services.lookupSlackUser
6689
+ lookupSlackUser
5831
6690
  );
5832
6691
  if (executionActor) {
5833
6692
  credentialContext = credentialContextForActor(executionActor);
@@ -5905,8 +6764,8 @@ function createSlackTurn(deps) {
5905
6764
  queuedMessages.map(async (queued) => {
5906
6765
  const attachments = queued.message.attachments;
5907
6766
  return {
5908
- actor: queuedInstructionActor(queued),
5909
- provenance: queuedInstructionProvenance(queued, teamId),
6767
+ actor: inboundMessageActor(queued),
6768
+ provenance: inboundMessageProvenance(queued, teamId),
5910
6769
  text: queued.userText,
5911
6770
  timestampMs: queued.message.metadata.dateSent.getTime(),
5912
6771
  omittedImageAttachmentCount: !isVisionEnabled() && hasPotentialImageAttachment(attachments) ? countPotentialImageAttachments(attachments) : 0,
@@ -5922,51 +6781,11 @@ function createSlackTurn(deps) {
5922
6781
  })
5923
6782
  );
5924
6783
  };
5925
- const drainParkedInputToEventLog = async (pairs) => {
5926
- if (!conversationId || pairs.length === 0) {
5927
- return true;
5928
- }
5929
- const stateAdapter = getStateAdapter();
5930
- await stateAdapter.connect();
5931
- const lock = await acquireActiveLock(stateAdapter, conversationId);
5932
- if (!lock) {
5933
- return false;
5934
- }
5935
- try {
5936
- const projection = await loadConversationProjection({
5937
- conversationId
5938
- });
5939
- const appendedKeys = new Set(
5940
- projection.messages.map(parkedInputKey).filter((key) => key !== void 0)
5941
- );
5942
- const missing = pairs.filter((pair) => {
5943
- const key = parkedInputKey(pair.message);
5944
- return key === void 0 || !appendedKeys.has(key);
5945
- });
5946
- if (missing.length === 0) {
5947
- return true;
5948
- }
5949
- await commitMessages({
5950
- conversationId,
5951
- messages: [
5952
- ...projection.messages,
5953
- ...missing.map((pair) => pair.message)
5954
- ],
5955
- provenance: [
5956
- ...projection.provenance,
5957
- ...missing.map((pair) => pair.provenance)
5958
- ]
5959
- });
5960
- return true;
5961
- } finally {
5962
- await stateAdapter.releaseLock(lock);
5963
- }
5964
- };
5965
- const appendParkedTurnInput = async (parkedSessionId) => {
6784
+ const saveMessagesForPausedTurn = async (pausedTurnId) => {
5966
6785
  if (!conversationId) {
5967
6786
  return true;
5968
6787
  }
5969
- const parkedMessages = [
6788
+ const messagesForPausedTurn = [
5970
6789
  ...options.queuedMessages ?? [],
5971
6790
  {
5972
6791
  explicitMention: Boolean(
@@ -5977,18 +6796,21 @@ function createSlackTurn(deps) {
5977
6796
  userText: currentText.userText
5978
6797
  }
5979
6798
  ].filter(
5980
- // Redelivery of the parked turn's own message must not duplicate
6799
+ // Redelivery of the paused Turn's own message must not duplicate
5981
6800
  // the prompt that already started the session.
5982
- (queued) => buildDeterministicTurnId(queued.message.id) !== parkedSessionId
6801
+ (queued) => buildDeterministicTurnId(queued.message.id) !== pausedTurnId
5983
6802
  );
5984
- if (parkedMessages.length === 0) {
6803
+ if (messagesForPausedTurn.length === 0) {
5985
6804
  return true;
5986
6805
  }
5987
- const parkedPairs = (await resolveSteeringMessages(parkedMessages)).map((steering) => ({
6806
+ const steeringMessages = (await resolveSteeringMessages(messagesForPausedTurn)).map((steering) => ({
5988
6807
  message: buildSteeringPiMessage(steering),
5989
6808
  provenance: steering.provenance
5990
6809
  }));
5991
- return drainParkedInputToEventLog(parkedPairs);
6810
+ return saveSteeringMessages({
6811
+ conversationId,
6812
+ messages: steeringMessages
6813
+ });
5992
6814
  };
5993
6815
  if (preparedState.userMessageAlreadyReplied) {
5994
6816
  const deliveredMessage = [...preparedState.conversation.messages].reverse().find(
@@ -6005,16 +6827,16 @@ function createSlackTurn(deps) {
6005
6827
  return;
6006
6828
  }
6007
6829
  if (conversationId && activeTurnId) {
6008
- const pausedTurn = await deps.services.getPausedTurnRequest({
6830
+ const pausedTurn = await deps.pausedTurns.get({
6009
6831
  conversationId,
6010
6832
  turnId: activeTurnId
6011
6833
  });
6012
6834
  if (pausedTurn) {
6013
- if (!await appendParkedTurnInput(pausedTurn.turnId)) {
6835
+ if (!await saveMessagesForPausedTurn(pausedTurn.turnId)) {
6014
6836
  throw new TurnInputDeferredError();
6015
6837
  }
6016
6838
  try {
6017
- await deps.services.wakePausedTurn(pausedTurn);
6839
+ await deps.pausedTurns.wake(pausedTurn);
6018
6840
  } catch (error) {
6019
6841
  logException(error, "agent.continue.schedule.failed", {
6020
6842
  "app.ai.resume_session_version": pausedTurn.expectedVersion,
@@ -6039,6 +6861,7 @@ function createSlackTurn(deps) {
6039
6861
  await abandonTurnRecord({
6040
6862
  conversationId,
6041
6863
  turnId: activeTurnId,
6864
+ // TODO(dcramer): Rename this legacy text in Slack and Conversation API Turn records together.
6042
6865
  errorMessage: "Auth-parked session superseded by a new user message"
6043
6866
  });
6044
6867
  markTurnClosed({
@@ -6108,7 +6931,7 @@ function createSlackTurn(deps) {
6108
6931
  nextTurnId: turnId
6109
6932
  });
6110
6933
  if (conversationId && preparedState.userMessageId) {
6111
- await deps.services.turnLifecycle.start({
6934
+ await turnLifecycle.start({
6112
6935
  conversationId,
6113
6936
  createdAtMs: Date.now(),
6114
6937
  inputMessageIds: [
@@ -6168,7 +6991,7 @@ function createSlackTurn(deps) {
6168
6991
  if (actor?.userName) {
6169
6992
  setTags({ userName: actor.userName });
6170
6993
  }
6171
- const turnAttachments = collectTurnAttachments(
6994
+ const turnAttachments = collectAttachments(
6172
6995
  message,
6173
6996
  options.queuedMessages
6174
6997
  );
@@ -6197,7 +7020,6 @@ function createSlackTurn(deps) {
6197
7020
  let runResultHandled = false;
6198
7021
  let assistantMessageDelivered = false;
6199
7022
  let acceptedDeliveryId;
6200
- let lifecycleTerminalized = false;
6201
7023
  let turnCompletionNotified = false;
6202
7024
  const recordDispatchOutcome = async (dispatchOutcome, state) => {
6203
7025
  const dispatchId = options.execution?.dispatch?.id;
@@ -6222,7 +7044,6 @@ function createSlackTurn(deps) {
6222
7044
  };
6223
7045
  let turnWakeError;
6224
7046
  let boundaryFailureCode = "agent_run_failed";
6225
- let finalizedFailureEventId;
6226
7047
  let terminalDispatchFailureOutcome;
6227
7048
  const notifyTurnCompleted = async () => {
6228
7049
  if (turnCompletionNotified) {
@@ -6354,7 +7175,7 @@ function createSlackTurn(deps) {
6354
7175
  });
6355
7176
  let piMessages = loadedPiMessages.piMessages;
6356
7177
  if (conversationId && loadedPiMessages.canCompact && piMessages?.length) {
6357
- const compaction = await deps.services.contextCompactor.maybeCompact({
7178
+ const compaction = await deps.contextCompactor.maybeCompact({
6358
7179
  conversation: preparedState.conversation,
6359
7180
  conversationContext: preparedState.conversationContext,
6360
7181
  conversationId,
@@ -6379,7 +7200,7 @@ function createSlackTurn(deps) {
6379
7200
  }
6380
7201
  }
6381
7202
  const hasDurablePromptHistory = Boolean(piMessages?.length);
6382
- const batchedInstructions = (await resolveSteeringMessages(
7203
+ const batchedSteeringMessages = (await resolveSteeringMessages(
6383
7204
  (options.queuedMessages ?? []).filter(
6384
7205
  (queued) => queued.explicitMention
6385
7206
  )
@@ -6387,20 +7208,23 @@ function createSlackTurn(deps) {
6387
7208
  message: buildSteeringPiMessage(steering),
6388
7209
  provenance: steering.provenance
6389
7210
  }));
6390
- if (!await drainParkedInputToEventLog(batchedInstructions)) {
7211
+ if (!await saveSteeringMessages({
7212
+ conversationId,
7213
+ messages: batchedSteeringMessages
7214
+ })) {
6391
7215
  shouldPersistFailureState = false;
6392
7216
  throw new TurnInputDeferredError();
6393
7217
  }
6394
- if (batchedInstructions.length > 0) {
7218
+ if (batchedSteeringMessages.length > 0) {
6395
7219
  const presentKeys = new Set(
6396
- (piMessages ?? []).map(parkedInputKey).filter((key) => key !== void 0)
7220
+ (piMessages ?? []).map(steeringMessageKey).filter((key) => key !== void 0)
6397
7221
  );
6398
- const newlyBatched = batchedInstructions.map((entry) => entry.message).filter((batchedMessage) => {
6399
- const key = parkedInputKey(batchedMessage);
7222
+ const newSteeringMessages = batchedSteeringMessages.map((entry) => entry.message).filter((batchedMessage) => {
7223
+ const key = steeringMessageKey(batchedMessage);
6400
7224
  return key === void 0 || !presentKeys.has(key);
6401
7225
  });
6402
- if (newlyBatched.length > 0) {
6403
- piMessages = [...piMessages ?? [], ...newlyBatched];
7226
+ if (newSteeringMessages.length > 0) {
7227
+ piMessages = [...piMessages ?? [], ...newSteeringMessages];
6404
7228
  }
6405
7229
  }
6406
7230
  status.update();
@@ -6420,7 +7244,7 @@ function createSlackTurn(deps) {
6420
7244
  const toolChannelId = channelId;
6421
7245
  const activeInstructionAuthorId = actor?.userId ?? parseActorUserId(message.author.userId);
6422
7246
  const activeInstructionAuthorName = actor?.fullName ?? actor?.userName;
6423
- const promptConversationContext = appendRecentThreadMessagesToContext(
7247
+ const promptConversationContext = appendRecentMessagesToContext(
6424
7248
  preparedState.conversationContext,
6425
7249
  options.queuedMessages ?? []
6426
7250
  );
@@ -6435,7 +7259,7 @@ function createSlackTurn(deps) {
6435
7259
  );
6436
7260
  return acceptedMessages ?? await resolveSteeringMessages(drained);
6437
7261
  } : void 0;
6438
- const outcome = await deps.services.agentRunner.run({
7262
+ const run = {
6439
7263
  conversationId,
6440
7264
  turnId,
6441
7265
  ...runId ? { runId } : void 0,
@@ -6507,7 +7331,121 @@ function createSlackTurn(deps) {
6507
7331
  });
6508
7332
  }
6509
7333
  }
6510
- });
7334
+ };
7335
+ let completedResult;
7336
+ const saveResult = async (result) => {
7337
+ let finalResult = result;
7338
+ setTags({ modelId: finalResult.diagnostics.modelId });
7339
+ const diagnosticsAttributes = getAgentTurnDiagnosticsAttributes(finalResult);
7340
+ setSpanAttributes(diagnosticsAttributes);
7341
+ let failureEventId;
7342
+ let failureReason;
7343
+ if (finalResult.diagnostics.outcome !== "success") {
7344
+ const finalized = finalizeFailedTurnReplyWithEvent({
7345
+ reply: finalResult,
7346
+ logException
7347
+ });
7348
+ finalResult = finalized.reply;
7349
+ failureEventId = finalized.eventId;
7350
+ failureReason = finalized.failureReason;
7351
+ await deliverAssistantMessage(finalResult.text);
7352
+ }
7353
+ const turnResult = finalResult.diagnostics.outcome === "success" ? { outcome: "completed" } : {
7354
+ errorMessage: finalResult.diagnostics.errorMessage ?? `Agent turn ended with ${finalResult.diagnostics.outcome}.`,
7355
+ outcome: "failed"
7356
+ };
7357
+ runResultHandled = true;
7358
+ shouldPersistFailureState = false;
7359
+ boundaryFailureCode = "agent_run_failed";
7360
+ const completedState = buildDeliveredTurnStatePatch({
7361
+ conversation: preparedState.conversation,
7362
+ reply: finalResult,
7363
+ sessionId: turnId,
7364
+ userMessageId: preparedState.userMessageId
7365
+ });
7366
+ let saveFailed = false;
7367
+ let saveFailureEventId;
7368
+ try {
7369
+ if (conversationId && finalResult.piMessages?.length) {
7370
+ await saveTurnCheckpoint({
7371
+ mode: "completed",
7372
+ channelName,
7373
+ conversationId,
7374
+ turnId,
7375
+ durationMs: finalResult.diagnostics.durationMs,
7376
+ usage: finalResult.diagnostics.usage,
7377
+ destination,
7378
+ destinationVisibility,
7379
+ source,
7380
+ sliceId: 1,
7381
+ dispatchOutcome: finalResult.diagnostics.outcome === "success" ? "completed" : "failed",
7382
+ ...options.execution?.dispatch && turnResult.errorMessage ? { errorMessage: turnResult.errorMessage } : void 0,
7383
+ ...acceptedDeliveryId ? { resultMessageId: acceptedDeliveryId } : void 0,
7384
+ messages: finalResult.piMessages,
7385
+ actor: executionActor,
7386
+ surface: options.execution?.surface ?? "slack",
7387
+ dispatchId: options.execution?.dispatch?.id
7388
+ });
7389
+ } else if (conversationId) {
7390
+ await recordTurnSummary({
7391
+ channelName,
7392
+ conversationId,
7393
+ cumulativeDurationMs: finalResult.diagnostics.durationMs,
7394
+ cumulativeUsage: finalResult.diagnostics.usage,
7395
+ turnId,
7396
+ sliceId: 1,
7397
+ startedAtMs: message.metadata.dateSent.getTime(),
7398
+ state: "completed",
7399
+ actor: executionActor,
7400
+ destination,
7401
+ destinationVisibility,
7402
+ source,
7403
+ surface: options.execution?.surface ?? "slack",
7404
+ dispatchId: options.execution?.dispatch?.id,
7405
+ dispatchOutcome: finalResult.diagnostics.outcome === "success" ? "completed" : "failed",
7406
+ ...acceptedDeliveryId ? { resultMessageId: acceptedDeliveryId } : void 0,
7407
+ traceId: getActiveTraceId()
7408
+ });
7409
+ }
7410
+ await persistWithRetry(
7411
+ () => persistConversationMessages({
7412
+ conversation: completedState.conversation,
7413
+ conversationId
7414
+ })
7415
+ );
7416
+ await persistThreadRuntimeStateWithRetry(thread, completedState);
7417
+ } catch (saveError) {
7418
+ saveFailed = true;
7419
+ saveFailureEventId = logException(
7420
+ saveError,
7421
+ "slack.reply.post_delivery_commit.failed",
7422
+ messageTs ? { "messaging.message.id": messageTs } : {}
7423
+ );
7424
+ }
7425
+ preparedState.conversation = completedState.conversation;
7426
+ persistedAtLeastOnce = true;
7427
+ options.onTurnOutcome?.(turnResult);
7428
+ completedResult = finalResult;
7429
+ if (saveFailed) {
7430
+ return {
7431
+ ...saveFailureEventId ? { eventId: saveFailureEventId } : void 0,
7432
+ failureCode: "persistence_failed",
7433
+ outcome: "failed"
7434
+ };
7435
+ }
7436
+ if (finalResult.diagnostics.outcome === "success") {
7437
+ return {
7438
+ outcome: assistantMessageDelivered ? "success" : "no_reply"
7439
+ };
7440
+ }
7441
+ return {
7442
+ ...failureEventId ? { eventId: failureEventId } : void 0,
7443
+ failureCode: "model_execution_failed",
7444
+ ...failureReason ? { failureReason } : void 0,
7445
+ outcome: "failed"
7446
+ };
7447
+ };
7448
+ const outcome = await deps.executeTurn(run, saveResult);
6511
7449
  if (outcome.status === "awaiting_auth") {
6512
7450
  await recordDispatchOutcome("blocked", "failed");
6513
7451
  options.onTurnOutcome?.({ outcome: "blocked" });
@@ -6530,14 +7468,13 @@ function createSlackTurn(deps) {
6530
7468
  conversation: preparedState.conversation
6531
7469
  });
6532
7470
  if (conversationId) {
6533
- await deps.services.turnLifecycle.fail({
7471
+ await turnLifecycle.fail({
6534
7472
  conversationId,
6535
7473
  createdAtMs: Date.now(),
6536
7474
  ...authFailureEventId ? { eventId: authFailureEventId } : void 0,
6537
7475
  failureCode: "agent_run_failed",
6538
7476
  turnId
6539
7477
  });
6540
- lifecycleTerminalized = true;
6541
7478
  }
6542
7479
  persistedAtLeastOnce = true;
6543
7480
  shouldPersistFailureState = false;
@@ -6570,7 +7507,7 @@ function createSlackTurn(deps) {
6570
7507
  );
6571
7508
  }
6572
7509
  try {
6573
- await deps.services.wakePausedTurn({
7510
+ await deps.pausedTurns.wake({
6574
7511
  conversationId,
6575
7512
  destination,
6576
7513
  turnId,
@@ -6588,134 +7525,26 @@ function createSlackTurn(deps) {
6588
7525
  }
6589
7526
  return;
6590
7527
  }
6591
- let reply = outcome.result;
6592
- setTags({ modelId: reply.diagnostics.modelId });
6593
- const diagnosticsAttributes = getAgentTurnDiagnosticsAttributes(reply);
6594
- setSpanAttributes(diagnosticsAttributes);
6595
- if (reply.diagnostics.outcome !== "success") {
6596
- const finalized = finalizeFailedTurnReplyWithEvent({
6597
- reply,
6598
- logException
6599
- });
6600
- reply = finalized.reply;
6601
- finalizedFailureEventId = finalized.eventId;
6602
- await deliverAssistantMessage(reply.text);
6603
- }
6604
- const turnResult = reply.diagnostics.outcome === "success" ? { outcome: "completed" } : {
6605
- errorMessage: reply.diagnostics.errorMessage ?? `Agent turn ended with ${reply.diagnostics.outcome}.`,
6606
- outcome: "failed"
6607
- };
6608
- runResultHandled = true;
6609
- shouldPersistFailureState = false;
6610
- boundaryFailureCode = "agent_run_failed";
6611
- const completedState = buildDeliveredTurnStatePatch({
6612
- conversation: preparedState.conversation,
6613
- reply,
6614
- sessionId: turnId,
6615
- userMessageId: preparedState.userMessageId
6616
- });
6617
- try {
6618
- if (conversationId && reply.piMessages?.length) {
6619
- await saveTurnCheckpoint({
6620
- mode: "completed",
6621
- channelName,
6622
- conversationId,
6623
- turnId,
6624
- durationMs: reply.diagnostics.durationMs,
6625
- usage: reply.diagnostics.usage,
6626
- destination,
6627
- destinationVisibility,
6628
- source,
6629
- sliceId: 1,
6630
- dispatchOutcome: reply.diagnostics.outcome === "success" ? "completed" : "failed",
6631
- ...options.execution?.dispatch && turnResult.errorMessage ? { errorMessage: turnResult.errorMessage } : void 0,
6632
- ...acceptedDeliveryId ? { resultMessageId: acceptedDeliveryId } : void 0,
6633
- messages: reply.piMessages,
6634
- actor: executionActor,
6635
- surface: options.execution?.surface ?? "slack",
6636
- dispatchId: options.execution?.dispatch?.id
6637
- });
6638
- } else if (conversationId) {
6639
- await recordTurnSummary({
6640
- channelName,
6641
- conversationId,
6642
- cumulativeDurationMs: reply.diagnostics.durationMs,
6643
- cumulativeUsage: reply.diagnostics.usage,
6644
- turnId,
6645
- sliceId: 1,
6646
- startedAtMs: message.metadata.dateSent.getTime(),
6647
- state: "completed",
6648
- actor: executionActor,
6649
- destination,
6650
- destinationVisibility,
6651
- source,
6652
- surface: options.execution?.surface ?? "slack",
6653
- dispatchId: options.execution?.dispatch?.id,
6654
- dispatchOutcome: reply.diagnostics.outcome === "success" ? "completed" : "failed",
6655
- ...acceptedDeliveryId ? { resultMessageId: acceptedDeliveryId } : void 0,
6656
- traceId: getActiveTraceId()
6657
- });
6658
- }
6659
- await persistWithRetry(
6660
- () => persistConversationMessages({
6661
- conversation: completedState.conversation,
6662
- conversationId
6663
- })
6664
- );
6665
- await persistThreadRuntimeStateWithRetry(thread, completedState);
6666
- } catch (commitError) {
6667
- const persistenceEventId = logException(
6668
- commitError,
6669
- "slack.reply.post_delivery_commit.failed",
6670
- messageTs ? { "messaging.message.id": messageTs } : {}
6671
- );
6672
- if (conversationId && !lifecycleTerminalized) {
6673
- await deps.services.turnLifecycle.fail({
6674
- conversationId,
6675
- createdAtMs: Date.now(),
6676
- ...persistenceEventId ? { eventId: persistenceEventId } : void 0,
6677
- failureCode: "persistence_failed",
6678
- turnId
6679
- });
6680
- lifecycleTerminalized = true;
6681
- }
6682
- }
6683
- preparedState.conversation = completedState.conversation;
6684
- persistedAtLeastOnce = true;
6685
- options.onTurnOutcome?.(turnResult);
6686
- if (!lifecycleTerminalized && conversationId) {
6687
- if (reply.diagnostics.outcome === "success") {
6688
- await deps.services.turnLifecycle.complete({
6689
- conversationId,
6690
- createdAtMs: Date.now(),
6691
- outcome: assistantMessageDelivered ? "success" : "no_reply",
6692
- turnId
6693
- });
6694
- } else {
6695
- await deps.services.turnLifecycle.fail({
6696
- conversationId,
6697
- createdAtMs: Date.now(),
6698
- ...finalizedFailureEventId ? { eventId: finalizedFailureEventId } : void 0,
6699
- failureCode: "model_execution_failed",
6700
- turnId
6701
- });
6702
- }
6703
- lifecycleTerminalized = true;
7528
+ if (!completedResult) {
7529
+ throw new Error("Completed Turn did not save a result");
6704
7530
  }
6705
7531
  if (shouldEmitDevAgentTrace()) {
6706
7532
  logInfo("agent.turn.completed", {
6707
- "app.ai.outcome": reply.diagnostics.outcome,
6708
- "app.ai.tool_call_count": reply.diagnostics.toolCalls.length,
6709
- "app.ai.tool_error_results": reply.diagnostics.toolErrorCount
7533
+ "app.ai.outcome": completedResult.diagnostics.outcome,
7534
+ "app.ai.tool_call_count": completedResult.diagnostics.toolCalls.length,
7535
+ "app.ai.tool_error_results": completedResult.diagnostics.toolErrorCount
6710
7536
  });
6711
7537
  }
6712
7538
  await notifyTurnCompleted();
6713
- if (reply.diagnostics.outcome === "success" && conversationId) {
7539
+ if (completedResult.diagnostics.outcome === "success" && conversationId) {
6714
7540
  try {
6715
- await deps.services.scheduleSessionCompletedPluginTasks({
6716
- conversationId,
6717
- sessionId: turnId
6718
- });
7541
+ await scheduleSessionCompletedPluginTasks(
7542
+ {
7543
+ conversationId,
7544
+ sessionId: turnId
7545
+ },
7546
+ deps.sendPluginTask ? { send: deps.sendPluginTask } : void 0
7547
+ );
6719
7548
  } catch (error) {
6720
7549
  logException(
6721
7550
  error,
@@ -6754,8 +7583,9 @@ function createSlackTurn(deps) {
6754
7583
  shouldPersistFailureState = true;
6755
7584
  }
6756
7585
  shouldPersistFailureState = true;
6757
- const classifiedFailure = getConversationTurnBoundaryError(error);
6758
- const failureCause = classifiedFailure?.cause ?? error;
7586
+ const runFailure = error instanceof AgentRunError ? error.cause : error;
7587
+ const classifiedFailure = getConversationTurnBoundaryError(runFailure);
7588
+ const failureCause = classifiedFailure?.cause ?? runFailure;
6759
7589
  if (failureCause instanceof AuthorizationFlowDisabledError || failureCause instanceof PluginCredentialFailureError) {
6760
7590
  terminalDispatchFailureOutcome = "blocked";
6761
7591
  }
@@ -7105,14 +7935,14 @@ function createPrepareTurnState(deps) {
7105
7935
  }
7106
7936
 
7107
7937
  // src/chat/slack/dispatch-turn.ts
7108
- import { Message as Message2, ThreadImpl as ThreadImpl2 } from "chat";
7938
+ import { Message as Message5, ThreadImpl as ThreadImpl4 } from "chat";
7109
7939
  function createSlackDispatchTurnRunner(options) {
7110
7940
  return async function runSlackDispatchTurn(dispatch2, hooks) {
7111
7941
  const state = getStateAdapter();
7112
7942
  await state.connect();
7113
7943
  const conversationId = getDispatchConversationId(dispatch2);
7114
7944
  const adapter = options.getSlackAdapter();
7115
- const message = new Message2({
7945
+ const message = new Message5({
7116
7946
  id: getDispatchInputMessageId(dispatch2.id),
7117
7947
  threadId: conversationId,
7118
7948
  text: dispatch2.input,
@@ -7135,7 +7965,7 @@ function createSlackDispatchTurnRunner(options) {
7135
7965
  }
7136
7966
  });
7137
7967
  message.isMention = true;
7138
- const thread = new ThreadImpl2({
7968
+ const thread = new ThreadImpl4({
7139
7969
  adapter,
7140
7970
  stateAdapter: state,
7141
7971
  id: conversationId,
@@ -7224,34 +8054,27 @@ function createSlackRuntime(options) {
7224
8054
  (message) => ensureSlackMessageActorIdentity(
7225
8055
  message,
7226
8056
  destination.teamId,
7227
- services.replyExecutor.lookupSlackUser
8057
+ lookupSlackUser
7228
8058
  )
7229
8059
  )
7230
8060
  );
7231
8061
  }
7232
8062
  });
7233
8063
  const executeSlackTurn = createSlackTurn({
8064
+ contextCompactor: services.contextCompactor,
8065
+ executeTurn: services.executeTurn,
7234
8066
  getSlackAdapter: options.getSlackAdapter,
8067
+ pausedTurns: options.pausedTurns ?? createPausedTurns(),
7235
8068
  prepareTurnState,
7236
8069
  resolveUserAttachments: services.visionContext.resolveUserAttachments,
7237
- services: services.replyExecutor
8070
+ sendPluginTask: options.sendPluginTask
7238
8071
  });
7239
8072
  const runtime = createSlackTurnRuntime({
7240
8073
  assistantUserName: botConfig.userName,
7241
8074
  cancelEventSubscriptions: cancelSubscriptions,
8075
+ getBotUserId: () => options.getSlackAdapter().botUserId,
7242
8076
  modelId: defaultModelId(botConfig),
7243
8077
  now: options.now ?? (() => Date.now()),
7244
- getThreadId,
7245
- getChannelId,
7246
- getRunId,
7247
- stripLeadingBotMention: (text, stripOptions) => stripLeadingBotMention(text, {
7248
- ...stripOptions,
7249
- botUserId: options.getSlackAdapter().botUserId
7250
- }),
7251
- withSpan,
7252
- logWarn,
7253
- logException,
7254
- failConversationTurn: (input) => services.replyExecutor.turnLifecycle.fail(input),
7255
8078
  prepareTurnState,
7256
8079
  persistPreparedState: async ({ thread, preparedState }) => {
7257
8080
  await persistThreadState(thread, {
@@ -7552,8 +8375,7 @@ async function runPausedTurnInContext(payload, options, runOptions) {
7552
8375
  "Paused turn"
7553
8376
  );
7554
8377
  const wakePausedTurn2 = options.wakePausedTurn ?? wakePausedTurn;
7555
- const resumeTurn = options.resumeTurn ?? resumeSlackTurn;
7556
- return await resumeTurn({
8378
+ return await resumeSlackTurn({
7557
8379
  messageText: "",
7558
8380
  conversationId: payload.conversationId,
7559
8381
  turnId: payload.turnId,
@@ -7562,7 +8384,7 @@ async function runPausedTurnInContext(payload, options, runOptions) {
7562
8384
  lockKey: payload.conversationId,
7563
8385
  // Queue continue runs under the conversation work lease already.
7564
8386
  ownsConversationLease: true,
7565
- agentRunner: options.agentRunner,
8387
+ executeTurn: async (run, saveResult, timeoutMs) => await executeTurn(options.agentRunner, run, saveResult, timeoutMs),
7566
8388
  scheduleSessionCompletedPluginTasks: options.scheduleSessionCompletedPluginTasks,
7567
8389
  beforeStart: async () => {
7568
8390
  let turn;
@@ -7650,7 +8472,7 @@ async function runPausedTurnInContext(payload, options, runOptions) {
7650
8472
  messageTs: getTurnUserSlackMessageTs(userMessage),
7651
8473
  inputMessageIds: [userMessage.id],
7652
8474
  initialStatus: latestReportedProgress(turnMessages),
7653
- replyContext: {
8475
+ run: {
7654
8476
  instruction: {
7655
8477
  ...conversationContext ? { context: conversationContext } : void 0,
7656
8478
  // Attachment fields come from the turn user message context helper.
@@ -7888,24 +8710,18 @@ async function runNextPausedTurnInContext(conversationId, options, runOptions) {
7888
8710
  // src/chat/app/conversation-work.ts
7889
8711
  function createConversationWork(options) {
7890
8712
  const apiTurnCancellation = createApiTurnCancellation();
7891
- const services = {
7892
- ...options.services,
7893
- replyExecutor: {
7894
- ...options.services?.replyExecutor,
7895
- agentRunner: options.agentRunner,
7896
- getPausedTurnRequest: options.services?.replyExecutor?.getPausedTurnRequest ?? (async (request) => await getPausedTurnRequest({
7897
- ...request,
7898
- conversationStore: options.conversationStore
7899
- })),
7900
- wakePausedTurn: options.services?.replyExecutor?.wakePausedTurn ?? (async (request) => await wakePausedTurn(request, {
7901
- queue: options.queue,
7902
- state: options.state
7903
- }))
7904
- }
7905
- };
8713
+ const pausedTurns = createPausedTurns({
8714
+ conversationStore: options.conversationStore,
8715
+ queue: options.queue,
8716
+ ...options.state ? { state: options.state } : void 0
8717
+ });
7906
8718
  const runtime = createSlackRuntime({
7907
8719
  getSlackAdapter: options.getSlackAdapter,
7908
- services
8720
+ pausedTurns,
8721
+ services: {
8722
+ ...options.services,
8723
+ agentRunner: options.agentRunner
8724
+ }
7909
8725
  });
7910
8726
  const slackWorker = createSlackConversationWorker({
7911
8727
  getSlackAdapter: options.getSlackAdapter,
@@ -7914,8 +8730,7 @@ function createConversationWork(options) {
7914
8730
  conversationId,
7915
8731
  {
7916
8732
  agentRunner: options.agentRunner,
7917
- scheduleSessionCompletedPluginTasks: services.replyExecutor?.scheduleSessionCompletedPluginTasks,
7918
- wakePausedTurn: services.replyExecutor?.wakePausedTurn
8733
+ wakePausedTurn: pausedTurns.wake
7919
8734
  },
7920
8735
  runOptions
7921
8736
  ),
@@ -7930,28 +8745,40 @@ function createConversationWork(options) {
7930
8745
  agentRunner: options.agentRunner,
7931
8746
  inputMessageIds: [getDispatchInputMessageId(dispatch2.id)],
7932
8747
  routingContext: buildDispatchRoutingContext(dispatch2),
7933
- scheduleSessionCompletedPluginTasks: services.replyExecutor?.scheduleSessionCompletedPluginTasks,
7934
- wakePausedTurn: services.replyExecutor?.wakePausedTurn
8748
+ wakePausedTurn: pausedTurns.wake
7935
8749
  },
7936
8750
  { shouldYield: hooks.shouldYield }
7937
8751
  );
7938
8752
  },
7939
8753
  runTurn: runtime.runDispatchTurn
7940
8754
  });
8755
+ const destinationWorker = async (context) => {
8756
+ const destination = context.destination;
8757
+ if (!destination) {
8758
+ throw new Error(
8759
+ `Conversation ${context.conversationId} is missing a destination`
8760
+ );
8761
+ }
8762
+ if (destination.platform === "slack") {
8763
+ return await slackWorker(context);
8764
+ }
8765
+ throw new Error(
8766
+ `Conversation ${context.conversationId} has a ${destination.platform} destination but no matching conversation worker`
8767
+ );
8768
+ };
7941
8769
  const providerWorker = createAgentDispatchWorkRouter({
7942
8770
  dispatchWorker,
7943
- fallbackWorker: slackWorker
8771
+ fallbackWorker: destinationWorker
7944
8772
  });
7945
8773
  return {
7946
8774
  apiTurnCancellation,
7947
8775
  conversationStore: options.conversationStore,
7948
8776
  queue: options.queue,
7949
8777
  run: routeApiTurnWork({
7950
- apiTurnWorker: createApiTurnWorker({
7951
- agentRunner: options.agentRunner,
7952
- cancellation: apiTurnCancellation,
7953
- turnLifecycle: services.replyExecutor?.turnLifecycle
7954
- }),
8778
+ apiTurnWorker: createApiTurnWorker(
8779
+ options.agentRunner,
8780
+ apiTurnCancellation
8781
+ ),
7955
8782
  fallbackWorker: routeAgentInvocationWork({
7956
8783
  invocationWorker: createAgentInvocationWorker(options.agentRunner),
7957
8784
  fallbackWorker: providerWorker
@@ -8151,6 +8978,66 @@ async function ingestEventTasks(input, options) {
8151
8978
  return { dispatched };
8152
8979
  }
8153
8980
 
8981
+ // src/chat/resource-events/workspace.ts
8982
+ function createResourceEventTeamIdResolver() {
8983
+ let pending;
8984
+ return async () => {
8985
+ if (!getSlackBotToken()) return void 0;
8986
+ pending ??= getSlackClient().auth.test().then((result) => {
8987
+ const teamId = result.team_id?.trim();
8988
+ if (!teamId) {
8989
+ throw new Error("Slack auth.test did not return a team id");
8990
+ }
8991
+ return teamId;
8992
+ }).catch((error) => {
8993
+ pending = void 0;
8994
+ throw error;
8995
+ });
8996
+ return await pending;
8997
+ };
8998
+ }
8999
+
9000
+ // src/chat/resource-events/app-publisher.ts
9001
+ function createResourceEventAppPublisher(args) {
9002
+ const resolveEventTaskTeamId = createResourceEventTeamIdResolver();
9003
+ return {
9004
+ async neededMatchKeys(input) {
9005
+ const work = args.conversationWork();
9006
+ const eventTaskTeamId = await resolveEventTaskTeamId();
9007
+ const [watchKeys, taskKeys] = await Promise.all([
9008
+ collectResourceEventMatchKeys({
9009
+ eventTypes: input.eventTypes,
9010
+ identifiers: input.identifiers,
9011
+ namespace: input.namespace,
9012
+ state: work.state
9013
+ }),
9014
+ eventTaskTeamId ? collectEventTaskMatchKeys(getDb(), {
9015
+ eventTypes: input.eventTypes,
9016
+ identifiers: input.identifiers,
9017
+ namespace: input.namespace,
9018
+ teamId: eventTaskTeamId
9019
+ }) : Promise.resolve([])
9020
+ ]);
9021
+ return [.../* @__PURE__ */ new Set([...watchKeys, ...taskKeys])].sort();
9022
+ },
9023
+ async publish(event) {
9024
+ const work = args.conversationWork();
9025
+ const queue = work.queue ?? getVercelConversationWorkQueue();
9026
+ const eventTaskTeamId = await resolveEventTaskTeamId();
9027
+ await Promise.all([
9028
+ ingestResourceEvent(event, {
9029
+ queue,
9030
+ state: work.state
9031
+ }),
9032
+ eventTaskTeamId ? ingestEventTasks(event, {
9033
+ queue,
9034
+ teamId: eventTaskTeamId
9035
+ }) : Promise.resolve()
9036
+ ]);
9037
+ }
9038
+ };
9039
+ }
9040
+
8154
9041
  // src/chat/api-turns/stop.ts
8155
9042
  async function stopApiConversationTurn(args) {
8156
9043
  const nowMs = args.nowMs ?? Date.now();
@@ -8353,7 +9240,7 @@ import {
8353
9240
  } from "crypto";
8354
9241
  import * as acp3 from "@agentclientprotocol/sdk";
8355
9242
  import { userSchema as userSchema2 } from "@sentry/junior-plugin-api";
8356
- import { z as z7 } from "zod";
9243
+ import { z as z8 } from "zod";
8357
9244
 
8358
9245
  // src/api/acp/state.ts
8359
9246
  import { setTimeout as wait } from "timers/promises";
@@ -8394,14 +9281,14 @@ async function fenceLock(state, lock, ttlMs = MUTATION_LOCK_TTL_MS) {
8394
9281
  import { createHash as createHash2, randomUUID } from "crypto";
8395
9282
  import * as acp2 from "@agentclientprotocol/sdk";
8396
9283
  import { userSchema } from "@sentry/junior-plugin-api";
8397
- import { z as z6 } from "zod";
9284
+ import { z as z7 } from "zod";
8398
9285
 
8399
9286
  // src/api/acp/schema.ts
8400
9287
  import * as acp from "@agentclientprotocol/sdk";
8401
- import { z as z5 } from "zod";
9288
+ import { z as z6 } from "zod";
8402
9289
  var ACP_SESSION_ID_PATTERN = /^local:acp:[a-f0-9]{32}$/;
8403
- var metaSchema = z5.record(z5.string(), z5.unknown()).nullable();
8404
- var jsonRpcIdSchema = z5.union([z5.string(), z5.number().finite(), z5.null()]);
9290
+ var metaSchema = z6.record(z6.string(), z6.unknown()).nullable();
9291
+ var jsonRpcIdSchema = z6.union([z6.string(), z6.number().finite(), z6.null()]);
8405
9292
  var SESSION_HEADER_METHODS = /* @__PURE__ */ new Set([
8406
9293
  acp.methods.agent.session.cancel,
8407
9294
  acp.methods.agent.session.close,
@@ -8411,78 +9298,94 @@ var SESSION_HEADER_METHODS = /* @__PURE__ */ new Set([
8411
9298
  acp.methods.agent.session.setConfigOption,
8412
9299
  acp.methods.agent.session.setMode
8413
9300
  ]);
8414
- var acpConnectionIdSchema = z5.string().uuid();
8415
- var acpSessionIdSchema = z5.string().regex(ACP_SESSION_ID_PATTERN);
8416
- var acpCallSchema = z5.object({
9301
+ var acpConnectionIdSchema = z6.string().uuid();
9302
+ var acpSessionIdSchema = z6.string().regex(ACP_SESSION_ID_PATTERN);
9303
+ var acpCallSchema = z6.object({
8417
9304
  id: jsonRpcIdSchema.optional(),
8418
- jsonrpc: z5.literal("2.0"),
8419
- method: z5.string().min(1),
8420
- params: z5.unknown().optional()
9305
+ jsonrpc: z6.literal("2.0"),
9306
+ method: z6.string().min(1),
9307
+ params: z6.unknown().optional()
8421
9308
  }).strict();
8422
- var jsonRpcErrorSchema = z5.object({
8423
- code: z5.number().int(),
8424
- data: z5.unknown().optional(),
8425
- message: z5.string()
9309
+ var jsonRpcErrorSchema = z6.object({
9310
+ code: z6.number().int(),
9311
+ data: z6.unknown().optional(),
9312
+ message: z6.string()
8426
9313
  }).strict();
8427
- var acpResponseSchema = z5.union([
8428
- z5.object({
9314
+ var acpResponseSchema = z6.union([
9315
+ z6.object({
8429
9316
  id: jsonRpcIdSchema,
8430
- jsonrpc: z5.literal("2.0"),
8431
- result: z5.unknown()
9317
+ jsonrpc: z6.literal("2.0"),
9318
+ result: z6.unknown()
8432
9319
  }).strict(),
8433
- z5.object({
9320
+ z6.object({
8434
9321
  error: jsonRpcErrorSchema,
8435
9322
  id: jsonRpcIdSchema,
8436
- jsonrpc: z5.literal("2.0")
9323
+ jsonrpc: z6.literal("2.0")
8437
9324
  }).strict()
8438
9325
  ]);
8439
- var acpInboundMessageSchema = z5.union([
9326
+ var acpInboundMessageSchema = z6.union([
8440
9327
  acpCallSchema,
8441
9328
  acpResponseSchema
8442
9329
  ]);
8443
- var implementationSchema = z5.object({
9330
+ var implementationSchema = z6.object({
8444
9331
  _meta: metaSchema.optional(),
8445
- name: z5.string().min(1),
8446
- title: z5.string().nullable().optional(),
8447
- version: z5.string()
9332
+ name: z6.string().min(1),
9333
+ title: z6.string().nullable().optional(),
9334
+ version: z6.string()
8448
9335
  }).strict();
8449
- var initializeParamsSchema = z5.object({
9336
+ var initializeParamsSchema = z6.object({
8450
9337
  _meta: metaSchema.optional(),
8451
- clientCapabilities: z5.record(z5.string(), z5.unknown()).optional(),
9338
+ clientCapabilities: z6.record(z6.string(), z6.unknown()).optional(),
8452
9339
  clientInfo: implementationSchema.nullable().optional(),
8453
- protocolVersion: z5.number().int().min(0).max(65535)
9340
+ protocolVersion: z6.number().int().min(0).max(65535)
8454
9341
  }).strict();
8455
- var authenticateParamsSchema = z5.object({
9342
+ var authenticateParamsSchema = z6.object({
8456
9343
  _meta: metaSchema.optional(),
8457
- methodId: z5.string().min(1)
9344
+ methodId: z6.string().min(1)
8458
9345
  }).strict();
8459
- var newSessionParamsSchema = z5.object({
9346
+ var newSessionParamsSchema = z6.object({
8460
9347
  _meta: metaSchema.optional(),
8461
- additionalDirectories: z5.array(z5.string()).optional(),
8462
- cwd: z5.string().min(1),
8463
- mcpServers: z5.array(z5.unknown())
9348
+ additionalDirectories: z6.array(z6.string()).optional(),
9349
+ cwd: z6.string().min(1),
9350
+ mcpServers: z6.array(z6.unknown())
8464
9351
  }).strict();
8465
9352
  var loadSessionParamsSchema = newSessionParamsSchema.extend({
8466
9353
  sessionId: acpSessionIdSchema
8467
9354
  });
8468
- var annotationsSchema = z5.object({
9355
+ var annotationsSchema = z6.object({
9356
+ _meta: metaSchema.optional(),
9357
+ audience: z6.array(z6.enum(["assistant", "user"])).nullable().optional(),
9358
+ lastModified: z6.string().nullable().optional(),
9359
+ priority: z6.number().finite().nullable().optional()
9360
+ }).strict();
9361
+ var textContentBlockSchema = z6.object({
8469
9362
  _meta: metaSchema.optional(),
8470
- audience: z5.array(z5.enum(["assistant", "user"])).nullable().optional(),
8471
- lastModified: z5.string().nullable().optional(),
8472
- priority: z5.number().finite().nullable().optional()
9363
+ annotations: annotationsSchema.nullable().optional(),
9364
+ text: z6.string(),
9365
+ type: z6.literal("text")
8473
9366
  }).strict();
8474
- var textContentBlockSchema = z5.object({
9367
+ var resourceLinkContentBlockSchema = z6.object({
8475
9368
  _meta: metaSchema.optional(),
8476
9369
  annotations: annotationsSchema.nullable().optional(),
8477
- text: z5.string(),
8478
- type: z5.literal("text")
9370
+ description: z6.string().nullable().optional(),
9371
+ mimeType: z6.string().nullable().optional(),
9372
+ name: z6.string(),
9373
+ size: z6.number().finite().nullable().optional(),
9374
+ title: z6.string().nullable().optional(),
9375
+ type: z6.literal("resource_link"),
9376
+ uri: z6.string()
8479
9377
  }).strict();
8480
- var promptParamsSchema = z5.object({
9378
+ var promptParamsSchema = z6.object({
8481
9379
  _meta: metaSchema.optional(),
8482
- prompt: z5.array(textContentBlockSchema),
9380
+ prompt: z6.array(
9381
+ z6.discriminatedUnion("type", [
9382
+ textContentBlockSchema,
9383
+ resourceLinkContentBlockSchema
9384
+ ])
9385
+ ),
8483
9386
  sessionId: acpSessionIdSchema
8484
9387
  }).strict();
8485
- var cancelParamsSchema = z5.object({
9388
+ var cancelParamsSchema = z6.object({
8486
9389
  _meta: metaSchema.optional(),
8487
9390
  sessionId: acpSessionIdSchema
8488
9391
  }).strict();
@@ -8520,41 +9423,41 @@ var MUTATION_LOCK_OPTIONS = {
8520
9423
  };
8521
9424
  var SSE_KEEP_ALIVE_MS = 15e3;
8522
9425
  var SSE_MAINTENANCE_INTERVAL_MS = 1e3;
8523
- var jsonRpcIdSchema2 = z6.union([z6.string(), z6.number().finite(), z6.null()]);
8524
- var acpConnectionSchema = z6.object({
8525
- credentialHash: z6.string().length(64),
8526
- nonce: z6.string().min(1),
9426
+ var jsonRpcIdSchema2 = z7.union([z7.string(), z7.number().finite(), z7.null()]);
9427
+ var acpConnectionSchema = z7.object({
9428
+ credentialHash: z7.string().length(64),
9429
+ nonce: z7.string().min(1),
8527
9430
  user: userSchema.optional()
8528
9431
  }).strict();
8529
- var acpStreamRouteSchema = z6.object({
8530
- connectionId: z6.string().min(1),
8531
- sessionId: z6.string().min(1).optional()
9432
+ var acpStreamRouteSchema = z7.object({
9433
+ connectionId: z7.string().min(1),
9434
+ sessionId: z7.string().min(1).optional()
8532
9435
  }).strict();
8533
- var acpPromptStreamOutputSchema = z6.object({
8534
- afterSeq: z6.number().int().nonnegative(),
8535
- kind: z6.literal("prompt"),
8536
- messageId: z6.string().min(1),
9436
+ var acpPromptStreamOutputSchema = z7.object({
9437
+ afterSeq: z7.number().int().nonnegative(),
9438
+ kind: z7.literal("prompt"),
9439
+ messageId: z7.string().min(1),
8537
9440
  requestId: jsonRpcIdSchema2,
8538
- turnId: z6.string().min(1)
9441
+ turnId: z7.string().min(1)
8539
9442
  }).strict();
8540
- var acpStreamOutputSchema = z6.discriminatedUnion("kind", [
8541
- z6.object({
8542
- kind: z6.literal("message"),
9443
+ var acpStreamOutputSchema = z7.discriminatedUnion("kind", [
9444
+ z7.object({
9445
+ kind: z7.literal("message"),
8543
9446
  message: acpInboundMessageSchema
8544
9447
  }).strict(),
8545
- z6.object({ kind: z6.literal("replay") }).strict(),
9448
+ z7.object({ kind: z7.literal("replay") }).strict(),
8546
9449
  acpPromptStreamOutputSchema
8547
9450
  ]);
8548
- var storedAcpStreamItemSchema = z6.object({
8549
- id: z6.string().min(1),
9451
+ var storedAcpStreamItemSchema = z7.object({
9452
+ id: z7.string().min(1),
8550
9453
  output: acpStreamOutputSchema
8551
9454
  }).strict();
8552
- var acpRequestReceiptSchema = z6.object({
8553
- deliveryKey: z6.string().min(1).optional(),
8554
- outputs: z6.array(acpStreamOutputSchema),
8555
- sessionId: z6.string().min(1).optional()
9455
+ var acpRequestReceiptSchema = z7.object({
9456
+ deliveryKey: z7.string().min(1).optional(),
9457
+ outputs: z7.array(acpStreamOutputSchema),
9458
+ sessionId: z7.string().min(1).optional()
8556
9459
  }).strict();
8557
- var acpStreamCursorSchema = z6.object({ itemId: z6.string().min(1) }).strict();
9460
+ var acpStreamCursorSchema = z7.object({ itemId: z7.string().min(1) }).strict();
8558
9461
  function stableHex(value) {
8559
9462
  return createHash2("sha256").update(value).digest("hex").slice(0, 32);
8560
9463
  }
@@ -9163,19 +10066,19 @@ function createSseBody(args) {
9163
10066
  var ACP_AUTHORIZATION_TTL_MS = 10 * 60 * 1e3;
9164
10067
  var ACP_CONNECTION_COOKIE = "junior_acp_connection";
9165
10068
  var LOCK_WAIT_MS2 = 5e3;
9166
- var jsonRpcIdSchema3 = z7.union([z7.string(), z7.number().finite(), z7.null()]);
9167
- var acpAuthorizationSchema = z7.object({
9168
- connectionId: z7.string().uuid(),
9169
- credentialHash: z7.string().length(64),
9170
- elicitationId: z7.string().uuid(),
9171
- expiresAtMs: z7.number().int().positive(),
10069
+ var jsonRpcIdSchema3 = z8.union([z8.string(), z8.number().finite(), z8.null()]);
10070
+ var acpAuthorizationSchema = z8.object({
10071
+ connectionId: z8.string().uuid(),
10072
+ credentialHash: z8.string().length(64),
10073
+ elicitationId: z8.string().uuid(),
10074
+ expiresAtMs: z8.number().int().positive(),
9172
10075
  requestId: jsonRpcIdSchema3,
9173
- requestKey: z7.string().min(1),
9174
- userCodeHash: z7.string().length(64)
10076
+ requestKey: z8.string().min(1),
10077
+ userCodeHash: z8.string().length(64)
9175
10078
  }).strict();
9176
- var acpAuthorizationPointerSchema = z7.object({
9177
- expiresAtMs: z7.number().int().positive(),
9178
- transactionId: z7.string().uuid()
10079
+ var acpAuthorizationPointerSchema = z8.object({
10080
+ expiresAtMs: z8.number().int().positive(),
10081
+ transactionId: z8.string().uuid()
9179
10082
  }).strict();
9180
10083
  var ACP_AUTH_METHOD_ID = "junior";
9181
10084
  var ACP_AUTH_METHOD = {
@@ -9502,7 +10405,7 @@ async function completeAcpAuthorization(args) {
9502
10405
  }
9503
10406
  async function handleAcpAuthorizationResponse(args) {
9504
10407
  if (typeof args.response.id !== "string") return "ignored";
9505
- const parsedId = z7.string().uuid().safeParse(args.response.id);
10408
+ const parsedId = z8.string().uuid().safeParse(args.response.id);
9506
10409
  if (!parsedId.success) return "ignored";
9507
10410
  const authorization = await readAuthorization(args.state, parsedId.data);
9508
10411
  if (!authorization || authorization.connectionId !== args.connectionId) {
@@ -9619,15 +10522,30 @@ function rejectUnsupportedMcpServers(mcpServers) {
9619
10522
  );
9620
10523
  }
9621
10524
  }
10525
+ function resourceLinkText(block) {
10526
+ return [
10527
+ "Resource link:",
10528
+ `Name: ${block.name}`,
10529
+ `URI: ${block.uri}`,
10530
+ ...block.title ? [`Title: ${block.title}`] : [],
10531
+ ...block.description ? [`Description: ${block.description}`] : [],
10532
+ ...block.mimeType ? [`MIME type: ${block.mimeType}`] : [],
10533
+ ...block.size !== void 0 && block.size !== null ? [`Size: ${block.size} bytes`] : []
10534
+ ].join("\n");
10535
+ }
9622
10536
  function promptText(prompt) {
9623
10537
  if (prompt.length === 0) {
9624
10538
  throw acp4.RequestError.invalidParams(
9625
10539
  { field: "prompt" },
9626
- "Junior accepts one or more text blocks only"
10540
+ "Junior accepts one or more text or resource link blocks"
9627
10541
  );
9628
10542
  }
9629
10543
  const blocks = [];
9630
10544
  for (const block of prompt) {
10545
+ if (block.type === "resource_link") {
10546
+ blocks.push(resourceLinkText(block));
10547
+ continue;
10548
+ }
9631
10549
  if (!block.text.trim()) {
9632
10550
  throw acp4.RequestError.invalidParams(
9633
10551
  { field: "prompt" },
@@ -10623,53 +11541,9 @@ async function createApp(options) {
10623
11541
  };
10624
11542
  let pluginRoutes = [];
10625
11543
  let pluginApiRoutes = [];
10626
- const resolveResourceEventTeamId = createResourceEventTeamIdResolver();
10627
- const resourceEvents = {
10628
- async neededMatchKeys(input) {
10629
- const teamId = await resolveResourceEventTeamId();
10630
- if (!teamId) return [];
10631
- const conversationWork = getConversationWorkOptions();
10632
- const [watchKeys, taskKeys] = await Promise.all([
10633
- collectResourceEventMatchKeys({
10634
- eventTypes: input.eventTypes,
10635
- identifiers: input.identifiers,
10636
- namespace: input.namespace,
10637
- state: conversationWork.state,
10638
- teamId
10639
- }),
10640
- collectEventTaskMatchKeys(getDb(), {
10641
- eventTypes: input.eventTypes,
10642
- identifiers: input.identifiers,
10643
- namespace: input.namespace,
10644
- teamId
10645
- })
10646
- ]);
10647
- return [.../* @__PURE__ */ new Set([...watchKeys, ...taskKeys])].sort();
10648
- },
10649
- async publish(event) {
10650
- const teamId = await resolveResourceEventTeamId();
10651
- if (!teamId) {
10652
- logWarn("resource_event.delivery.unavailable", {
10653
- "app.resource_event.namespace": event.namespace,
10654
- "app.resource_event.reason": "multi_workspace"
10655
- });
10656
- return;
10657
- }
10658
- const conversationWork = getConversationWorkOptions();
10659
- const queue = conversationWork.queue ?? getVercelConversationWorkQueue();
10660
- await Promise.all([
10661
- ingestResourceEvent(event, {
10662
- queue,
10663
- state: conversationWork.state,
10664
- teamId
10665
- }),
10666
- ingestEventTasks(event, {
10667
- queue,
10668
- teamId
10669
- })
10670
- ]);
10671
- }
10672
- };
11544
+ const resourceEvents = createResourceEventAppPublisher({
11545
+ conversationWork: () => getConversationWorkOptions()
11546
+ });
10673
11547
  let sandboxEgressTracePropagationDomains = [];
10674
11548
  try {
10675
11549
  sandboxEgressTracePropagationDomains = normalizeSandboxEgressTracePropagationDomains(
@@ -10710,7 +11584,7 @@ async function createApp(options) {
10710
11584
  tracePropagation
10711
11585
  });
10712
11586
  const runtimeServiceOverrides = {
10713
- replyExecutor: { agentRunner },
11587
+ agentRunner,
10714
11588
  sandbox: { tracePropagation }
10715
11589
  };
10716
11590
  let conversationWorkOptions;