@sentry/junior 0.90.0 → 0.92.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 (131) hide show
  1. package/dist/{agent-hooks-MXAF7RQL.js → agent-hooks-BYSSWCNW.js} +7 -7
  2. package/dist/api/people/list.d.ts +3 -3
  3. package/dist/api/people/list.js +15 -15
  4. package/dist/api/people/list.query.d.ts +2 -2
  5. package/dist/api/people/profile.d.ts +3 -3
  6. package/dist/api/people/profile.js +12 -12
  7. package/dist/api/people/profile.query.d.ts +2 -2
  8. package/dist/api/people/shared.d.ts +13 -13
  9. package/dist/api/people/types.d.ts +12 -12
  10. package/dist/api-reference.d.ts +1 -1
  11. package/dist/app.js +406 -267
  12. package/dist/{catalog-runtime-DXE6NXHT.js → catalog-runtime-NZHMSMYC.js} +2 -2
  13. package/dist/chat/actor.d.ts +75 -0
  14. package/dist/chat/agent/prompt.d.ts +4 -4
  15. package/dist/chat/agent/request.d.ts +21 -13
  16. package/dist/chat/agent/resume.d.ts +5 -4
  17. package/dist/chat/agent/tools.d.ts +2 -2
  18. package/dist/chat/capabilities/jr-rpc-command.d.ts +1 -1
  19. package/dist/chat/conversation-privacy.d.ts +11 -0
  20. package/dist/chat/conversations/sql/migrations.d.ts +1 -1
  21. package/dist/chat/conversations/sql/schema/conversations.d.ts +2 -19
  22. package/dist/chat/conversations/sql/schema.d.ts +2 -19
  23. package/dist/chat/conversations/sql/store.d.ts +3 -3
  24. package/dist/chat/conversations/store.d.ts +4 -4
  25. package/dist/chat/credentials/context.d.ts +4 -4
  26. package/dist/chat/current-instruction.d.ts +5 -3
  27. package/dist/chat/logging.d.ts +2 -2
  28. package/dist/chat/no-reply.d.ts +1 -1
  29. package/dist/chat/oauth-authorization-message.d.ts +6 -0
  30. package/dist/chat/oauth-flow.d.ts +1 -1
  31. package/dist/chat/pi/messages.d.ts +2 -2
  32. package/dist/chat/pi/transcript.d.ts +15 -0
  33. package/dist/chat/plugins/agent-hooks.d.ts +3 -3
  34. package/dist/chat/plugins/credential-hooks.d.ts +2 -8
  35. package/dist/chat/prompt.d.ts +3 -6
  36. package/dist/chat/runtime/reply-executor.d.ts +1 -1
  37. package/dist/chat/runtime/turn-input.d.ts +1 -1
  38. package/dist/chat/sandbox/egress/schemas.d.ts +2 -2
  39. package/dist/chat/sandbox/egress/session.d.ts +1 -1
  40. package/dist/chat/services/context-compaction.d.ts +1 -1
  41. package/dist/chat/services/conversation-memory.d.ts +1 -1
  42. package/dist/chat/services/mcp-auth-orchestration.d.ts +1 -1
  43. package/dist/chat/services/message-actor-identity.d.ts +4 -4
  44. package/dist/chat/services/pending-auth.d.ts +2 -2
  45. package/dist/chat/services/plugin-auth-orchestration.d.ts +1 -1
  46. package/dist/chat/services/provider-default-config.d.ts +1 -1
  47. package/dist/chat/services/subscribed-decision.d.ts +1 -1
  48. package/dist/chat/services/turn-result.d.ts +1 -1
  49. package/dist/chat/services/turn-session-record.d.ts +11 -8
  50. package/dist/chat/services/turn-thinking-level.d.ts +1 -1
  51. package/dist/chat/slack/assistant-thread/title.d.ts +1 -1
  52. package/dist/chat/slack/mrkdwn.d.ts +6 -0
  53. package/dist/chat/slack/tools/canvas/create.d.ts +41 -1
  54. package/dist/chat/slack/tools/canvas/edit.d.ts +60 -1
  55. package/dist/chat/slack/tools/canvas/read.d.ts +60 -1
  56. package/dist/chat/slack/tools/canvas/write.d.ts +41 -1
  57. package/dist/chat/slack/tools/channel-list-messages.d.ts +45 -1
  58. package/dist/chat/slack/tools/context.d.ts +3 -3
  59. package/dist/chat/slack/tools/list/add-items.d.ts +42 -1
  60. package/dist/chat/slack/tools/list/create.d.ts +40 -1
  61. package/dist/chat/slack/tools/list/get-items.d.ts +40 -1
  62. package/dist/chat/slack/tools/list/update-item.d.ts +46 -1
  63. package/dist/chat/slack/tools/message-add-reaction.d.ts +40 -1
  64. package/dist/chat/slack/tools/send-message.d.ts +45 -1
  65. package/dist/chat/slack/tools/thread-read.d.ts +44 -1
  66. package/dist/chat/slack/tools/user-lookup.d.ts +45 -1
  67. package/dist/chat/slack/user.d.ts +3 -3
  68. package/dist/chat/slack/vision-context.d.ts +2 -2
  69. package/dist/chat/sql/schema.d.ts +2 -19
  70. package/dist/chat/state/conversation-details.d.ts +4 -4
  71. package/dist/chat/state/conversation.d.ts +1 -1
  72. package/dist/chat/state/session-log.d.ts +140 -26
  73. package/dist/chat/state/turn-session.d.ts +18 -5
  74. package/dist/chat/task-execution/slack-work.d.ts +2 -2
  75. package/dist/chat/task-execution/state.d.ts +4 -4
  76. package/dist/chat/tool-support/zod-tool.d.ts +16 -4
  77. package/dist/chat/tools/advisor/tool.d.ts +41 -1
  78. package/dist/chat/tools/definition.d.ts +10 -0
  79. package/dist/chat/tools/execute-tool.d.ts +41 -1
  80. package/dist/chat/tools/resource-events.d.ts +124 -3
  81. package/dist/chat/tools/runtime/report-progress.d.ts +40 -1
  82. package/dist/chat/tools/sandbox/bash.d.ts +41 -1
  83. package/dist/chat/tools/sandbox/edit-file.d.ts +44 -1
  84. package/dist/chat/tools/sandbox/find-files.d.ts +42 -1
  85. package/dist/chat/tools/sandbox/grep.d.ts +46 -1
  86. package/dist/chat/tools/sandbox/list-dir.d.ts +41 -1
  87. package/dist/chat/tools/sandbox/read-file.d.ts +42 -1
  88. package/dist/chat/tools/sandbox/write-file.d.ts +41 -1
  89. package/dist/chat/tools/search-tools.d.ts +102 -1
  90. package/dist/chat/tools/skill/call-mcp-tool.d.ts +10 -1
  91. package/dist/chat/tools/skill/load-skill.d.ts +40 -1
  92. package/dist/chat/tools/skill/search-mcp-tools.d.ts +100 -1
  93. package/dist/chat/tools/system-time.d.ts +38 -1
  94. package/dist/chat/tools/types.d.ts +4 -4
  95. package/dist/chat/tools/web/fetch-tool.d.ts +41 -1
  96. package/dist/chat/tools/web/image-generate.d.ts +62 -1
  97. package/dist/chat/tools/web/search.d.ts +41 -1
  98. package/dist/{chunk-HXL2ZV74.js → chunk-3F54A3YM.js} +82 -11
  99. package/dist/{chunk-BKSZL4QO.js → chunk-7DVIELX3.js} +670 -401
  100. package/dist/{chunk-GCWD2VHP.js → chunk-7FS3K243.js} +284 -124
  101. package/dist/{chunk-AOISHLSF.js → chunk-ACJENBVF.js} +143 -20
  102. package/dist/{chunk-IRRMABQD.js → chunk-APIVR44P.js} +10 -10
  103. package/dist/{chunk-PHZHJTCK.js → chunk-BMQ5DXHV.js} +30 -52
  104. package/dist/{chunk-XP7F4LYB.js → chunk-BTH37NCU.js} +4 -4
  105. package/dist/{chunk-5GBUZI6M.js → chunk-H7KUZAMZ.js} +4 -4
  106. package/dist/{chunk-TYUXD3FN.js → chunk-MC4ZZE4Q.js} +1 -1
  107. package/dist/{chunk-QCKGI74V.js → chunk-N25HRI6B.js} +10 -10
  108. package/dist/{chunk-2S7M37HY.js → chunk-NIFONS4W.js} +86 -47
  109. package/dist/{chunk-ONFOWI2D.js → chunk-OJP53WIU.js} +16 -15
  110. package/dist/{chunk-NW7AXDA5.js → chunk-OZJXGX4U.js} +2 -2
  111. package/dist/{chunk-KC42JAAQ.js → chunk-PFXC67GJ.js} +3 -3
  112. package/dist/{chunk-ZUK7BL63.js → chunk-S6QKIGRM.js} +66 -54
  113. package/dist/{chunk-IX76WFJV.js → chunk-TF5VLGA7.js} +10 -10
  114. package/dist/{chunk-DACFZ5CI.js → chunk-VY7TVOIK.js} +16 -12
  115. package/dist/{chunk-AN2437E3.js → chunk-YTNPU7I2.js} +2 -2
  116. package/dist/{chunk-3MPOMK3K.js → chunk-YYBX2BD5.js} +61 -3
  117. package/dist/{chunk-RS6ANWVT.js → chunk-ZATRYQLR.js} +1 -1
  118. package/dist/cli/chat.js +20 -20
  119. package/dist/cli/check.js +3 -3
  120. package/dist/cli/plugins.js +9 -9
  121. package/dist/cli/snapshot-warmup.js +6 -6
  122. package/dist/cli/upgrade.js +9 -9
  123. package/dist/{db-CXI7PR5U.js → db-GCK43OO3.js} +4 -4
  124. package/dist/instrumentation.js +1 -1
  125. package/dist/reporting/conversations.d.ts +3 -3
  126. package/dist/reporting.d.ts +1 -1
  127. package/dist/reporting.js +48 -50
  128. package/dist/{runner-FKL3RAHA.js → runner-XWTFA26U.js} +20 -18
  129. package/dist/{validation-I7GD2YWS.js → validation-KYAWETI4.js} +3 -3
  130. package/package.json +6 -6
  131. package/dist/chat/requester.d.ts +0 -68
package/dist/app.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  scheduleSessionCompletedPluginTasks,
18
18
  updateConversationStats,
19
19
  upsertConversationMessage
20
- } from "./chunk-AOISHLSF.js";
20
+ } from "./chunk-ACJENBVF.js";
21
21
  import {
22
22
  CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
23
23
  CONVERSATION_WORK_STALE_ENQUEUE_MS,
@@ -41,7 +41,7 @@ import {
41
41
  requestConversationContinuation,
42
42
  requestConversationWork,
43
43
  startConversationWork
44
- } from "./chunk-IX76WFJV.js";
44
+ } from "./chunk-TF5VLGA7.js";
45
45
  import {
46
46
  getVercelConversationWorkQueue,
47
47
  resolveConversationWorkQueueTopic,
@@ -60,11 +60,11 @@ import {
60
60
  resolveSlackChannelTypeFromMessage,
61
61
  resolveSlackConversationContext,
62
62
  setConversationTitle
63
- } from "./chunk-QCKGI74V.js";
63
+ } from "./chunk-N25HRI6B.js";
64
64
  import {
65
65
  validatePluginEgressCredentialHooks,
66
66
  validatePluginRegistrations
67
- } from "./chunk-TYUXD3FN.js";
67
+ } from "./chunk-MC4ZZE4Q.js";
68
68
  import {
69
69
  defineJuniorPlugins,
70
70
  pluginCatalogConfigFromEnv,
@@ -104,7 +104,7 @@ import {
104
104
  shouldPropagateSandboxEgressTrace,
105
105
  startOAuthFlow,
106
106
  unlinkProvider
107
- } from "./chunk-BKSZL4QO.js";
107
+ } from "./chunk-7DVIELX3.js";
108
108
  import {
109
109
  CooperativeTurnYieldError,
110
110
  TurnInputCommitLostError,
@@ -131,30 +131,33 @@ import {
131
131
  persistThreadStateById,
132
132
  persistYieldSessionRecord,
133
133
  startActiveTurn
134
- } from "./chunk-ONFOWI2D.js";
134
+ } from "./chunk-OJP53WIU.js";
135
135
  import {
136
136
  JUNIOR_THREAD_STATE_TTL_MS,
137
137
  coerceThreadConversationState
138
- } from "./chunk-KC42JAAQ.js";
139
- import "./chunk-5GBUZI6M.js";
138
+ } from "./chunk-PFXC67GJ.js";
139
+ import "./chunk-H7KUZAMZ.js";
140
140
  import {
141
141
  buildSlackOutputMessage,
142
+ escapeSlackMrkdwnText,
143
+ formatSlackLink,
142
144
  normalizeSlackStatusText,
143
145
  splitSlackReplyText,
144
- truncateStatusText,
145
- unwrapCurrentInstruction
146
- } from "./chunk-PHZHJTCK.js";
146
+ truncateStatusText
147
+ } from "./chunk-BMQ5DXHV.js";
147
148
  import {
148
149
  abandonAgentTurnSessionRecord,
149
150
  commitMessages,
150
- escapeXml,
151
+ contextProvenance,
151
152
  failAgentTurnSessionRecord,
152
153
  getAgentTurnSessionRecord,
154
+ instructionProvenanceFor,
153
155
  listAgentTurnSessionSummariesForConversation,
154
156
  loadProjection,
157
+ loadProjectionWithProvenance,
155
158
  recordAgentTurnSessionSummary,
156
159
  recordAuthorizationCompleted
157
- } from "./chunk-GCWD2VHP.js";
160
+ } from "./chunk-7FS3K243.js";
158
161
  import {
159
162
  SlackActionError,
160
163
  bindSlackDirectCredentialSubject,
@@ -173,25 +176,26 @@ import {
173
176
  setPlugins,
174
177
  validatePlugins,
175
178
  verifySlackDirectCredentialSubject
176
- } from "./chunk-DACFZ5CI.js";
179
+ } from "./chunk-VY7TVOIK.js";
177
180
  import {
178
181
  createPluginLogger,
179
182
  createPluginState
180
- } from "./chunk-NW7AXDA5.js";
183
+ } from "./chunk-OZJXGX4U.js";
181
184
  import "./chunk-G3E7SCME.js";
182
185
  import {
183
186
  acquireActiveLock,
184
187
  getStateAdapter
185
- } from "./chunk-RS6ANWVT.js";
188
+ } from "./chunk-ZATRYQLR.js";
186
189
  import {
187
190
  getConversationStore,
188
191
  getDb
189
- } from "./chunk-2S7M37HY.js";
192
+ } from "./chunk-NIFONS4W.js";
190
193
  import {
191
194
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
192
195
  botConfig,
193
196
  completeObject,
194
197
  completeText,
198
+ escapeXml,
195
199
  getChatConfig,
196
200
  getRuntimeMetadata,
197
201
  getSlackBotToken,
@@ -203,14 +207,15 @@ import {
203
207
  normalizeSlackEmojiName,
204
208
  setSlackReactionConfig,
205
209
  stripRuntimeTurnContext,
206
- trimTrailingAssistantMessages
207
- } from "./chunk-HXL2ZV74.js";
210
+ trimTrailingAssistantMessages,
211
+ unwrapCurrentInstruction
212
+ } from "./chunk-3F54A3YM.js";
208
213
  import {
209
214
  parseSlackThreadId,
210
215
  readSlackRawMessageContext,
211
216
  resolveSlackChannelIdFromMessage,
212
217
  resolveSlackChannelIdFromThreadId
213
- } from "./chunk-3MPOMK3K.js";
218
+ } from "./chunk-YYBX2BD5.js";
214
219
  import {
215
220
  createSlackDestination,
216
221
  destinationKey,
@@ -220,22 +225,23 @@ import {
220
225
  } from "./chunk-GHGPTPBL.js";
221
226
  import {
222
227
  discoverSkills
223
- } from "./chunk-AN2437E3.js";
228
+ } from "./chunk-YTNPU7I2.js";
224
229
  import {
225
230
  buildOAuthTokenRequest,
226
231
  hasRequiredOAuthScope,
227
232
  parseOAuthTokenResponse,
228
233
  pluginCatalogRuntime
229
- } from "./chunk-XP7F4LYB.js";
234
+ } from "./chunk-BTH37NCU.js";
230
235
  import {
231
236
  buildTurnFailureResponse,
237
+ createActor,
232
238
  createChatSdkLogger,
233
239
  createRequestContext,
234
- createRequester,
235
- createSlackRequester,
236
- createSlackResumeRequester,
240
+ createSlackActor,
241
+ createSlackResumeActor,
237
242
  getActiveTraceId,
238
243
  isActorUserId,
244
+ isUserActor,
239
245
  logError,
240
246
  logException,
241
247
  logInfo,
@@ -245,10 +251,10 @@ import {
245
251
  setSpanAttributes,
246
252
  setSpanStatus,
247
253
  setTags,
248
- toStoredSlackRequester,
254
+ toStoredSlackActor,
249
255
  withContext,
250
256
  withSpan
251
- } from "./chunk-ZUK7BL63.js";
257
+ } from "./chunk-S6QKIGRM.js";
252
258
  import {
253
259
  toOptionalString
254
260
  } from "./chunk-OB42YVAE.js";
@@ -321,12 +327,6 @@ function getDashboardConversationLink(conversationId) {
321
327
  }
322
328
 
323
329
  // src/chat/slack/footer.ts
324
- function escapeSlackMrkdwn(text) {
325
- return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
326
- }
327
- function escapeSlackLinkUrl(url) {
328
- return url.replaceAll("&", "&amp;").replaceAll("<", "%3C").replaceAll(">", "%3E");
329
- }
330
330
  function buildSlackReplyFooter(args) {
331
331
  const items = [];
332
332
  const conversationId = args.conversationId?.trim();
@@ -358,7 +358,7 @@ function buildSlackReplyBlocks(text, footer) {
358
358
  type: "context",
359
359
  elements: footer.items.map((item) => ({
360
360
  type: "mrkdwn",
361
- text: item.url ? `*${escapeSlackMrkdwn(item.label)}:* <${escapeSlackLinkUrl(item.url)}|${escapeSlackMrkdwn(item.value)}>` : `*${escapeSlackMrkdwn(item.label)}:* ${escapeSlackMrkdwn(item.value)}`
361
+ text: item.url ? `*${escapeSlackMrkdwnText(item.label)}:* ${formatSlackLink(item.url, item.value)}` : `*${escapeSlackMrkdwnText(item.label)}:* ${escapeSlackMrkdwnText(item.value)}`
362
362
  }))
363
363
  });
364
364
  }
@@ -588,8 +588,8 @@ var dispatchStatusSchema = z.enum([
588
588
  "blocked"
589
589
  ]);
590
590
  var dispatchActorSchema = z.object({
591
- type: z.literal("system"),
592
- id: nonEmptyExactStringSchema
591
+ platform: z.literal("system"),
592
+ name: nonEmptyExactStringSchema
593
593
  }).strict();
594
594
  var credentialSubjectBindingSchema = z.object({
595
595
  type: z.literal("slack-direct-conversation"),
@@ -776,7 +776,7 @@ async function createOrGetDispatch(args) {
776
776
  }
777
777
  const metadata = normalizeMetadata(args.options.metadata);
778
778
  const record = {
779
- actor: { type: "system", id: args.plugin },
779
+ actor: { platform: "system", name: args.plugin },
780
780
  attempt: 0,
781
781
  createdAtMs: args.nowMs,
782
782
  ...args.options.credentialSubject ? { credentialSubject: args.options.credentialSubject } : {},
@@ -854,7 +854,7 @@ function upsertDispatchUserMessage(args) {
854
854
  ),
855
855
  createdAtMs: args.nowMs,
856
856
  author: {
857
- userName: `system:${args.dispatch.actor.id}`,
857
+ userName: `system:${args.dispatch.actor.name}`,
858
858
  isBot: true
859
859
  },
860
860
  meta: {
@@ -927,8 +927,8 @@ async function runAgentDispatchSlice(callback, deps) {
927
927
  slackThreadId: conversationId,
928
928
  slackChannelId: dispatch.destination.channelId,
929
929
  runId: dispatch.id,
930
- actorType: dispatch.actor.type,
931
- actorId: dispatch.actor.id,
930
+ actorType: dispatch.actor.platform,
931
+ actorId: dispatch.actor.name,
932
932
  assistantUserName: botConfig.userName
933
933
  };
934
934
  const destinationLockId = getDispatchDestinationLockId(dispatch.destination);
@@ -1147,6 +1147,7 @@ async function runAgentDispatchSlice(callback, deps) {
1147
1147
  usage: reply.diagnostics.usage,
1148
1148
  destination: dispatch.destination,
1149
1149
  source: dispatch.source,
1150
+ actor: dispatch.actor,
1150
1151
  surface: "api",
1151
1152
  logContext: {
1152
1153
  threadId: conversationId,
@@ -1280,7 +1281,7 @@ async function recordExecutionMetadata(args) {
1280
1281
  updatedAtMs: conversation.execution.updatedAtMs
1281
1282
  },
1282
1283
  lastActivityAtMs: conversation.lastActivityAtMs,
1283
- requester: conversation.requester,
1284
+ actor: conversation.actor,
1284
1285
  source: conversation.source,
1285
1286
  title: conversation.title,
1286
1287
  updatedAtMs: conversation.updatedAtMs
@@ -1577,53 +1578,51 @@ async function runWithSlackInstallation(args) {
1577
1578
 
1578
1579
  // src/chat/services/message-actor-identity.ts
1579
1580
  var messageActors = /* @__PURE__ */ new WeakMap();
1580
- function canonicalUserId(author, requester) {
1581
+ function canonicalUserId(author, actor) {
1581
1582
  const authorUserId = parseActorUserId(author.userId);
1582
- if (authorUserId && authorUserId !== requester.userId) {
1583
- throw new Error("Message requester user id mismatch");
1583
+ if (authorUserId && authorUserId !== actor.userId) {
1584
+ throw new Error("Message actor user id mismatch");
1584
1585
  }
1585
- const userId = authorUserId ?? requester.userId;
1586
+ const userId = authorUserId ?? actor.userId;
1586
1587
  if (!userId) {
1587
- throw new Error("Message requester requires a user id");
1588
+ throw new Error("Message actor requires a user id");
1588
1589
  }
1589
1590
  return userId;
1590
1591
  }
1591
- function requesterFromAuthor(author) {
1592
+ function actorFromAuthor(author) {
1592
1593
  const userId = parseActorUserId(author.userId);
1593
1594
  return userId ? { userId } : void 0;
1594
1595
  }
1595
- function applyRequesterToAuthor(author, requester) {
1596
- if (!isActorUserId(requester.userId)) {
1597
- throw new Error("Message requester requires a user id");
1596
+ function applyActorToAuthor(author, actor) {
1597
+ if (!isActorUserId(actor.userId)) {
1598
+ throw new Error("Message actor requires a user id");
1598
1599
  }
1599
- author.userId = requester.userId;
1600
- author.userName = requester.userName ?? "";
1601
- author.fullName = requester.fullName ?? "";
1600
+ author.userId = actor.userId;
1601
+ author.userName = actor.userName ?? "";
1602
+ author.fullName = actor.fullName ?? "";
1602
1603
  }
1603
- function bindMessageActorIdentity(message, requester) {
1604
- const userId = canonicalUserId(message.author, requester);
1605
- const actorRequester = createRequester(requester, {
1606
- platform: requester.platform,
1607
- ...requester.platform === "slack" ? { teamId: requester.teamId } : {},
1604
+ function bindMessageActorIdentity(message, actor) {
1605
+ const userId = canonicalUserId(message.author, actor);
1606
+ const currentActor = createActor(actor, {
1607
+ platform: actor.platform,
1608
+ ...actor.platform === "slack" ? { teamId: actor.teamId } : {},
1608
1609
  userId
1609
1610
  });
1610
- if (!actorRequester) {
1611
- throw new Error("Message requester requires a user id");
1611
+ if (!currentActor) {
1612
+ throw new Error("Message actor requires a user id");
1612
1613
  }
1613
- messageActors.set(message, actorRequester);
1614
- applyRequesterToAuthor(message.author, actorRequester);
1615
- return actorRequester;
1614
+ messageActors.set(message, currentActor);
1615
+ applyActorToAuthor(message.author, currentActor);
1616
+ return currentActor;
1616
1617
  }
1617
1618
  function getMessageActorIdentity(message) {
1618
- return messageActors.get(message) ?? requesterFromAuthor(message.author);
1619
+ return messageActors.get(message) ?? actorFromAuthor(message.author);
1619
1620
  }
1620
1621
  async function ensureSlackMessageActorIdentity(message, teamId, lookupSlackUser2) {
1621
1622
  const existing = messageActors.get(message);
1622
1623
  if (existing) {
1623
1624
  if (existing.platform !== "slack") {
1624
- throw new Error(
1625
- "Slack message actor identity requires a Slack requester"
1626
- );
1625
+ throw new Error("Slack message actor identity requires a Slack actor");
1627
1626
  }
1628
1627
  return existing;
1629
1628
  }
@@ -1631,14 +1630,14 @@ async function ensureSlackMessageActorIdentity(message, teamId, lookupSlackUser2
1631
1630
  if (!userId) {
1632
1631
  throw new Error("Slack message actor identity requires a user id");
1633
1632
  }
1634
- const requester = bindMessageActorIdentity(
1633
+ const actor = bindMessageActorIdentity(
1635
1634
  message,
1636
- createSlackRequester(teamId, userId, await lookupSlackUser2(teamId, userId))
1635
+ createSlackActor(teamId, userId, await lookupSlackUser2(teamId, userId))
1637
1636
  );
1638
- if (requester.platform !== "slack") {
1639
- throw new Error("Slack message actor identity requires a Slack requester");
1637
+ if (actor.platform !== "slack") {
1638
+ throw new Error("Slack message actor identity requires a Slack actor");
1640
1639
  }
1641
- return requester;
1640
+ return actor;
1642
1641
  }
1643
1642
 
1644
1643
  // src/chat/slack/user.ts
@@ -1723,8 +1722,8 @@ async function lookupSlackUser(teamId, userId) {
1723
1722
  return null;
1724
1723
  }
1725
1724
  }
1726
- async function lookupSlackRequester(teamId, userId) {
1727
- return createSlackRequester(
1725
+ async function lookupSlackActor(teamId, userId) {
1726
+ return createSlackActor(
1728
1727
  teamId,
1729
1728
  userId,
1730
1729
  await lookupSlackUser(teamId, userId)
@@ -3776,8 +3775,8 @@ function getResumeLogContext(args, lockKey) {
3776
3775
  return {
3777
3776
  conversationId: routing?.correlation?.conversationId ?? lockKey,
3778
3777
  slackThreadId: routing?.correlation?.threadId ?? lockKey,
3779
- slackUserId: routing?.requester?.userId ?? routing?.correlation?.requesterId,
3780
- slackUserName: routing?.requester?.userName,
3778
+ slackUserId: isUserActor(routing?.actor) ? routing.actor.userId : routing?.correlation?.actorId,
3779
+ slackUserName: isUserActor(routing?.actor) ? routing.actor.userName : void 0,
3781
3780
  slackChannelId: args.channelId,
3782
3781
  runId: routing?.correlation?.runId,
3783
3782
  assistantUserName: botConfig.userName,
@@ -3853,7 +3852,7 @@ function createResumeReplyContext(args, statusSession) {
3853
3852
  threadId: replyContext.routing.correlation?.threadId ?? threadId,
3854
3853
  channelId: replyContext.routing.correlation?.channelId ?? args.channelId,
3855
3854
  threadTs: replyContext.routing.correlation?.threadTs ?? args.threadTs,
3856
- requesterId: replyContext.routing.correlation?.requesterId ?? replyContext.routing.requester?.userId
3855
+ actorId: replyContext.routing.correlation?.actorId ?? (isUserActor(replyContext.routing.actor) ? replyContext.routing.actor.userId : void 0)
3857
3856
  }
3858
3857
  },
3859
3858
  policy: {
@@ -3913,18 +3912,25 @@ async function resumeSlackTurn(args) {
3913
3912
  if (preparedArgs) {
3914
3913
  runArgs = { ...args, ...preparedArgs };
3915
3914
  }
3916
- if (!runArgs.replyContext?.routing.requester?.userId) {
3915
+ const activeReplyContext = runArgs.replyContext;
3916
+ if (!activeReplyContext) {
3917
+ throw new Error(
3918
+ "Resumed turn requires replyContext.routing.actor.userId"
3919
+ );
3920
+ }
3921
+ const resumeActor = activeReplyContext.routing.actor;
3922
+ if (!isUserActor(resumeActor)) {
3917
3923
  throw new Error(
3918
- "Resumed turn requires replyContext.routing.requester.userId"
3924
+ "Resumed turn requires replyContext.routing.actor.userId"
3919
3925
  );
3920
3926
  }
3921
- const credentialContext = runArgs.replyContext.routing.credentialContext;
3927
+ const credentialContext = activeReplyContext.routing.credentialContext;
3922
3928
  if (!credentialContext) {
3923
3929
  throw new Error("Resumed turn requires replyContext.credentialContext");
3924
3930
  }
3925
- if (credentialContext.actor.type !== "user" || credentialContext.actor.userId !== runArgs.replyContext.routing.requester.userId) {
3931
+ if (!("type" in credentialContext.actor) || credentialContext.actor.userId !== resumeActor.userId) {
3926
3932
  throw new Error(
3927
- "Resumed turn credential actor must match replyContext.routing.requester.userId"
3933
+ "Resumed turn credential actor must match replyContext.routing.actor.userId"
3928
3934
  );
3929
3935
  }
3930
3936
  if (runArgs.messageTs) {
@@ -3967,7 +3973,7 @@ async function resumeSlackTurn(args) {
3967
3973
  deferredPauseKind = "auth";
3968
3974
  deferredAuthInfo = {
3969
3975
  providerDisplayName: outcome.providerDisplayName,
3970
- requesterId: runArgs.replyContext?.routing.requester?.userId
3976
+ actorId: resumeActor.userId
3971
3977
  };
3972
3978
  deferredPauseHandler = async () => {
3973
3979
  await onAuthPause({
@@ -4019,11 +4025,11 @@ async function resumeSlackTurn(args) {
4019
4025
  currentUsage: reply.diagnostics.usage,
4020
4026
  destination: replyContext.routing.destination,
4021
4027
  source: replyContext.routing.source,
4022
- requester: replyContext.routing.requester,
4028
+ actor: replyContext.routing.actor,
4023
4029
  surface: "slack",
4024
4030
  logContext: {
4025
4031
  threadId: replyContext.routing.correlation.threadId,
4026
- requesterId: replyContext.routing.requester?.userId,
4032
+ actorId: isUserActor(replyContext.routing.actor) ? replyContext.routing.actor.userId : void 0,
4027
4033
  channelId: runArgs.channelId,
4028
4034
  runId: replyContext.routing.correlation.runId,
4029
4035
  assistantUserName: botConfig.userName,
@@ -4109,7 +4115,7 @@ async function resumeSlackTurn(args) {
4109
4115
  runArgs.channelId,
4110
4116
  runArgs.threadTs,
4111
4117
  buildAuthPauseResponse(
4112
- deferredAuthInfo.requesterId,
4118
+ deferredAuthInfo.actorId,
4113
4119
  deferredAuthInfo.providerDisplayName
4114
4120
  ),
4115
4121
  footer
@@ -4353,7 +4359,7 @@ async function resumeAuthorizedMcpTurn(args) {
4353
4359
  conversation,
4354
4360
  kind: "mcp",
4355
4361
  provider,
4356
- requesterId: authSession.userId
4362
+ actorId: authSession.userId
4357
4363
  });
4358
4364
  const resolvedSessionId = pendingAuth?.sessionId ?? authSession.sessionId;
4359
4365
  const userMessage2 = getTurnUserMessage(conversation, resolvedSessionId);
@@ -4390,7 +4396,7 @@ async function resumeAuthorizedMcpTurn(args) {
4390
4396
  conversation: lockedConversation,
4391
4397
  kind: "mcp",
4392
4398
  provider,
4393
- requesterId: authSession.userId
4399
+ actorId: authSession.userId
4394
4400
  });
4395
4401
  const lockedSessionId = lockedPendingAuth?.sessionId ?? authSession.sessionId;
4396
4402
  if (lockedSessionId !== resolvedSessionId) {
@@ -4435,10 +4441,10 @@ async function resumeAuthorizedMcpTurn(args) {
4435
4441
  const lockedChannelConfiguration = getChannelConfigurationServiceById(
4436
4442
  authSession.channelId
4437
4443
  );
4438
- let requester;
4444
+ let actor;
4439
4445
  try {
4440
- requester = createSlackResumeRequester({
4441
- requester: lockedSessionRecord.requester,
4446
+ actor = createSlackResumeActor({
4447
+ actor: isUserActor(lockedSessionRecord.actor) ? lockedSessionRecord.actor : void 0,
4442
4448
  teamId: destination.teamId,
4443
4449
  userId: authSession.userId
4444
4450
  });
@@ -4447,7 +4453,7 @@ async function resumeAuthorizedMcpTurn(args) {
4447
4453
  conversationId: authSession.conversationId,
4448
4454
  expectedVersion: lockedSessionRecord.version,
4449
4455
  sessionId: lockedSessionId,
4450
- errorMessage: "Stored Slack requester identity did not match OAuth requester"
4456
+ errorMessage: "Stored Slack actor identity did not match OAuth actor"
4451
4457
  });
4452
4458
  return false;
4453
4459
  }
@@ -4464,7 +4470,7 @@ async function resumeAuthorizedMcpTurn(args) {
4464
4470
  conversationId: authSession.conversationId,
4465
4471
  kind: "mcp",
4466
4472
  provider,
4467
- requesterId: authSession.userId,
4473
+ actorId: authSession.userId,
4468
4474
  authorizationId: mcpAuthorizationId({
4469
4475
  provider,
4470
4476
  sessionId: lockedSessionId
@@ -4483,9 +4489,9 @@ async function resumeAuthorizedMcpTurn(args) {
4483
4489
  },
4484
4490
  routing: {
4485
4491
  credentialContext: {
4486
- actor: { type: "user", userId: requester.userId }
4492
+ actor: { type: "user", userId: actor.userId }
4487
4493
  },
4488
- requester,
4494
+ actor,
4489
4495
  destination,
4490
4496
  source: lockedSessionRecord.source,
4491
4497
  correlation: {
@@ -4493,7 +4499,7 @@ async function resumeAuthorizedMcpTurn(args) {
4493
4499
  turnId: lockedSessionId,
4494
4500
  channelId: authSession.channelId,
4495
4501
  threadTs: authSession.threadTs,
4496
- requesterId: requester.userId
4502
+ actorId: actor.userId
4497
4503
  },
4498
4504
  toolChannelId: authSession.toolChannelId ?? lockedArtifacts.assistantContextChannelId ?? authSession.channelId
4499
4505
  },
@@ -4864,7 +4870,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
4864
4870
  conversation,
4865
4871
  kind: "plugin",
4866
4872
  provider: stored.provider,
4867
- requesterId: stored.userId,
4873
+ actorId: stored.userId,
4868
4874
  ...stored.scope ? { scope: stored.scope } : {}
4869
4875
  });
4870
4876
  const resolvedSessionId = pendingAuth?.sessionId ?? stored.resumeSessionId;
@@ -4920,7 +4926,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
4920
4926
  conversation: lockedConversation,
4921
4927
  kind: "plugin",
4922
4928
  provider: stored.provider,
4923
- requesterId: stored.userId,
4929
+ actorId: stored.userId,
4924
4930
  ...stored.scope ? { scope: stored.scope } : {}
4925
4931
  });
4926
4932
  const lockedSessionId = lockedPendingAuth?.sessionId ?? stored.resumeSessionId;
@@ -4966,10 +4972,10 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
4966
4972
  const lockedChannelConfiguration = getChannelConfigurationServiceById(
4967
4973
  stored.channelId
4968
4974
  );
4969
- let requester;
4975
+ let actor;
4970
4976
  try {
4971
- requester = createSlackResumeRequester({
4972
- requester: lockedSessionRecord.requester,
4977
+ actor = createSlackResumeActor({
4978
+ actor: isUserActor(lockedSessionRecord.actor) ? lockedSessionRecord.actor : void 0,
4973
4979
  teamId: destination.teamId,
4974
4980
  userId: lockedUserMessage.author.userId
4975
4981
  });
@@ -4978,7 +4984,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
4978
4984
  conversationId: stored.resumeConversationId,
4979
4985
  expectedVersion: lockedSessionRecord.version,
4980
4986
  sessionId: lockedSessionId,
4981
- errorMessage: "Stored Slack requester identity did not match OAuth requester"
4987
+ errorMessage: "Stored Slack actor identity did not match OAuth actor"
4982
4988
  });
4983
4989
  return false;
4984
4990
  }
@@ -4995,7 +5001,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
4995
5001
  conversationId: stored.resumeConversationId,
4996
5002
  kind: "plugin",
4997
5003
  provider: stored.provider,
4998
- requesterId: stored.userId,
5004
+ actorId: stored.userId,
4999
5005
  authorizationId: pluginAuthorizationId({
5000
5006
  provider: stored.provider,
5001
5007
  sessionId: lockedSessionId
@@ -5016,10 +5022,10 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
5016
5022
  credentialContext: {
5017
5023
  actor: {
5018
5024
  type: "user",
5019
- userId: requester.userId
5025
+ userId: actor.userId
5020
5026
  }
5021
5027
  },
5022
- requester,
5028
+ actor,
5023
5029
  destination,
5024
5030
  source: lockedSessionRecord.source,
5025
5031
  correlation: {
@@ -5027,7 +5033,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
5027
5033
  turnId: lockedSessionId,
5028
5034
  channelId: stored.channelId,
5029
5035
  threadTs: stored.threadTs,
5030
- requesterId: requester.userId
5036
+ actorId: actor.userId
5031
5037
  },
5032
5038
  toolChannelId: lockedArtifacts.assistantContextChannelId ?? stored.channelId
5033
5039
  },
@@ -5120,10 +5126,7 @@ async function resumePendingOAuthMessage(stored, options) {
5120
5126
  stored.destination,
5121
5127
  "OAuth pending message resume"
5122
5128
  );
5123
- const requester = await lookupSlackRequester(
5124
- destination.teamId,
5125
- stored.userId
5126
- );
5129
+ const actor = await lookupSlackActor(destination.teamId, stored.userId);
5127
5130
  const messageTs = getTurnUserSlackMessageTs(latestUserMessage);
5128
5131
  await resumeAuthorizedRequest({
5129
5132
  messageText: stored.pendingMessage,
@@ -5141,14 +5144,14 @@ async function resumePendingOAuthMessage(stored, options) {
5141
5144
  credentialContext: {
5142
5145
  actor: { type: "user", userId: stored.userId }
5143
5146
  },
5144
- requester,
5147
+ actor,
5145
5148
  destination: stored.destination,
5146
5149
  source,
5147
5150
  correlation: {
5148
5151
  conversationId: threadId,
5149
5152
  channelId: stored.channelId,
5150
5153
  threadTs: stored.threadTs,
5151
- requesterId: stored.userId
5154
+ actorId: stored.userId
5152
5155
  }
5153
5156
  },
5154
5157
  policy: {
@@ -5840,17 +5843,17 @@ function isExternalSlackUser(raw) {
5840
5843
  async function postEphemeral(event, text) {
5841
5844
  await event.channel.postEphemeral(event.user, text, { fallbackToDM: false });
5842
5845
  }
5843
- function requireRequesterId(event) {
5846
+ function requireActorId(event) {
5844
5847
  const userId = parseActorUserId(event.user.userId);
5845
5848
  if (!userId) {
5846
- throw new Error("Slack slash command requires a requester user id");
5849
+ throw new Error("Slack slash command requires a actor user id");
5847
5850
  }
5848
5851
  return userId;
5849
5852
  }
5850
5853
  function getCommandName() {
5851
5854
  return getChatConfig().slack.slashCommand;
5852
5855
  }
5853
- async function handleLink(event, requesterId, provider) {
5856
+ async function handleLink(event, actorId, provider) {
5854
5857
  if (!pluginCatalogRuntime.isProvider(provider)) {
5855
5858
  await postEphemeral(event, `Unknown provider: \`${provider}\``);
5856
5859
  return;
@@ -5864,7 +5867,7 @@ async function handleLink(event, requesterId, provider) {
5864
5867
  }
5865
5868
  const raw = event.raw;
5866
5869
  const result = await startOAuthFlow(provider, {
5867
- requesterId,
5870
+ actorId,
5868
5871
  channelId: raw.channel_id
5869
5872
  });
5870
5873
  if (!result.ok) {
@@ -5883,7 +5886,7 @@ async function handleLink(event, requesterId, provider) {
5883
5886
  );
5884
5887
  }
5885
5888
  }
5886
- async function handleUnlink(event, requesterId, provider) {
5889
+ async function handleUnlink(event, actorId, provider) {
5887
5890
  if (!pluginCatalogRuntime.isProvider(provider)) {
5888
5891
  await postEphemeral(event, `Unknown provider: \`${provider}\``);
5889
5892
  return;
@@ -5896,10 +5899,10 @@ async function handleUnlink(event, requesterId, provider) {
5896
5899
  return;
5897
5900
  }
5898
5901
  const tokenStore = createUserTokenStore();
5899
- await tokenStore.delete(requesterId, provider);
5902
+ await tokenStore.delete(actorId, provider);
5900
5903
  logInfo(
5901
5904
  "slash_command_unlink",
5902
- { slackUserId: requesterId },
5905
+ { slackUserId: actorId },
5903
5906
  { "app.credential.provider": provider },
5904
5907
  `Unlinked ${formatProviderLabel(provider)} account via ${getCommandName()} slash command`
5905
5908
  );
@@ -5925,11 +5928,11 @@ async function handleSlashCommand(event) {
5925
5928
  return;
5926
5929
  }
5927
5930
  const normalized = provider.toLowerCase();
5928
- const requesterId = requireRequesterId(event);
5931
+ const actorId = requireActorId(event);
5929
5932
  if (subcommand === "link") {
5930
- await handleLink(event, requesterId, normalized);
5933
+ await handleLink(event, actorId, normalized);
5931
5934
  } else {
5932
- await handleUnlink(event, requesterId, normalized);
5935
+ await handleUnlink(event, actorId, normalized);
5933
5936
  }
5934
5937
  }
5935
5938
 
@@ -6206,7 +6209,7 @@ async function handleSlashCommandForm(args) {
6206
6209
  "Slack slash command payload"
6207
6210
  );
6208
6211
  const teamId = args.params.get("team_id") ?? void 0;
6209
- const userIdentity = createRequester(
6212
+ const userIdentity = createActor(
6210
6213
  {
6211
6214
  platform: "slack",
6212
6215
  teamId,
@@ -7428,7 +7431,7 @@ async function decideSubscribedThreadReply(args) {
7428
7431
  modelId: args.modelId,
7429
7432
  threadId: args.input.context.threadId ?? "",
7430
7433
  channelId: args.input.context.channelId ?? "",
7431
- requesterId: args.input.context.requesterId ?? "",
7434
+ actorId: args.input.context.actorId ?? "",
7432
7435
  runId: args.input.context.runId ?? ""
7433
7436
  }
7434
7437
  });
@@ -7521,7 +7524,7 @@ function getQueuedMessages(context, options) {
7521
7524
  stripLeadingSlackMentionToken: options.explicitMention || Boolean(message.isMention)
7522
7525
  });
7523
7526
  return {
7524
- explicitMention: options.explicitMention || Boolean(message.isMention),
7527
+ explicitMention: Boolean(message.isMention),
7525
7528
  message,
7526
7529
  rawText: appendSlackLegacyAttachmentText(message.text, message.raw),
7527
7530
  userText: appendSlackLegacyAttachmentText(stripped, message.raw)
@@ -7562,15 +7565,15 @@ function buildLogContext(deps, args) {
7562
7565
  return {
7563
7566
  conversationId: args.threadId ?? args.runId,
7564
7567
  slackThreadId: args.threadId,
7565
- slackUserId: args.requesterId,
7566
- slackUserName: args.requesterUserName,
7568
+ slackUserId: args.actorId,
7569
+ slackUserName: args.actorUserName,
7567
7570
  slackChannelId: args.channelId,
7568
7571
  runId: args.runId,
7569
7572
  assistantUserName: deps.assistantUserName,
7570
7573
  modelId: deps.modelId
7571
7574
  };
7572
7575
  }
7573
- function requesterUserName(message) {
7576
+ function actorUserName(message) {
7574
7577
  return getMessageActorIdentity(message)?.userName;
7575
7578
  }
7576
7579
  function isResourceEventNotificationMessage2(message) {
@@ -7647,7 +7650,7 @@ function createSlackTurnRuntime(deps) {
7647
7650
  const { message } = candidate;
7648
7651
  const context = {
7649
7652
  threadId: deps.getThreadId(thread, message),
7650
- requesterId: message.author.userId,
7653
+ actorId: message.author.userId,
7651
7654
  channelId: deps.getChannelId(thread, message),
7652
7655
  runId: deps.getRunId(thread, message)
7653
7656
  };
@@ -7680,8 +7683,8 @@ function createSlackTurnRuntime(deps) {
7680
7683
  "subscribed_message_reply_skipped",
7681
7684
  logContext({
7682
7685
  threadId: args.context.threadId,
7683
- requesterId: args.context.requesterId,
7684
- requesterUserName: requesterUserName(args.message),
7686
+ actorId: args.context.actorId,
7687
+ actorUserName: actorUserName(args.message),
7685
7688
  channelId: args.context.channelId,
7686
7689
  runId: args.context.runId
7687
7690
  }),
@@ -7805,8 +7808,8 @@ function createSlackTurnRuntime(deps) {
7805
7808
  pending: skippedSteeringMessages,
7806
7809
  context: logContext({
7807
7810
  threadId: deps.getThreadId(thread, message),
7808
- requesterId: message.author.userId,
7809
- requesterUserName: requesterUserName(message),
7811
+ actorId: message.author.userId,
7812
+ actorUserName: actorUserName(message),
7810
7813
  channelId: deps.getChannelId(thread, message),
7811
7814
  runId: deps.getRunId(thread, message)
7812
7815
  })
@@ -7819,8 +7822,8 @@ function createSlackTurnRuntime(deps) {
7819
7822
  const context = logContext({
7820
7823
  threadId,
7821
7824
  channelId,
7822
- requesterId: message.author.userId,
7823
- requesterUserName: requesterUserName(message),
7825
+ actorId: message.author.userId,
7826
+ actorUserName: actorUserName(message),
7824
7827
  runId
7825
7828
  });
7826
7829
  processingReaction = await processingReactions.start(context, message);
@@ -7892,8 +7895,8 @@ function createSlackTurnRuntime(deps) {
7892
7895
  }
7893
7896
  const errorContext = logContext({
7894
7897
  threadId: deps.getThreadId(thread, message),
7895
- requesterId: message.author.userId,
7896
- requesterUserName: requesterUserName(message),
7898
+ actorId: message.author.userId,
7899
+ actorUserName: actorUserName(message),
7897
7900
  channelId: deps.getChannelId(thread, message),
7898
7901
  runId: deps.getRunId(thread, message)
7899
7902
  });
@@ -7905,8 +7908,8 @@ function createSlackTurnRuntime(deps) {
7905
7908
  "mention_handler_read_only_channel",
7906
7909
  logContext({
7907
7910
  threadId: deps.getThreadId(thread, message),
7908
- requesterId: message.author.userId,
7909
- requesterUserName: requesterUserName(message),
7911
+ actorId: message.author.userId,
7912
+ actorUserName: actorUserName(message),
7910
7913
  channelId: deps.getChannelId(thread, message),
7911
7914
  runId: deps.getRunId(thread, message)
7912
7915
  }),
@@ -7947,8 +7950,8 @@ function createSlackTurnRuntime(deps) {
7947
7950
  pending: skippedSteeringMessages,
7948
7951
  context: logContext({
7949
7952
  threadId: deps.getThreadId(thread, message),
7950
- requesterId: message.author.userId,
7951
- requesterUserName: requesterUserName(message),
7953
+ actorId: message.author.userId,
7954
+ actorUserName: actorUserName(message),
7952
7955
  channelId: deps.getChannelId(thread, message),
7953
7956
  runId: deps.getRunId(thread, message)
7954
7957
  })
@@ -7970,8 +7973,8 @@ function createSlackTurnRuntime(deps) {
7970
7973
  pending: skippedSteeringMessages,
7971
7974
  context: logContext({
7972
7975
  threadId: deps.getThreadId(thread, message),
7973
- requesterId: message.author.userId,
7974
- requesterUserName: requesterUserName(message),
7976
+ actorId: message.author.userId,
7977
+ actorUserName: actorUserName(message),
7975
7978
  channelId: deps.getChannelId(thread, message),
7976
7979
  runId: deps.getRunId(thread, message)
7977
7980
  })
@@ -7982,11 +7985,11 @@ function createSlackTurnRuntime(deps) {
7982
7985
  const channelId = deps.getChannelId(thread, message);
7983
7986
  const runId = deps.getRunId(thread, message);
7984
7987
  const isResourceEventNotification = isResourceEventNotificationMessage2(message);
7985
- const requesterId = isResourceEventNotification ? void 0 : message.author.userId;
7988
+ const actorId = isResourceEventNotification ? void 0 : message.author.userId;
7986
7989
  const turnContext = logContext({
7987
7990
  threadId,
7988
- requesterId,
7989
- requesterUserName: requesterUserName(message),
7991
+ actorId,
7992
+ actorUserName: actorUserName(message),
7990
7993
  channelId,
7991
7994
  runId
7992
7995
  });
@@ -8006,7 +8009,7 @@ function createSlackTurnRuntime(deps) {
8006
8009
  };
8007
8010
  const threadContext = {
8008
8011
  threadId,
8009
- requesterId,
8012
+ actorId,
8010
8013
  channelId,
8011
8014
  runId
8012
8015
  };
@@ -8152,8 +8155,8 @@ function createSlackTurnRuntime(deps) {
8152
8155
  }
8153
8156
  const errorContext = logContext({
8154
8157
  threadId: deps.getThreadId(thread, message),
8155
- requesterId: message.author.userId,
8156
- requesterUserName: requesterUserName(message),
8158
+ actorId: message.author.userId,
8159
+ actorUserName: actorUserName(message),
8157
8160
  channelId: deps.getChannelId(thread, message),
8158
8161
  runId: deps.getRunId(thread, message)
8159
8162
  });
@@ -8165,8 +8168,8 @@ function createSlackTurnRuntime(deps) {
8165
8168
  "subscribed_message_handler_read_only_channel",
8166
8169
  logContext({
8167
8170
  threadId: deps.getThreadId(thread, message),
8168
- requesterId: message.author.userId,
8169
- requesterUserName: requesterUserName(message),
8171
+ actorId: message.author.userId,
8172
+ actorUserName: actorUserName(message),
8170
8173
  channelId: deps.getChannelId(thread, message),
8171
8174
  runId: deps.getRunId(thread, message)
8172
8175
  }),
@@ -8207,8 +8210,8 @@ function createSlackTurnRuntime(deps) {
8207
8210
  pending: skippedSteeringMessages,
8208
8211
  context: logContext({
8209
8212
  threadId: deps.getThreadId(thread, message),
8210
- requesterId: message.author.userId,
8211
- requesterUserName: requesterUserName(message),
8213
+ actorId: message.author.userId,
8214
+ actorUserName: actorUserName(message),
8212
8215
  channelId: deps.getChannelId(thread, message),
8213
8216
  runId: deps.getRunId(thread, message)
8214
8217
  })
@@ -8327,12 +8330,13 @@ function userMessage(text) {
8327
8330
  timestamp: Date.now()
8328
8331
  };
8329
8332
  }
8330
- function selectRetainedUserMessages(messages, maxTokens = RETAINED_USER_MESSAGE_TOKENS) {
8331
- const stripped = stripRuntimeTurnContext(messages);
8333
+ function selectRetainedUserMessageEntries(messages, maxTokens = RETAINED_USER_MESSAGE_TOKENS) {
8332
8334
  const selected = [];
8333
8335
  let remaining = maxTokens;
8334
- for (const message of [...stripped].reverse()) {
8335
- if (message.role !== "user" || remaining <= 0) {
8336
+ for (let sourceIndex = messages.length - 1; sourceIndex >= 0; sourceIndex -= 1) {
8337
+ const stripped = stripRuntimeTurnContext([messages[sourceIndex]]);
8338
+ const message = stripped[0];
8339
+ if (!message || message.role !== "user" || remaining <= 0) {
8336
8340
  continue;
8337
8341
  }
8338
8342
  const text = sanitizeText(messageText(message));
@@ -8341,17 +8345,17 @@ function selectRetainedUserMessages(messages, maxTokens = RETAINED_USER_MESSAGE_
8341
8345
  }
8342
8346
  const tokens = estimateTextTokens(text);
8343
8347
  if (tokens <= remaining) {
8344
- selected.push(text);
8348
+ selected.push({ message: userMessage(text), sourceIndex });
8345
8349
  remaining -= tokens;
8346
8350
  continue;
8347
8351
  }
8348
8352
  const truncated = truncateToTokenBudget(text, remaining);
8349
8353
  if (truncated) {
8350
- selected.push(truncated);
8354
+ selected.push({ message: userMessage(truncated), sourceIndex });
8351
8355
  }
8352
8356
  break;
8353
8357
  }
8354
- return selected.reverse().map(userMessage);
8358
+ return selected.reverse();
8355
8359
  }
8356
8360
  function renderMessageForSummary(message) {
8357
8361
  const role = message.role;
@@ -8428,7 +8432,7 @@ async function summarizeContext(args, deps) {
8428
8432
  modelId: botConfig.fastModelId,
8429
8433
  threadId: args.metadata?.threadId ?? "",
8430
8434
  channelId: args.metadata?.channelId ?? "",
8431
- requesterId: args.metadata?.requesterId ?? "",
8435
+ actorId: args.metadata?.actorId ?? "",
8432
8436
  runId: args.metadata?.runId ?? ""
8433
8437
  }
8434
8438
  });
@@ -8447,11 +8451,12 @@ function estimateHistoryTokens(messages) {
8447
8451
  );
8448
8452
  return Math.max(usageEstimate, structuralEstimate);
8449
8453
  }
8450
- function buildReplacementHistory(args) {
8454
+ function buildReplacementProvenance(args) {
8451
8455
  return [
8452
- ...selectRetainedUserMessages(args.messages),
8453
- userMessage(`${COMPACTION_SUMMARY_PREFIX}
8454
- ${args.summary}`)
8456
+ ...args.retained.map(
8457
+ (entry) => args.sourceProvenance[entry.sourceIndex] ?? contextProvenance
8458
+ ),
8459
+ contextProvenance
8455
8460
  ];
8456
8461
  }
8457
8462
  function loadCompactionSource(messages) {
@@ -8488,7 +8493,7 @@ async function maybeCompactWithDeps(args, deps) {
8488
8493
  "context_compaction_summary_failed",
8489
8494
  {
8490
8495
  slackThreadId: args.metadata?.threadId,
8491
- slackUserId: args.metadata?.requesterId,
8496
+ slackUserId: args.metadata?.actorId,
8492
8497
  slackChannelId: args.metadata?.channelId,
8493
8498
  runId: args.metadata?.runId,
8494
8499
  assistantUserName: botConfig.userName,
@@ -8507,13 +8512,24 @@ async function maybeCompactWithDeps(args, deps) {
8507
8512
  });
8508
8513
  }
8509
8514
  async function writeCompactedThreadContext(args, sourceMessages, summary, context) {
8510
- const replacement = buildReplacementHistory({
8511
- messages: trimTrailingAssistantMessages(sourceMessages),
8512
- summary
8515
+ const sourceProjection = await loadProjectionWithProvenance({
8516
+ conversationId: args.conversationId
8513
8517
  });
8518
+ const retained = selectRetainedUserMessageEntries(
8519
+ trimTrailingAssistantMessages(sourceProjection.messages)
8520
+ );
8521
+ const replacement = [
8522
+ ...retained.map((entry) => entry.message),
8523
+ userMessage(`${COMPACTION_SUMMARY_PREFIX}
8524
+ ${summary}`)
8525
+ ];
8514
8526
  await commitMessages({
8515
8527
  conversationId: args.conversationId,
8516
8528
  messages: replacement,
8529
+ provenance: buildReplacementProvenance({
8530
+ retained,
8531
+ sourceProvenance: sourceProjection.provenance
8532
+ }),
8517
8533
  ttlMs: THREAD_STATE_TTL_MS3
8518
8534
  });
8519
8535
  updateConversationStats(args.conversation);
@@ -8548,7 +8564,7 @@ function createSubscribedReplyPolicy(deps) {
8548
8564
  "subscribed_message_classifier_failed",
8549
8565
  {
8550
8566
  slackThreadId: input.context.threadId,
8551
- slackUserId: input.context.requesterId,
8567
+ slackUserId: input.context.actorId,
8552
8568
  slackChannelId: input.context.channelId,
8553
8569
  runId: input.context.runId,
8554
8570
  assistantUserName: botConfig.userName,
@@ -8729,7 +8745,7 @@ async function resolveUserAttachmentsWithDeps(attachments, context, deps) {
8729
8745
  metadata: {
8730
8746
  threadId: context.threadId ?? "",
8731
8747
  channelId: context.channelId ?? "",
8732
- requesterId: context.requesterId ?? "",
8748
+ actorId: context.actorId ?? "",
8733
8749
  runId: context.runId ?? "",
8734
8750
  filename: attachment.name ?? ""
8735
8751
  }
@@ -8759,7 +8775,7 @@ async function resolveUserAttachmentsWithDeps(attachments, context, deps) {
8759
8775
  "attachment_skipped_size_limit",
8760
8776
  {
8761
8777
  slackThreadId: context.threadId,
8762
- slackUserId: context.requesterId,
8778
+ slackUserId: context.actorId,
8763
8779
  slackChannelId: context.channelId,
8764
8780
  runId: context.runId,
8765
8781
  assistantUserName: botConfig.userName,
@@ -8784,7 +8800,7 @@ async function resolveUserAttachmentsWithDeps(attachments, context, deps) {
8784
8800
  "image_attachment_processing_failed",
8785
8801
  {
8786
8802
  slackThreadId: context.threadId,
8787
- slackUserId: context.requesterId,
8803
+ slackUserId: context.actorId,
8788
8804
  slackChannelId: context.channelId,
8789
8805
  runId: context.runId,
8790
8806
  assistantUserName: botConfig.userName,
@@ -8803,7 +8819,7 @@ async function resolveUserAttachmentsWithDeps(attachments, context, deps) {
8803
8819
  "attachment_resolution_failed",
8804
8820
  {
8805
8821
  slackThreadId: context.threadId,
8806
- slackUserId: context.requesterId,
8822
+ slackUserId: context.actorId,
8807
8823
  slackChannelId: context.channelId,
8808
8824
  runId: context.runId,
8809
8825
  assistantUserName: botConfig.userName,
@@ -8839,7 +8855,7 @@ async function summarizeConversationImage(args, deps) {
8839
8855
  metadata: {
8840
8856
  threadId: args.context.threadId ?? "",
8841
8857
  channelId: args.context.channelId ?? "",
8842
- requesterId: args.context.requesterId ?? "",
8858
+ actorId: args.context.actorId ?? "",
8843
8859
  runId: args.context.runId ?? "",
8844
8860
  fileId: args.fileId
8845
8861
  }
@@ -8853,7 +8869,7 @@ async function summarizeConversationImage(args, deps) {
8853
8869
  "conversation_image_vision_failed",
8854
8870
  {
8855
8871
  slackThreadId: args.context.threadId,
8856
- slackUserId: args.context.requesterId,
8872
+ slackUserId: args.context.actorId,
8857
8873
  slackChannelId: args.context.channelId,
8858
8874
  runId: args.context.runId,
8859
8875
  assistantUserName: botConfig.userName,
@@ -8909,7 +8925,7 @@ async function hydrateConversationVisionContextWithDeps(conversation, context, d
8909
8925
  "conversation_image_replies_fetch_failed",
8910
8926
  {
8911
8927
  slackThreadId: context.threadId,
8912
- slackUserId: context.requesterId,
8928
+ slackUserId: context.actorId,
8913
8929
  slackChannelId: context.channelId,
8914
8930
  runId: context.runId,
8915
8931
  assistantUserName: botConfig.userName,
@@ -8976,7 +8992,7 @@ async function hydrateConversationVisionContextWithDeps(conversation, context, d
8976
8992
  "conversation_image_skipped_size_limit",
8977
8993
  {
8978
8994
  slackThreadId: context.threadId,
8979
- slackUserId: context.requesterId,
8995
+ slackUserId: context.actorId,
8980
8996
  slackChannelId: context.channelId,
8981
8997
  runId: context.runId,
8982
8998
  assistantUserName: botConfig.userName,
@@ -9003,7 +9019,7 @@ async function hydrateConversationVisionContextWithDeps(conversation, context, d
9003
9019
  "conversation_image_download_failed",
9004
9020
  {
9005
9021
  slackThreadId: context.threadId,
9006
- slackUserId: context.requesterId,
9022
+ slackUserId: context.actorId,
9007
9023
  slackChannelId: context.channelId,
9008
9024
  runId: context.runId,
9009
9025
  assistantUserName: botConfig.userName,
@@ -9023,7 +9039,7 @@ async function hydrateConversationVisionContextWithDeps(conversation, context, d
9023
9039
  "conversation_image_skipped_size_limit",
9024
9040
  {
9025
9041
  slackThreadId: context.threadId,
9026
- slackUserId: context.requesterId,
9042
+ slackUserId: context.actorId,
9027
9043
  slackChannelId: context.channelId,
9028
9044
  runId: context.runId,
9029
9045
  assistantUserName: botConfig.userName,
@@ -9066,7 +9082,7 @@ async function hydrateConversationVisionContextWithDeps(conversation, context, d
9066
9082
  "conversation_image_context_hydrated",
9067
9083
  {
9068
9084
  slackThreadId: context.threadId,
9069
- slackUserId: context.requesterId,
9085
+ slackUserId: context.actorId,
9070
9086
  slackChannelId: context.channelId,
9071
9087
  runId: context.runId,
9072
9088
  assistantUserName: botConfig.userName,
@@ -9172,7 +9188,7 @@ function maybeUpdateAssistantTitle(args) {
9172
9188
  "thread_title_generation_failed",
9173
9189
  {
9174
9190
  slackThreadId: args.threadId,
9175
- slackUserId: args.requesterId,
9191
+ slackUserId: args.actorId,
9176
9192
  slackChannelId: args.channelId,
9177
9193
  runId: args.runId,
9178
9194
  assistantUserName: args.assistantUserName,
@@ -9206,7 +9222,7 @@ function maybeUpdateAssistantTitle(args) {
9206
9222
  "thread_title_generation_permission_denied",
9207
9223
  {
9208
9224
  slackThreadId: args.threadId,
9209
- slackUserId: args.requesterId,
9225
+ slackUserId: args.actorId,
9210
9226
  slackChannelId: args.channelId,
9211
9227
  runId: args.runId,
9212
9228
  assistantUserName: args.assistantUserName,
@@ -9220,7 +9236,7 @@ function maybeUpdateAssistantTitle(args) {
9220
9236
  "thread_title_slack_update_failed",
9221
9237
  {
9222
9238
  slackThreadId: args.threadId,
9223
- slackUserId: args.requesterId,
9239
+ slackUserId: args.actorId,
9224
9240
  slackChannelId: args.channelId,
9225
9241
  runId: args.runId,
9226
9242
  assistantUserName: args.assistantUserName,
@@ -9253,7 +9269,7 @@ async function maybeApplyProviderDefaultConfigRequest(args) {
9253
9269
  await args.channelConfiguration.set({
9254
9270
  key: "github.repo",
9255
9271
  value: repo,
9256
- updatedBy: args.requesterId,
9272
+ updatedBy: args.actorId,
9257
9273
  source: "provider-default-config"
9258
9274
  });
9259
9275
  return {
@@ -9273,8 +9289,8 @@ function collectCanvasUrls(artifacts) {
9273
9289
  ].filter((url) => typeof url === "string" && url !== "")
9274
9290
  );
9275
9291
  }
9276
- function turnRequester(requester) {
9277
- return toStoredSlackRequester(requester);
9292
+ function turnActor(actor) {
9293
+ return toStoredSlackActor(actor);
9278
9294
  }
9279
9295
  function parkedInputKey(message) {
9280
9296
  if (message.role !== "user") {
@@ -9284,12 +9300,77 @@ function parkedInputKey(message) {
9284
9300
  const text = first && typeof first === "object" && "text" in first ? String(first.text ?? "") : "";
9285
9301
  return `${message.timestamp}:${text}`;
9286
9302
  }
9303
+ function renderRecentThreadMessages(conversationContext, messages) {
9304
+ const passiveMessages = messages.filter((queued) => {
9305
+ if (queued.explicitMention) {
9306
+ return false;
9307
+ }
9308
+ const slackTs = queuedInstructionActor(queued)?.slackTs;
9309
+ return !slackTs || !conversationContext?.includes(`slack_ts="${slackTs}"`);
9310
+ });
9311
+ if (passiveMessages.length === 0) {
9312
+ return void 0;
9313
+ }
9314
+ const lines = ["<recent-thread-messages>"];
9315
+ for (const queued of passiveMessages) {
9316
+ const actor = queuedInstructionActor(queued);
9317
+ const attrs = [
9318
+ actor?.authorId ? `author_id="${escapeXml(actor.authorId)}"` : void 0,
9319
+ actor?.authorName ? `author_name="${escapeXml(actor.authorName)}"` : void 0,
9320
+ actor?.slackTs ? `slack_ts="${escapeXml(actor.slackTs)}"` : void 0
9321
+ ].filter((attr) => Boolean(attr)).join(" ");
9322
+ lines.push(
9323
+ attrs ? ` <message ${attrs}>` : " <message>",
9324
+ escapeXml(queued.userText),
9325
+ " </message>"
9326
+ );
9327
+ }
9328
+ lines.push("</recent-thread-messages>");
9329
+ return lines.join("\n");
9330
+ }
9331
+ function appendRecentThreadMessagesToContext(conversationContext, messages, options) {
9332
+ const recentThreadMessages = renderRecentThreadMessages(
9333
+ conversationContext,
9334
+ messages
9335
+ );
9336
+ const contextParts = [
9337
+ options?.includeConversationContext === false ? void 0 : conversationContext?.trim(),
9338
+ recentThreadMessages
9339
+ ].filter((part) => Boolean(part));
9340
+ return contextParts.length > 0 ? contextParts.join("\n\n") : void 0;
9341
+ }
9342
+ function queuedInstructionActor(queued) {
9343
+ const actor = getMessageActorIdentity(queued.message);
9344
+ const authorId = actor?.userId ?? parseActorUserId(queued.message.author.userId);
9345
+ const authorName = actor?.fullName ?? actor?.userName;
9346
+ const slackTs = getSlackMessageTs(queued.message);
9347
+ return {
9348
+ ...authorId ? { authorId } : {},
9349
+ ...authorName ? { authorName } : {},
9350
+ ...slackTs ? { slackTs } : {}
9351
+ };
9352
+ }
9353
+ function queuedInstructionProvenance(queued, teamId) {
9354
+ if (isResourceEventMessage(queued.message)) {
9355
+ return contextProvenance;
9356
+ }
9357
+ const identity = getMessageActorIdentity(queued.message);
9358
+ const author = identity && "platform" in identity ? identity : createActor(
9359
+ { userId: parseActorUserId(queued.message.author.userId) },
9360
+ {
9361
+ platform: "slack",
9362
+ teamId,
9363
+ userId: parseActorUserId(queued.message.author.userId)
9364
+ }
9365
+ );
9366
+ return instructionProvenanceFor(author);
9367
+ }
9287
9368
  function isResourceEventMessage(message) {
9288
9369
  const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
9289
9370
  return raw?.event_type === "resource_event";
9290
9371
  }
9291
9372
  function resourceEventCredentialContext(message) {
9292
- return isResourceEventMessage(message) ? { actor: { type: "system", id: "resource-event" } } : void 0;
9373
+ return isResourceEventMessage(message) ? { actor: { platform: "system", name: "resource-event" } } : void 0;
9293
9374
  }
9294
9375
  async function resolveChannelName(thread) {
9295
9376
  const existingName = thread.channel.name?.trim();
@@ -9407,10 +9488,6 @@ function createReplyToThread(deps) {
9407
9488
  message.raw
9408
9489
  )
9409
9490
  };
9410
- const effectiveUserText = combineTurnText(
9411
- options.queuedMessages ?? [],
9412
- currentText
9413
- ).userText;
9414
9491
  await Promise.all(
9415
9492
  (options.queuedMessages ?? []).filter((queued) => !isResourceEventMessage(queued.message)).map(
9416
9493
  (queued) => ensureSlackMessageActorIdentity(
@@ -9420,16 +9497,18 @@ function createReplyToThread(deps) {
9420
9497
  )
9421
9498
  )
9422
9499
  );
9500
+ const effectiveUserText = currentText.userText;
9423
9501
  const credentialContext = resourceEventCredentialContext(message) ?? {
9424
9502
  actor: { type: "user", userId: message.author.userId }
9425
9503
  };
9426
- const requester = credentialContext.actor.type === "user" ? await ensureSlackMessageActorIdentity(
9504
+ const actor = "type" in credentialContext.actor ? await ensureSlackMessageActorIdentity(
9427
9505
  message,
9428
9506
  teamId,
9429
9507
  deps.services.lookupSlackUser
9430
9508
  ) : void 0;
9431
- const storedRequester = requester ? turnRequester(requester) : void 0;
9432
- const slackRequesterId = requester?.userId;
9509
+ const executionActor = "type" in credentialContext.actor ? actor : credentialContext.actor;
9510
+ const storedActor = actor ? turnActor(actor) : void 0;
9511
+ const slackActorId = actor?.userId;
9433
9512
  const preparedState = options.preparedState ?? await deps.prepareTurnState({
9434
9513
  thread,
9435
9514
  message,
@@ -9440,7 +9519,7 @@ function createReplyToThread(deps) {
9440
9519
  queuedMessages: options.queuedMessages,
9441
9520
  context: {
9442
9521
  threadId,
9443
- requesterId: slackRequesterId,
9522
+ actorId: slackActorId,
9444
9523
  channelId,
9445
9524
  runId
9446
9525
  }
@@ -9465,11 +9544,11 @@ function createReplyToThread(deps) {
9465
9544
  await options.beforeFirstResponsePost?.();
9466
9545
  };
9467
9546
  const postAuthPauseNotice = async (providerDisplayName) => {
9468
- if (!requester) {
9469
- throw new Error("Slack auth pause notice requires a requester");
9547
+ if (!actor) {
9548
+ throw new Error("Slack auth pause notice requires an actor");
9470
9549
  }
9471
9550
  const text = buildAuthPauseResponse(
9472
- requester.userId,
9551
+ actor.userId,
9473
9552
  providerDisplayName
9474
9553
  );
9475
9554
  const footer = buildSlackReplyFooter({ conversationId });
@@ -9511,6 +9590,8 @@ function createReplyToThread(deps) {
9511
9590
  queuedMessages.map(async (queued) => {
9512
9591
  const attachments = queued.message.attachments;
9513
9592
  return {
9593
+ actor: queuedInstructionActor(queued),
9594
+ provenance: queuedInstructionProvenance(queued, teamId),
9514
9595
  text: queued.userText,
9515
9596
  timestampMs: queued.message.metadata.dateSent.getTime(),
9516
9597
  omittedImageAttachmentCount: !isVisionEnabled() && hasPotentialImageAttachment(attachments) ? countPotentialImageAttachments(attachments) : 0,
@@ -9518,7 +9599,7 @@ function createReplyToThread(deps) {
9518
9599
  attachments,
9519
9600
  {
9520
9601
  threadId,
9521
- requesterId: isResourceEventMessage(queued.message) ? void 0 : queued.message.author.userId,
9602
+ actorId: isResourceEventMessage(queued.message) ? void 0 : queued.message.author.userId,
9522
9603
  channelId,
9523
9604
  runId,
9524
9605
  conversation: preparedState.conversation,
@@ -9529,26 +9610,8 @@ function createReplyToThread(deps) {
9529
9610
  })
9530
9611
  );
9531
9612
  };
9532
- const appendParkedTurnInput = async (parkedSessionId) => {
9533
- if (!conversationId) {
9534
- return true;
9535
- }
9536
- const parkedMessages = [
9537
- ...options.queuedMessages ?? [],
9538
- {
9539
- explicitMention: Boolean(
9540
- options.explicitMention || message.isMention
9541
- ),
9542
- message,
9543
- rawText: currentText.rawText,
9544
- userText: currentText.userText
9545
- }
9546
- ].filter(
9547
- // Redelivery of the parked turn's own message must not duplicate
9548
- // the prompt that already started the session.
9549
- (queued) => buildDeterministicTurnId(queued.message.id) !== parkedSessionId
9550
- );
9551
- if (parkedMessages.length === 0) {
9613
+ const drainParkedInputToSessionLog = async (pairs) => {
9614
+ if (!conversationId || pairs.length === 0) {
9552
9615
  return true;
9553
9616
  }
9554
9617
  const stateAdapter = getStateAdapter();
@@ -9558,13 +9621,14 @@ function createReplyToThread(deps) {
9558
9621
  return false;
9559
9622
  }
9560
9623
  try {
9561
- const piMessages = (await resolveSteeringMessages(parkedMessages)).map(buildSteeringPiMessage);
9562
- const projection = await loadProjection({ conversationId });
9624
+ const projection = await loadProjectionWithProvenance({
9625
+ conversationId
9626
+ });
9563
9627
  const appendedKeys = new Set(
9564
- projection.map(parkedInputKey).filter((key) => key !== void 0)
9628
+ projection.messages.map(parkedInputKey).filter((key) => key !== void 0)
9565
9629
  );
9566
- const missing = piMessages.filter((piMessage) => {
9567
- const key = parkedInputKey(piMessage);
9630
+ const missing = pairs.filter((pair) => {
9631
+ const key = parkedInputKey(pair.message);
9568
9632
  return key === void 0 || !appendedKeys.has(key);
9569
9633
  });
9570
9634
  if (missing.length === 0) {
@@ -9572,8 +9636,14 @@ function createReplyToThread(deps) {
9572
9636
  }
9573
9637
  await commitMessages({
9574
9638
  conversationId,
9575
- messages: [...projection, ...missing],
9576
- requester: storedRequester,
9639
+ messages: [
9640
+ ...projection.messages,
9641
+ ...missing.map((pair) => pair.message)
9642
+ ],
9643
+ provenance: [
9644
+ ...projection.provenance,
9645
+ ...missing.map((pair) => pair.provenance)
9646
+ ],
9577
9647
  ttlMs: THREAD_STATE_TTL_MS4
9578
9648
  });
9579
9649
  return true;
@@ -9581,6 +9651,34 @@ function createReplyToThread(deps) {
9581
9651
  await stateAdapter.releaseLock(lock);
9582
9652
  }
9583
9653
  };
9654
+ const appendParkedTurnInput = async (parkedSessionId) => {
9655
+ if (!conversationId) {
9656
+ return true;
9657
+ }
9658
+ const parkedMessages = [
9659
+ ...options.queuedMessages ?? [],
9660
+ {
9661
+ explicitMention: Boolean(
9662
+ options.explicitMention || message.isMention
9663
+ ),
9664
+ message,
9665
+ rawText: currentText.rawText,
9666
+ userText: currentText.userText
9667
+ }
9668
+ ].filter(
9669
+ // Redelivery of the parked turn's own message must not duplicate
9670
+ // the prompt that already started the session.
9671
+ (queued) => buildDeterministicTurnId(queued.message.id) !== parkedSessionId
9672
+ );
9673
+ if (parkedMessages.length === 0) {
9674
+ return true;
9675
+ }
9676
+ const parkedPairs = (await resolveSteeringMessages(parkedMessages)).map((steering) => ({
9677
+ message: buildSteeringPiMessage(steering),
9678
+ provenance: steering.provenance
9679
+ }));
9680
+ return drainParkedInputToSessionLog(parkedPairs);
9681
+ };
9584
9682
  if (preparedState.userMessageAlreadyReplied) {
9585
9683
  await persistThreadState(thread, {
9586
9684
  conversation: preparedState.conversation
@@ -9660,7 +9758,7 @@ function createReplyToThread(deps) {
9660
9758
  }
9661
9759
  const configReply = await maybeApplyProviderDefaultConfigRequest({
9662
9760
  channelConfiguration: preparedState.channelConfiguration,
9663
- requesterId: requester?.userId,
9761
+ actorId: actor?.userId,
9664
9762
  text: effectiveUserText
9665
9763
  });
9666
9764
  if (configReply) {
@@ -9709,7 +9807,7 @@ function createReplyToThread(deps) {
9709
9807
  startedAtMs: turnStartedAtMs,
9710
9808
  state: "running",
9711
9809
  surface: "slack",
9712
- requester,
9810
+ actor,
9713
9811
  destination,
9714
9812
  destinationVisibility,
9715
9813
  source,
@@ -9726,7 +9824,7 @@ function createReplyToThread(deps) {
9726
9824
  void initConversationContext(conversationId, {
9727
9825
  channelName,
9728
9826
  originSurface: "slack",
9729
- originRequester: storedRequester,
9827
+ originActor: storedActor,
9730
9828
  startedAtMs: turnStartedAtMs
9731
9829
  }).catch((error) => {
9732
9830
  logException(
@@ -9773,15 +9871,15 @@ function createReplyToThread(deps) {
9773
9871
  conversation: preparedState.conversation
9774
9872
  });
9775
9873
  await options.onTurnStatePersisted?.();
9776
- if (requester) {
9874
+ if (actor) {
9777
9875
  setSentryUser({
9778
- id: requester.userId,
9779
- ...requester.userName ? { username: requester.userName } : {},
9780
- ...requester.email ? { email: requester.email } : {}
9876
+ id: actor.userId,
9877
+ ...actor.userName ? { username: actor.userName } : {},
9878
+ ...actor.email ? { email: actor.email } : {}
9781
9879
  });
9782
9880
  }
9783
- if (requester?.userName) {
9784
- setTags({ slackUserName: requester.userName });
9881
+ if (actor?.userName) {
9882
+ setTags({ slackUserName: actor.userName });
9785
9883
  }
9786
9884
  const turnAttachments = collectTurnAttachments(
9787
9885
  message,
@@ -9791,7 +9889,7 @@ function createReplyToThread(deps) {
9791
9889
  turnAttachments,
9792
9890
  {
9793
9891
  threadId,
9794
- requesterId: slackRequesterId,
9892
+ actorId: slackActorId,
9795
9893
  channelId,
9796
9894
  runId,
9797
9895
  conversation: preparedState.conversation,
@@ -9847,7 +9945,7 @@ function createReplyToThread(deps) {
9847
9945
  conversationId,
9848
9946
  metadata: {
9849
9947
  threadId,
9850
- requesterId: slackRequesterId,
9948
+ actorId: slackActorId,
9851
9949
  channelId,
9852
9950
  runId
9853
9951
  },
@@ -9861,6 +9959,31 @@ function createReplyToThread(deps) {
9861
9959
  });
9862
9960
  }
9863
9961
  }
9962
+ const hasDurablePromptHistory = Boolean(piMessages?.length);
9963
+ const batchedInstructions = (await resolveSteeringMessages(
9964
+ (options.queuedMessages ?? []).filter(
9965
+ (queued) => queued.explicitMention
9966
+ )
9967
+ )).map((steering) => ({
9968
+ message: buildSteeringPiMessage(steering),
9969
+ provenance: steering.provenance
9970
+ }));
9971
+ if (!await drainParkedInputToSessionLog(batchedInstructions)) {
9972
+ shouldPersistFailureState = false;
9973
+ throw new TurnInputDeferredError();
9974
+ }
9975
+ if (batchedInstructions.length > 0) {
9976
+ const presentKeys = new Set(
9977
+ (piMessages ?? []).map(parkedInputKey).filter((key) => key !== void 0)
9978
+ );
9979
+ const newlyBatched = batchedInstructions.map((entry) => entry.message).filter((batchedMessage) => {
9980
+ const key = parkedInputKey(batchedMessage);
9981
+ return key === void 0 || !presentKeys.has(key);
9982
+ });
9983
+ if (newlyBatched.length > 0) {
9984
+ piMessages = [...piMessages ?? [], ...newlyBatched];
9985
+ }
9986
+ }
9864
9987
  status.start();
9865
9988
  const assistantTitleTask = maybeUpdateAssistantTitle({
9866
9989
  assistantThreadContext,
@@ -9871,7 +9994,7 @@ function createReplyToThread(deps) {
9871
9994
  generateThreadTitle: deps.services.generateThreadTitle,
9872
9995
  getSlackAdapter: deps.getSlackAdapter,
9873
9996
  modelId: botConfig.fastModelId,
9874
- requesterId: slackRequesterId,
9997
+ actorId: slackActorId,
9875
9998
  runId,
9876
9999
  threadId
9877
10000
  });
@@ -9924,6 +10047,12 @@ function createReplyToThread(deps) {
9924
10047
  );
9925
10048
  });
9926
10049
  const toolChannelId = preparedState.artifacts.assistantContextChannelId ?? channelId;
10050
+ const activeInstructionAuthorId = actor?.userId ?? parseActorUserId(message.author.userId);
10051
+ const activeInstructionAuthorName = actor?.fullName ?? actor?.userName;
10052
+ const promptConversationContext = appendRecentThreadMessagesToContext(
10053
+ preparedState.conversationContext,
10054
+ options.queuedMessages ?? []
10055
+ );
9927
10056
  const drainSteeringMessages = options.drainSteeringMessages ? async (accept) => {
9928
10057
  let acceptedMessages;
9929
10058
  const drained = await options.drainSteeringMessages(
@@ -9937,8 +10066,14 @@ function createReplyToThread(deps) {
9937
10066
  } : void 0;
9938
10067
  const outcome = await deps.services.agentRunner.run({
9939
10068
  input: {
10069
+ actor: {
10070
+ ...activeInstructionAuthorId ? { authorId: activeInstructionAuthorId } : {},
10071
+ ...activeInstructionAuthorName ? { authorName: activeInstructionAuthorName } : {},
10072
+ ...slackMessageTs ? { slackTs: slackMessageTs } : {}
10073
+ },
10074
+ includeConversationContextWithPiMessages: hasDurablePromptHistory,
9940
10075
  messageText: effectiveUserText,
9941
- conversationContext: preparedState.conversationContext,
10076
+ conversationContext: promptConversationContext,
9942
10077
  piMessages,
9943
10078
  inboundAttachmentCount: turnAttachments.length,
9944
10079
  omittedImageAttachmentCount,
@@ -9946,7 +10081,7 @@ function createReplyToThread(deps) {
9946
10081
  },
9947
10082
  routing: {
9948
10083
  credentialContext,
9949
- requester,
10084
+ actor,
9950
10085
  slackConversation,
9951
10086
  source,
9952
10087
  destination,
@@ -9961,7 +10096,7 @@ function createReplyToThread(deps) {
9961
10096
  runId,
9962
10097
  channelId,
9963
10098
  channelName,
9964
- requesterId: slackRequesterId
10099
+ actorId: slackActorId
9965
10100
  },
9966
10101
  toolChannelId
9967
10102
  },
@@ -10015,7 +10150,7 @@ function createReplyToThread(deps) {
10015
10150
  }
10016
10151
  });
10017
10152
  if (outcome.status === "awaiting_auth") {
10018
- if (!requester) {
10153
+ if (!actor) {
10019
10154
  const text = `I could not act on this subscribed event because ${outcome.providerDisplayName} needs user authorization. Ask me in this thread to connect ${outcome.providerDisplayName} before retrying.`;
10020
10155
  await postThreadReply(
10021
10156
  buildSlackOutputMessage(text),
@@ -10209,13 +10344,13 @@ function createReplyToThread(deps) {
10209
10344
  messages: reply.piMessages,
10210
10345
  logContext: {
10211
10346
  threadId,
10212
- requesterId: slackRequesterId,
10347
+ actorId: slackActorId,
10213
10348
  channelId,
10214
10349
  runId,
10215
10350
  assistantUserName: botConfig.userName,
10216
10351
  modelId: reply.diagnostics.modelId
10217
10352
  },
10218
- requester,
10353
+ actor: executionActor,
10219
10354
  surface: "slack"
10220
10355
  });
10221
10356
  } else if (conversationId) {
@@ -10228,7 +10363,7 @@ function createReplyToThread(deps) {
10228
10363
  sliceId: 1,
10229
10364
  startedAtMs: message.metadata.dateSent.getTime(),
10230
10365
  state: "completed",
10231
- requester,
10366
+ actor: executionActor,
10232
10367
  destination,
10233
10368
  destinationVisibility,
10234
10369
  source,
@@ -10299,6 +10434,10 @@ function createReplyToThread(deps) {
10299
10434
  shouldPersistFailureState = false;
10300
10435
  throw error;
10301
10436
  }
10437
+ if (error instanceof TurnInputDeferredError) {
10438
+ shouldPersistFailureState = false;
10439
+ throw error;
10440
+ }
10302
10441
  if (error === agentContinueScheduleError) {
10303
10442
  shouldPersistFailureState = true;
10304
10443
  throw error;
@@ -10381,7 +10520,7 @@ function createReplyToThread(deps) {
10381
10520
  sliceId: 1,
10382
10521
  startedAtMs: message.metadata.dateSent.getTime(),
10383
10522
  state: "failed",
10384
- requester,
10523
+ actor,
10385
10524
  destination,
10386
10525
  destinationVisibility,
10387
10526
  source,
@@ -10617,7 +10756,7 @@ function createPrepareTurnState(deps) {
10617
10756
  await deps.hydrateConversationVisionContext(conversation, {
10618
10757
  threadId: args.context.threadId,
10619
10758
  channelId: args.context.channelId,
10620
- requesterId: args.context.requesterId,
10759
+ actorId: args.context.actorId,
10621
10760
  runId: args.context.runId,
10622
10761
  threadTs: getThreadTs(args.context.threadId)
10623
10762
  });
@@ -10625,7 +10764,7 @@ function createPrepareTurnState(deps) {
10625
10764
  await deps.compactConversationIfNeeded(conversation, {
10626
10765
  threadId: args.context.threadId,
10627
10766
  channelId: args.context.channelId,
10628
- requesterId: args.context.requesterId,
10767
+ actorId: args.context.actorId,
10629
10768
  runId: args.context.runId
10630
10769
  });
10631
10770
  const conversationContext = buildConversationContext(conversation, {
@@ -10909,11 +11048,11 @@ async function failContinuationStartup(args) {
10909
11048
  );
10910
11049
  }
10911
11050
  }
10912
- async function resolveContinuationRequester(args) {
10913
- const stored = args.sessionRecordRequester;
11051
+ async function resolveContinuationActor(args) {
11052
+ const stored = args.sessionRecordActor;
10914
11053
  if (stored?.platform === "slack" && stored.teamId === args.teamId && stored.userId === args.userId) {
10915
- return createSlackResumeRequester({
10916
- requester: stored,
11054
+ return createSlackResumeActor({
11055
+ actor: stored,
10917
11056
  teamId: args.teamId,
10918
11057
  userId: args.userId
10919
11058
  });
@@ -10921,12 +11060,12 @@ async function resolveContinuationRequester(args) {
10921
11060
  const work = await getConversationWorkState2({
10922
11061
  conversationId: args.conversationId
10923
11062
  });
10924
- const workRequester = work?.requester;
10925
- if (workRequester && workRequester.teamId === args.teamId && workRequester.slackUserId === args.userId) {
10926
- return createSlackRequester(args.teamId, args.userId, {
10927
- email: workRequester.email,
10928
- fullName: workRequester.fullName,
10929
- userName: workRequester.slackUserName
11063
+ const workActor = work?.actor;
11064
+ if (workActor && workActor.teamId === args.teamId && workActor.slackUserId === args.userId) {
11065
+ return createSlackActor(args.teamId, args.userId, {
11066
+ email: workActor.email,
11067
+ fullName: workActor.fullName,
11068
+ userName: workActor.slackUserName
10930
11069
  });
10931
11070
  }
10932
11071
  return void 0;
@@ -10994,16 +11133,16 @@ async function continueSlackAgentRun(payload, options) {
10994
11133
  payload.destination,
10995
11134
  "Slack continuation"
10996
11135
  );
10997
- const requester = await resolveContinuationRequester({
11136
+ const actor = await resolveContinuationActor({
10998
11137
  conversationId: payload.conversationId,
10999
- sessionRecordRequester: activeSessionRecord.requester,
11138
+ sessionRecordActor: activeSessionRecord.actor,
11000
11139
  teamId: destination.teamId,
11001
11140
  userId: userMessage2.author.userId
11002
11141
  });
11003
- if (!requester) {
11142
+ if (!actor) {
11004
11143
  await failStrandedSessionWithFallback({
11005
11144
  conversationId: payload.conversationId,
11006
- errorMessage: "Stored Slack requester missing for continuation",
11145
+ errorMessage: "Stored Slack actor missing for continuation",
11007
11146
  sessionRecord: activeSessionRecord
11008
11147
  });
11009
11148
  return false;
@@ -11030,10 +11169,10 @@ async function continueSlackAgentRun(payload, options) {
11030
11169
  credentialContext: {
11031
11170
  actor: {
11032
11171
  type: "user",
11033
- userId: requester.userId
11172
+ userId: actor.userId
11034
11173
  }
11035
11174
  },
11036
- requester,
11175
+ actor,
11037
11176
  destination: payload.destination,
11038
11177
  source: activeSessionRecord.source,
11039
11178
  correlation: {
@@ -11041,7 +11180,7 @@ async function continueSlackAgentRun(payload, options) {
11041
11180
  turnId: payload.sessionId,
11042
11181
  channelId: thread.channelId,
11043
11182
  threadTs: thread.threadTs,
11044
- requesterId: requester.userId
11183
+ actorId: actor.userId
11045
11184
  },
11046
11185
  toolChannelId: artifacts.assistantContextChannelId ?? thread.channelId
11047
11186
  },
@@ -11187,7 +11326,7 @@ async function recoverStrandedRunningSession(args) {
11187
11326
  messages: sessionRecord.piMessages,
11188
11327
  errorMessage: "Recovered running session after hard worker death",
11189
11328
  logContext: { modelId: botConfig.modelId },
11190
- requester: sessionRecord.requester,
11329
+ actor: sessionRecord.actor,
11191
11330
  surface: sessionRecord.surface
11192
11331
  });
11193
11332
  if (!parked) {