@sentry/junior 0.145.0 → 0.147.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 (171) hide show
  1. package/dist/{agent-hooks-L7D2BDVV.js → agent-hooks-HS6VGUPM.js} +10 -10
  2. package/dist/api/conversations/detail.d.ts +1 -0
  3. package/dist/api/conversations/event-list.d.ts +1 -0
  4. package/dist/api/schema/conversation.d.ts +4 -0
  5. package/dist/api/schema.js +1 -1
  6. package/dist/api.js +26 -22
  7. package/dist/app.js +285 -290
  8. package/dist/{catalog-runtime-QLAC4Q3W.js → catalog-runtime-M6ZTPYRV.js} +5 -5
  9. package/dist/chat/agent/prompt.d.ts +0 -2
  10. package/dist/chat/agent/request.d.ts +2 -5
  11. package/dist/chat/agent/resume.d.ts +0 -3
  12. package/dist/chat/agent/sandbox.d.ts +2 -2
  13. package/dist/chat/agent/skills.d.ts +0 -1
  14. package/dist/chat/agent/tools.d.ts +0 -3
  15. package/dist/chat/agent-dispatch/types.d.ts +2 -2
  16. package/dist/chat/capabilities/jr-rpc-command.d.ts +2 -2
  17. package/dist/chat/configuration/service.d.ts +5 -2
  18. package/dist/chat/configuration/sql.d.ts +9 -0
  19. package/dist/chat/configuration/types.d.ts +17 -13
  20. package/dist/chat/conversations/history.d.ts +3 -0
  21. package/dist/chat/conversations/message-search.d.ts +32 -0
  22. package/dist/chat/conversations/projection.d.ts +10 -0
  23. package/dist/chat/conversations/sql/message-search.d.ts +4 -0
  24. package/dist/chat/conversations/tool-source.d.ts +5 -0
  25. package/dist/chat/credentials/unlink-provider.d.ts +2 -1
  26. package/dist/chat/credentials/user-token-store.d.ts +2 -0
  27. package/dist/chat/db.d.ts +2 -2
  28. package/dist/chat/event-tasks/tool-support.d.ts +2 -0
  29. package/dist/chat/identities/sql.d.ts +8 -0
  30. package/dist/chat/logging.d.ts +2 -0
  31. package/dist/chat/mcp/auth-store.d.ts +0 -2
  32. package/dist/chat/mcp/oauth.d.ts +0 -2
  33. package/dist/chat/oauth-flow.d.ts +3 -1
  34. package/dist/chat/pi/client.d.ts +2 -0
  35. package/dist/chat/plugins/credential-hooks.d.ts +2 -0
  36. package/dist/chat/prompt.d.ts +0 -2
  37. package/dist/chat/resource-events/notification.d.ts +2 -1
  38. package/dist/chat/runtime/delivered-turn-state.d.ts +1 -4
  39. package/dist/chat/runtime/thread-state.d.ts +8 -11
  40. package/dist/chat/runtime/turn-input.d.ts +4 -2
  41. package/dist/chat/runtime/turn-preparation.d.ts +2 -4
  42. package/dist/chat/sandbox/command-result.d.ts +2 -0
  43. package/dist/chat/sandbox/egress/schemas.d.ts +6 -0
  44. package/dist/chat/scheduled-tasks/tool-support.d.ts +2 -0
  45. package/dist/chat/scheduled-tasks/tools/create.d.ts +2 -0
  46. package/dist/chat/scheduled-tasks/tools/delete.d.ts +2 -0
  47. package/dist/chat/scheduled-tasks/tools/list.d.ts +2 -0
  48. package/dist/chat/scheduled-tasks/tools/run-now.d.ts +2 -0
  49. package/dist/chat/scheduled-tasks/tools/update.d.ts +2 -0
  50. package/dist/chat/services/mcp-auth-orchestration.d.ts +0 -3
  51. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
  52. package/dist/chat/services/provider-default-config.d.ts +2 -2
  53. package/dist/chat/services/subscribed-decision.d.ts +3 -0
  54. package/dist/chat/services/subscribed-reply-policy.d.ts +1 -0
  55. package/dist/chat/services/turn-result.d.ts +0 -3
  56. package/dist/chat/services/turn-router.d.ts +3 -0
  57. package/dist/chat/slack/assistant-thread/lifecycle.d.ts +0 -1
  58. package/dist/chat/slack/assistant-thread/title.d.ts +0 -3
  59. package/dist/chat/slack/dispatch-turn.d.ts +1 -1
  60. package/dist/chat/slack/message/attachments.d.ts +2 -0
  61. package/dist/chat/slack/message/blocks.d.ts +2 -0
  62. package/dist/chat/slack/message/content.d.ts +18 -0
  63. package/dist/chat/slack/message/identity.d.ts +7 -0
  64. package/dist/chat/slack/tools/canvas/context.d.ts +0 -10
  65. package/dist/chat/slack/tools/canvas/create.d.ts +2 -0
  66. package/dist/chat/slack/tools/canvas/edit.d.ts +2 -0
  67. package/dist/chat/slack/tools/canvas/read.d.ts +2 -0
  68. package/dist/chat/slack/tools/canvas/write.d.ts +2 -0
  69. package/dist/chat/slack/tools/channel-list-messages.d.ts +2 -0
  70. package/dist/chat/slack/tools/{conversation-search.d.ts → conversation-message-search.d.ts} +23 -14
  71. package/dist/chat/slack/tools/list/add-items.d.ts +4 -1
  72. package/dist/chat/slack/tools/list/api.d.ts +8 -1
  73. package/dist/chat/slack/tools/list/create.d.ts +2 -0
  74. package/dist/chat/slack/tools/list/get-items.d.ts +5 -3
  75. package/dist/chat/slack/tools/list/update-item.d.ts +5 -1
  76. package/dist/chat/slack/tools/message-add-reaction.d.ts +2 -0
  77. package/dist/chat/slack/tools/public-search.d.ts +2 -0
  78. package/dist/chat/slack/tools/send-files.d.ts +2 -0
  79. package/dist/chat/slack/tools/thread-read.d.ts +2 -0
  80. package/dist/chat/slack/vision-cache.d.ts +5 -0
  81. package/dist/chat/state/conversation.d.ts +4 -5
  82. package/dist/chat/task-execution/checkpoint.d.ts +1 -3
  83. package/dist/chat/task-execution/turn-cursor.d.ts +0 -9
  84. package/dist/chat/tool-support/structured-result.d.ts +1 -0
  85. package/dist/chat/tool-support/timed-out-tool-result.d.ts +11 -0
  86. package/dist/chat/tools/create-event-task.d.ts +2 -0
  87. package/dist/chat/tools/delete-event-task.d.ts +2 -0
  88. package/dist/chat/tools/handoff/tool.d.ts +2 -0
  89. package/dist/chat/tools/list-event-tasks.d.ts +2 -0
  90. package/dist/chat/tools/list-resource-event-subscriptions.d.ts +2 -0
  91. package/dist/chat/tools/runtime/report-progress.d.ts +2 -0
  92. package/dist/chat/tools/runtime/spawn-agent.d.ts +2 -0
  93. package/dist/chat/tools/{query-conversation-events.d.ts → search-conversation-events.d.ts} +5 -3
  94. package/dist/chat/tools/search-resource-event-types.d.ts +2 -0
  95. package/dist/chat/tools/search-tools.d.ts +2 -0
  96. package/dist/chat/tools/skill/load-skill.d.ts +2 -0
  97. package/dist/chat/tools/skill/search-mcp-tools.d.ts +2 -0
  98. package/dist/chat/tools/stop-watching-resources.d.ts +2 -0
  99. package/dist/chat/tools/system-time.d.ts +2 -0
  100. package/dist/chat/tools/types.d.ts +0 -6
  101. package/dist/chat/tools/update-event-task.d.ts +2 -0
  102. package/dist/chat/tools/user-lookup.d.ts +29 -0
  103. package/dist/chat/tools/watch-resource-events.d.ts +2 -0
  104. package/dist/chat/tools/web/fetch-tool.d.ts +2 -0
  105. package/dist/chat/tools/web/image-generate.d.ts +2 -0
  106. package/dist/chat/tools/web/search.d.ts +2 -0
  107. package/dist/{chunk-PJ4NMVQB.js → chunk-34GS7B6L.js} +2 -2
  108. package/dist/{chunk-2LWPFSB4.js → chunk-4LJO56OJ.js} +9 -1
  109. package/dist/{chunk-QJBDABQA.js → chunk-6H5SZR24.js} +16 -20
  110. package/dist/{chunk-LVVSIMBB.js → chunk-745QJ3ZA.js} +1 -1
  111. package/dist/{chunk-64SBYW2O.js → chunk-7A4M7PCV.js} +613 -561
  112. package/dist/{chunk-XFKIRN3Q.js → chunk-7NVJVJID.js} +4 -3
  113. package/dist/{chunk-FUBRJA5F.js → chunk-7UQIVT6G.js} +13 -6
  114. package/dist/{chunk-ZIAMN2UW.js → chunk-AIOK6LAG.js} +40 -513
  115. package/dist/{chunk-EIX2LQ6L.js → chunk-AVOCH2Z5.js} +3 -3
  116. package/dist/{chunk-GUWLDMGF.js → chunk-AVZDSUFB.js} +4 -4
  117. package/dist/{chunk-2XET6PKP.js → chunk-AYU72WO7.js} +102 -73
  118. package/dist/chunk-AZ7EAOBE.js +566 -0
  119. package/dist/{chunk-DXEQAIUV.js → chunk-CSZINQJ2.js} +1 -1
  120. package/dist/{chunk-HLOUZC5C.js → chunk-CWP5RHVX.js} +4 -4
  121. package/dist/{chunk-DS3J6WGY.js → chunk-DLDRQHG5.js} +1 -1
  122. package/dist/{chunk-27TEJTZO.js → chunk-DU74WPIC.js} +55 -37
  123. package/dist/{chunk-YD54Q45G.js → chunk-EFLJ2WJH.js} +6 -4
  124. package/dist/{chunk-CD2XFGYQ.js → chunk-GGB4WL5A.js} +1 -1
  125. package/dist/{chunk-GDV5LXRA.js → chunk-IIOOO4FQ.js} +1 -1
  126. package/dist/{chunk-SIN3MXH6.js → chunk-JUUKWRBE.js} +1 -1
  127. package/dist/{chunk-VTDMB7XX.js → chunk-K4SZAP3K.js} +1 -1
  128. package/dist/{chunk-QUG4JSZK.js → chunk-ORO3PWKQ.js} +1 -1
  129. package/dist/{chunk-RUSS62EN.js → chunk-PVNG6UMU.js} +3 -3
  130. package/dist/{chunk-I47UGQPJ.js → chunk-Q4R73I43.js} +365 -206
  131. package/dist/{chunk-JTGS3ZZE.js → chunk-RXBVB2JM.js} +1 -1
  132. package/dist/{chunk-TZRXYWRE.js → chunk-SGZO7UWH.js} +2 -2
  133. package/dist/{chunk-JLMVCNXL.js → chunk-SVHUEHUL.js} +1 -0
  134. package/dist/{chunk-B46ZMVOV.js → chunk-X5UY34KT.js} +6 -5
  135. package/dist/{chunk-5PNPQYTO.js → chunk-YBVXBNSV.js} +2 -2
  136. package/dist/{chunk-HISR3DTV.js → chunk-YEO3VX72.js} +10 -25
  137. package/dist/{chunk-ZIMRGFYL.js → chunk-YHDERDRO.js} +7 -6
  138. package/dist/{chunk-WF5HVH3M.js → chunk-YNTTROJT.js} +1 -1
  139. package/dist/{chunk-2UH3JI64.js → chunk-YSB2N563.js} +87 -34
  140. package/dist/{chunk-ZYAJMESY.js → chunk-Z4YU7Z4L.js} +3 -2
  141. package/dist/cli/chat.js +32 -32
  142. package/dist/cli/check.js +6 -6
  143. package/dist/cli/plugins.js +13 -13
  144. package/dist/cli/snapshot-create.js +9 -9
  145. package/dist/cli/upgrade.js +7 -7
  146. package/dist/db/schema/location-configurations.d.ts +127 -0
  147. package/dist/db/schema.d.ts +128 -1
  148. package/dist/{db-62PW6LM3.js → db-CSEW4RII.js} +9 -9
  149. package/dist/instrumentation.js +4 -4
  150. package/dist/nitro.js +2 -2
  151. package/dist/{oauth-callback-server-6NZNHJAM.js → oauth-callback-server-FUEV5HNG.js} +24 -24
  152. package/dist/{runner-GCRPG3GQ.js → runner-U3XHSKSH.js} +21 -41
  153. package/dist/{skills-2S3MDFIQ.js → skills-AKE6W3WI.js} +6 -6
  154. package/dist/spawn-B6GDTWJ4.js +39 -0
  155. package/dist/{validation-HAOLCJ5A.js → validation-WDTAULUF.js} +6 -6
  156. package/dist/version.js +1 -1
  157. package/dist/{work-R4XYKMUW.js → work-C3HAO2BG.js} +17 -17
  158. package/dist/{worker-U2UCVR7M.js → worker-LNP4YKBM.js} +10 -10
  159. package/migrations/0024_misty_typhoid_mary.sql +12 -0
  160. package/migrations/meta/0024_snapshot.json +2275 -0
  161. package/migrations/meta/_journal.json +7 -0
  162. package/package.json +4 -4
  163. package/dist/chat/conversations/search.d.ts +0 -24
  164. package/dist/chat/conversations/sql/search.d.ts +0 -4
  165. package/dist/chat/slack/legacy-attachments.d.ts +0 -4
  166. package/dist/chat/slack/message.d.ts +0 -12
  167. package/dist/chat/slack/tools/user-lookup.d.ts +0 -26
  168. package/dist/chat/state/artifacts.d.ts +0 -30
  169. package/dist/chat/tool-support/turn-deadline-result.d.ts +0 -3
  170. package/dist/chunk-Q6QZTTLS.js +0 -55
  171. package/dist/spawn-7WK37BTD.js +0 -39
@@ -7,7 +7,7 @@ import {
7
7
  PluginCredentialFailureError,
8
8
  agentNameSchema,
9
9
  createPluginAuthOrchestration
10
- } from "./chunk-B46ZMVOV.js";
10
+ } from "./chunk-X5UY34KT.js";
11
11
  import {
12
12
  authorizationId
13
13
  } from "./chunk-DIB4GX3G.js";
@@ -21,14 +21,18 @@ import {
21
21
  getMcpAwareErrorType,
22
22
  getMcpAwareTelemetryMessage,
23
23
  getMcpProviderErrorAttributes,
24
+ getOAuthAccountProviders,
24
25
  hasEgressCredentialHooks,
25
26
  issuePluginCredential,
26
27
  issueProviderCredentialLease,
28
+ lookupSlackUserByEmail,
29
+ lookupSlackUserProfile,
27
30
  onPluginEgressResponse,
28
31
  patchMcpAuthSession,
32
+ searchSlackUsers,
29
33
  selectPluginGrant,
30
34
  toMcpProviderError
31
- } from "./chunk-I47UGQPJ.js";
35
+ } from "./chunk-Q4R73I43.js";
32
36
  import {
33
37
  RetryableDeliveryError,
34
38
  actorFromRouting,
@@ -44,12 +48,12 @@ import {
44
48
  getSlackMessagePermalink,
45
49
  resolveBaseUrl,
46
50
  uploadFilesToConversation
47
- } from "./chunk-FUBRJA5F.js";
51
+ } from "./chunk-7UQIVT6G.js";
48
52
  import {
49
53
  estimateTextTokens,
50
54
  getAgentContextCompactionTriggerTokens,
51
55
  getAgentContextInputLimitTokens
52
- } from "./chunk-VTDMB7XX.js";
56
+ } from "./chunk-K4SZAP3K.js";
53
57
  import {
54
58
  AGENTS_REMOVAL_NOTICE,
55
59
  AGENTS_REPLACEMENT_NOTICE,
@@ -89,7 +93,6 @@ import {
89
93
  loadConversationProjection,
90
94
  loadTurnCheckpoint,
91
95
  loadTurnRoute,
92
- mergeArtifactsState,
93
96
  missingPathSearchResult,
94
97
  normalizeToLf,
95
98
  normalizeToolNameFromResult,
@@ -111,7 +114,7 @@ import {
111
114
  stripRuntimeTurnContext,
112
115
  trimTrailingAssistantMessages,
113
116
  truncateText
114
- } from "./chunk-ZIAMN2UW.js";
117
+ } from "./chunk-AIOK6LAG.js";
115
118
  import {
116
119
  JUNIOR_THREAD_STATE_TTL_MS
117
120
  } from "./chunk-3Y47VMHV.js";
@@ -143,7 +146,7 @@ import {
143
146
  runNonInteractiveCommand,
144
147
  throwSandboxOperationError,
145
148
  wrapSandboxSetupError
146
- } from "./chunk-GUWLDMGF.js";
149
+ } from "./chunk-AVZDSUFB.js";
147
150
  import {
148
151
  SCHEDULED_TASK_SYSTEM_ACTOR,
149
152
  compactEventTask,
@@ -175,15 +178,15 @@ import {
175
178
  saveEventTask,
176
179
  scheduledTaskAttributes,
177
180
  writableEventTask
178
- } from "./chunk-YD54Q45G.js";
181
+ } from "./chunk-EFLJ2WJH.js";
179
182
  import {
180
183
  parseSlackThreadId
181
- } from "./chunk-DXEQAIUV.js";
184
+ } from "./chunk-CSZINQJ2.js";
182
185
  import {
183
186
  SHORT_TITLE_MAX_LENGTH,
184
187
  generateShortTitle,
185
188
  resolveTaskTitle
186
- } from "./chunk-ZYAJMESY.js";
189
+ } from "./chunk-Z4YU7Z4L.js";
187
190
  import {
188
191
  ToolInputError,
189
192
  addAgentTurnUsage,
@@ -201,7 +204,7 @@ import {
201
204
  getSlackToolContext,
202
205
  readActorIdentity,
203
206
  resolveChannelCapabilities
204
- } from "./chunk-ZIMRGFYL.js";
207
+ } from "./chunk-YHDERDRO.js";
205
208
  import {
206
209
  SlackActionError,
207
210
  downloadPrivateSlackFile,
@@ -210,18 +213,22 @@ import {
210
213
  isConversationScopedChannel,
211
214
  normalizeSlackConversationId,
212
215
  withSlackRetries
213
- } from "./chunk-TZRXYWRE.js";
216
+ } from "./chunk-SGZO7UWH.js";
214
217
  import {
215
218
  KNOWN_CONVERSATION_EVENT_TYPES,
216
219
  contextProvenance,
217
220
  getConversationEventStore,
218
- getConversationSearchStore,
221
+ getConversationMessageSearchStore,
219
222
  getConversationStore,
220
223
  getDb,
224
+ getSqlExecutor,
221
225
  instructionActors,
222
226
  instructionProvenanceFor,
223
227
  sameActorIdentity
224
- } from "./chunk-2UH3JI64.js";
228
+ } from "./chunk-YSB2N563.js";
229
+ import {
230
+ juniorIdentities
231
+ } from "./chunk-DU74WPIC.js";
225
232
  import {
226
233
  SANDBOX_DATA_ROOT,
227
234
  SANDBOX_SKILLS_ROOT,
@@ -233,7 +240,7 @@ import {
233
240
  } from "./chunk-EM225ITJ.js";
234
241
  import {
235
242
  getStateAdapter
236
- } from "./chunk-QUG4JSZK.js";
243
+ } from "./chunk-ORO3PWKQ.js";
237
244
  import {
238
245
  ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
239
246
  COMPACTION_SUMMARY_PREFIX,
@@ -261,13 +268,12 @@ import {
261
268
  modelIdForProfile,
262
269
  modelProfileSchema,
263
270
  normalizeSlackEmojiName,
264
- parseTurnReasoningLevel,
265
271
  profileConfig,
266
272
  renderCurrentInstruction,
267
273
  resolveGatewayCredential,
268
274
  resolveGatewayModel,
269
275
  unwrapCurrentInstruction
270
- } from "./chunk-XFKIRN3Q.js";
276
+ } from "./chunk-7NVJVJID.js";
271
277
  import {
272
278
  canExposeConversationPayload,
273
279
  resolveConversationPrivacy,
@@ -277,16 +283,16 @@ import {
277
283
  toGenAiMessagesTraceAttributes,
278
284
  toGenAiPayloadMetadata,
279
285
  toGenAiPayloadTraceAttributes
280
- } from "./chunk-JTGS3ZZE.js";
286
+ } from "./chunk-RXBVB2JM.js";
281
287
  import {
282
288
  discoverSkills,
283
289
  findSkillByName,
284
290
  loadSkillsByName,
285
291
  parseSkillInvocation
286
- } from "./chunk-5PNPQYTO.js";
292
+ } from "./chunk-YBVXBNSV.js";
287
293
  import {
288
294
  pluginCatalogRuntime
289
- } from "./chunk-SIN3MXH6.js";
295
+ } from "./chunk-JUUKWRBE.js";
290
296
  import {
291
297
  CredentialUnavailableError,
292
298
  OAuthProviderError,
@@ -294,7 +300,7 @@ import {
294
300
  getOAuthProviderErrorAttributes,
295
301
  resolveAuthTokenPlaceholder,
296
302
  resolvePluginCommandEnv
297
- } from "./chunk-CD2XFGYQ.js";
303
+ } from "./chunk-GGB4WL5A.js";
298
304
  import {
299
305
  credentialUserSubjectId
300
306
  } from "./chunk-RUIXF3YQ.js";
@@ -316,6 +322,7 @@ import {
316
322
  logInfo,
317
323
  logWarn,
318
324
  normalizeGenAiFinishReason,
325
+ normalizeIdentityEmail,
319
326
  serializeGenAiAttribute,
320
327
  setSpanAttributes,
321
328
  setSpanStatus,
@@ -323,7 +330,7 @@ import {
323
330
  summarizeMessageText,
324
331
  withLogContext,
325
332
  withSpan
326
- } from "./chunk-2LWPFSB4.js";
333
+ } from "./chunk-4LJO56OJ.js";
327
334
  import {
328
335
  startInactiveSpan,
329
336
  withActiveSpan
@@ -805,7 +812,6 @@ import { isRetryableAssistantError } from "@earendil-works/pi-ai";
805
812
  function buildTurnResult(input) {
806
813
  const {
807
814
  newMessages,
808
- artifactStatePatch,
809
815
  toolCalls,
810
816
  sandboxRef,
811
817
  durationMs,
@@ -901,7 +907,6 @@ function buildTurnResult(input) {
901
907
  };
902
908
  return {
903
909
  text: primaryText,
904
- artifactStatePatch: Object.keys(artifactStatePatch).length > 0 ? artifactStatePatch : void 0,
905
910
  sandboxRef,
906
911
  piMessages: input.piMessages,
907
912
  diagnostics: resolvedDiagnostics
@@ -981,27 +986,22 @@ function getDiscardedRetryUsage(messages, retryMessages) {
981
986
  return hasAgentTurnUsage(usage) ? usage : void 0;
982
987
  }
983
988
 
984
- // src/chat/tool-support/turn-deadline-result.ts
985
- var TURN_DEADLINE_INTERRUPTION = {
986
- cause: "turn_deadline",
987
- scope: "execution_slice",
988
- task_status: "active"
989
- };
990
- function annotateTurnDeadlineToolResult(result) {
991
- if (!result.details || typeof result.details !== "object" || Array.isArray(result.details) || !("aborted" in result.details) || result.details.aborted !== true) {
989
+ // src/chat/tool-support/timed-out-tool-result.ts
990
+ function projectTimedOutToolResult(result) {
991
+ const details = result.details;
992
+ if (!details || typeof details !== "object" || Array.isArray(details) || !("aborted" in details) || details.aborted !== true) {
992
993
  return void 0;
993
994
  }
994
- const details = {
995
- ...result.details,
996
- interruption: TURN_DEADLINE_INTERRUPTION
997
- };
998
- const envelope = makeStructuredToolOutput(details, {
999
- content: result.content.slice(1)
995
+ const record2 = details;
996
+ const target = typeof record2.target === "string" && record2.target.length > 0 ? record2.target : void 0;
997
+ const envelope = makeStructuredToolOutput({
998
+ ...target ? { target } : {},
999
+ timed_out: true
1000
1000
  });
1001
1001
  return {
1002
1002
  content: envelope.content,
1003
1003
  details: envelope.details,
1004
- isError: true
1004
+ isError: false
1005
1005
  };
1006
1006
  }
1007
1007
 
@@ -1222,13 +1222,15 @@ async function classifyTurn(args) {
1222
1222
  prompt: args.prompt,
1223
1223
  thinkingLevel: "low",
1224
1224
  system: buildClassifierSystemPrompt(Object.keys(args.profiles)),
1225
- temperature: 0
1225
+ temperature: 0,
1226
+ promptName: "junior.thinking_route"
1226
1227
  });
1227
1228
  const parsed = schema.parse(result.object);
1228
1229
  const reason = parsed.reason.trim();
1229
1230
  if (parsed.confidence < CLASSIFIER_CONFIDENCE_THRESHOLD) {
1230
1231
  return {
1231
1232
  confidence: parsed.confidence,
1233
+ ...result.costUsd !== void 0 ? { costUsd: result.costUsd } : {},
1232
1234
  profile: STANDARD_MODEL_PROFILE,
1233
1235
  reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
1234
1236
  reason: `low_confidence_medium_default:${reason}`,
@@ -1237,6 +1239,7 @@ async function classifyTurn(args) {
1237
1239
  }
1238
1240
  return {
1239
1241
  confidence: parsed.confidence,
1242
+ ...result.costUsd !== void 0 ? { costUsd: result.costUsd } : {},
1240
1243
  profile: parsed.profile,
1241
1244
  reasoningLevel: parsed.reasoning_level,
1242
1245
  reason,
@@ -1573,7 +1576,6 @@ async function restoreSkillRuntime(args) {
1573
1576
  const restoredSkill = await args.skillSandbox.loadSkill(skillName);
1574
1577
  if (restoredSkill) {
1575
1578
  upsertActiveSkill(args.activeSkills, restoredSkill);
1576
- args.syncLoadedSkillNamesForResume();
1577
1579
  }
1578
1580
  }
1579
1581
  if (args.invokedSkill) {
@@ -1582,7 +1584,6 @@ async function restoreSkillRuntime(args) {
1582
1584
  );
1583
1585
  if (restoredSkill) {
1584
1586
  upsertActiveSkill(args.activeSkills, restoredSkill);
1585
- args.syncLoadedSkillNamesForResume();
1586
1587
  }
1587
1588
  }
1588
1589
  }
@@ -1761,34 +1762,6 @@ function formatReferenceFilesLines() {
1761
1762
  return `- ${escapeXml(name)} (${escapeXml(`${SANDBOX_DATA_ROOT}/${name}`)})`;
1762
1763
  });
1763
1764
  }
1764
- function formatArtifactsLines(artifactState) {
1765
- if (!artifactState) return null;
1766
- const lines = [];
1767
- if (artifactState.lastCanvasId) {
1768
- lines.push(`- last_canvas_id: ${escapeXml(artifactState.lastCanvasId)}`);
1769
- }
1770
- if (artifactState.lastCanvasUrl) {
1771
- lines.push(`- last_canvas_url: ${escapeXml(artifactState.lastCanvasUrl)}`);
1772
- }
1773
- if (artifactState.recentCanvases && artifactState.recentCanvases.length > 0) {
1774
- lines.push("- recent_canvases:");
1775
- for (const canvas of artifactState.recentCanvases) {
1776
- lines.push(` - id: ${escapeXml(canvas.id)}`);
1777
- if (canvas.title) lines.push(` title: ${escapeXml(canvas.title)}`);
1778
- if (canvas.url) lines.push(` url: ${escapeXml(canvas.url)}`);
1779
- if (canvas.createdAt) {
1780
- lines.push(` created_at: ${escapeXml(canvas.createdAt)}`);
1781
- }
1782
- }
1783
- }
1784
- if (artifactState.lastListId) {
1785
- lines.push(`- last_list_id: ${escapeXml(artifactState.lastListId)}`);
1786
- }
1787
- if (artifactState.lastListUrl) {
1788
- lines.push(`- last_list_url: ${escapeXml(artifactState.lastListUrl)}`);
1789
- }
1790
- return lines.length > 0 ? lines : null;
1791
- }
1792
1765
  function formatConfigurationLines(configuration) {
1793
1766
  const keys = Object.keys(configuration ?? {}).sort(
1794
1767
  (a, b) => a.localeCompare(b)
@@ -1839,7 +1812,7 @@ var EXECUTION_CONTRACT_RULES = [
1839
1812
  "- Ask the user only for missing access, approval, or a decision that blocks safe progress. Ask one focused question; otherwise infer conservatively and continue.",
1840
1813
  "- For conflicting evidence, compare sources and state which source is authoritative for the answer.",
1841
1814
  "- Use `reportProgress` only for work with multiple substantive phases or a materially long wait. Skip short lookups and routine commands; after an initial update, call it again only when the major phase changes.",
1842
- "- When a tool outcome is unknown and may include side effects, inspect authoritative state before retrying. If state already reflects the intended result, do not repeat the mutation."
1815
+ "- A tool result with `timed_out: true` means that attempt did not finish. Continue the active task. Before retrying work that may have side effects, inspect authoritative state and do not repeat a mutation that already applied."
1843
1816
  ];
1844
1817
  var CONVERSATION_RULES = [
1845
1818
  "- In thread follow-ups, answer from prior thread context; do not repeat resolved clarifying questions.",
@@ -2001,10 +1974,6 @@ function buildContextSection(params) {
2001
1974
  if (dispatchLines) {
2002
1975
  blocks.push(dispatchLines);
2003
1976
  }
2004
- const artifactLines = formatArtifactsLines(params.artifactState);
2005
- if (artifactLines) {
2006
- blocks.push(renderTag("artifacts", artifactLines));
2007
- }
2008
1977
  const configLines = formatConfigurationLines(params.configuration);
2009
1978
  if (configLines) {
2010
1979
  blocks.push(
@@ -2109,7 +2078,6 @@ function buildTurnContextPrompt(params) {
2109
2078
  pluginPromptContributions,
2110
2079
  includeSessionContext ? buildContextSection({
2111
2080
  actor: params.actor,
2112
- artifactState: params.artifactState,
2113
2081
  configuration: params.configuration,
2114
2082
  dispatch: params.dispatch
2115
2083
  }) : null,
@@ -2407,7 +2375,6 @@ async function assemblePrompt(args) {
2407
2375
  source
2408
2376
  } : void 0,
2409
2377
  actor: isUserActor(args.currentActor) ? args.currentActor : void 0,
2410
- artifactState: args.artifactState,
2411
2378
  configuration: args.configurationValues
2412
2379
  }) : null;
2413
2380
  const turnContextParts = turnContextPrompt ? [{ type: "text", text: turnContextPrompt }] : [];
@@ -2493,9 +2460,9 @@ function commandResult(input) {
2493
2460
  exitCode: input.exitCode
2494
2461
  };
2495
2462
  }
2496
- function requireChannelConfiguration(deps) {
2497
- if (deps.channelConfiguration) {
2498
- return { ok: true, configuration: deps.channelConfiguration };
2463
+ function requireLocationConfiguration(deps) {
2464
+ if (deps.locationConfiguration) {
2465
+ return { ok: true, configuration: deps.locationConfiguration };
2499
2466
  }
2500
2467
  return {
2501
2468
  ok: false,
@@ -2541,7 +2508,7 @@ async function handleConfigCommand(args, deps) {
2541
2508
  "jr-rpc config list [--prefix <value>]"
2542
2509
  ].join("\n");
2543
2510
  const subverb = (args[0] ?? "").trim();
2544
- const configurationResult = requireChannelConfiguration(deps);
2511
+ const configurationResult = requireLocationConfiguration(deps);
2545
2512
  if (!configurationResult.ok) {
2546
2513
  return configurationResult.result;
2547
2514
  }
@@ -6036,7 +6003,7 @@ function createAgentSandbox(options) {
6036
6003
  if (command) {
6037
6004
  const result = await maybeExecuteJrRpcCustomCommand(command, {
6038
6005
  activeSkill: options.getActiveSkill(),
6039
- channelConfiguration: options.channelConfiguration,
6006
+ locationConfiguration: options.locationConfiguration,
6040
6007
  actorId: isUserActor(options.actor) ? options.actor.userId : void 0,
6041
6008
  onConfigurationValueChanged: (key, value) => {
6042
6009
  if (value === void 0) {
@@ -6921,7 +6888,8 @@ async function enrichImagePrompt(rawPrompt) {
6921
6888
  modelId: botConfig.fastModelId,
6922
6889
  system: ENRICHMENT_SYSTEM_PROMPT,
6923
6890
  messages: [{ role: "user", content: rawPrompt, timestamp: Date.now() }],
6924
- maxTokens: 1024
6891
+ maxTokens: 1024,
6892
+ promptName: "junior.image_prompt_enrichment"
6925
6893
  });
6926
6894
  if (text && text.trim().length > 0) {
6927
6895
  logInfo("image.prompt.enriched", {
@@ -8132,7 +8100,7 @@ function createSearchResourceEventTypesTool(catalog) {
8132
8100
  outputSchema: outputSchema2,
8133
8101
  async execute({ query, namespace, maxResults }) {
8134
8102
  const normalizedQuery = normalizeSearchText(query ?? "");
8135
- const terms = normalizedQuery.split(/\s+/).filter(Boolean);
8103
+ const terms2 = normalizedQuery.split(/\s+/).filter(Boolean);
8136
8104
  const matches = searchableResourceTypes(catalog).filter(
8137
8105
  (resourceType) => {
8138
8106
  if (namespace && resourceType.namespace !== namespace) return false;
@@ -8144,7 +8112,7 @@ function createSearchResourceEventTypesTool(catalog) {
8144
8112
  ...resourceType.suggestedEvents ?? []
8145
8113
  ].join(" ")
8146
8114
  );
8147
- return terms.every((term) => text.includes(term));
8115
+ return terms2.every((term) => text.includes(term));
8148
8116
  }
8149
8117
  );
8150
8118
  const resourceTypes = matches.slice(
@@ -9816,32 +9784,63 @@ function createSlackChannelListMessagesTool(context) {
9816
9784
  });
9817
9785
  }
9818
9786
 
9819
- // src/chat/slack/tools/conversation-search.ts
9787
+ // src/chat/slack/tools/conversation-message-search.ts
9820
9788
  import { z as z37 } from "zod";
9789
+
9790
+ // src/chat/conversations/tool-source.ts
9791
+ var CONVERSATIONS_TOOL_SOURCE = {
9792
+ id: "conversations",
9793
+ description: "Search messages and events in retained Junior conversations."
9794
+ };
9795
+
9796
+ // src/chat/slack/tools/conversation-message-search.ts
9821
9797
  var DEFAULT_LIMIT = 5;
9822
- var conversationSearchOutputSchema = juniorToolOutputSchema.extend({
9823
- query: z37.string(),
9798
+ var conversationMessageSearchOutputSchema = juniorToolOutputSchema.extend({
9799
+ channel_id: z37.string().min(1).optional(),
9824
9800
  count: z37.number().int().nonnegative(),
9825
- threads: z37.array(
9801
+ query: z37.string().optional(),
9802
+ matches: z37.array(
9826
9803
  z37.object({
9804
+ channel_id: z37.string().min(1),
9805
+ channel_name: z37.string().min(1).optional(),
9827
9806
  conversation_id: z37.string().min(1),
9828
- thread_ts: z37.string().min(1),
9807
+ excerpt: z37.string(),
9829
9808
  message_id: z37.string().min(1),
9830
9809
  message_role: z37.enum(["assistant", "user"]),
9831
9810
  message_timestamp: z37.string().datetime(),
9832
- excerpt: z37.string(),
9833
- permalink: z37.string().url().optional()
9811
+ permalink: z37.string().url().optional(),
9812
+ thread_ts: z37.string().min(1)
9834
9813
  }).strict()
9835
9814
  )
9836
9815
  });
9837
- function createSlackConversationSearchTool(scope, currentConversationId, deps = {}) {
9816
+ function resolveSearchFilters(input) {
9817
+ const query = input.query?.trim() || void 0;
9818
+ let channelId;
9819
+ if (input.channel_id != null) {
9820
+ const parsed = parseRequiredSlackChannelIdParam(
9821
+ "channel_id",
9822
+ input.channel_id
9823
+ );
9824
+ if (!parsed.ok) {
9825
+ throw new ToolInputError(parsed.error);
9826
+ }
9827
+ channelId = parsed.value;
9828
+ }
9829
+ if (!query && !channelId) {
9830
+ throw new ToolInputError(
9831
+ "Provide at least one of `query` or `channel_id`."
9832
+ );
9833
+ }
9834
+ return {
9835
+ ...channelId ? { channelId } : {},
9836
+ ...query ? { query } : {}
9837
+ };
9838
+ }
9839
+ function createSlackConversationMessageSearchTool(scope, currentConversationId, deps = {}) {
9838
9840
  return zodTool({
9839
- description: "Search prior public Junior conversation threads across the current Slack workspace. Use when the user refers to an earlier public discussion, decision, or answer that is not in the current thread. Searches retained visible user and assistant messages only.",
9841
+ description: "Search retained user and assistant messages in public Junior conversations across the current Slack workspace. Excludes the current conversation.",
9840
9842
  exposure: "deferred",
9841
- source: {
9842
- id: "conversation-history",
9843
- description: "Search retained public Junior conversation threads in the current Slack workspace."
9844
- },
9843
+ source: CONVERSATIONS_TOOL_SOURCE,
9845
9844
  annotations: {
9846
9845
  destructiveHint: false,
9847
9846
  idempotentHint: true,
@@ -9849,20 +9848,24 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
9849
9848
  readOnlyHint: true
9850
9849
  },
9851
9850
  inputSchema: z37.object({
9852
- query: z37.string().trim().min(1).max(200).describe("Words or a short phrase to find in prior conversations."),
9853
- limit: z37.number().int().min(1).max(10).describe("Maximum number of prior conversation threads to return.").nullable().optional()
9854
- }),
9855
- outputSchema: conversationSearchOutputSchema,
9856
- execute: async ({ query, limit }) => {
9857
- const store = deps.store ?? getConversationSearchStore();
9851
+ channel_id: slackChannelIdParam(
9852
+ "Destination Slack channel ID; no active-channel default."
9853
+ ).nullable().optional(),
9854
+ query: z37.string().trim().min(1).max(200).nullable().describe("Words or phrase to match in message text.").optional(),
9855
+ limit: z37.number().int().min(1).max(10).describe(`Maximum matches. Default ${DEFAULT_LIMIT}; max 10.`).nullable().optional()
9856
+ }).strict(),
9857
+ outputSchema: conversationMessageSearchOutputSchema,
9858
+ execute: async (input) => {
9859
+ const filters = resolveSearchFilters(input);
9860
+ const store = deps.store ?? getConversationMessageSearchStore();
9858
9861
  const matches = await store.search({
9859
9862
  currentConversationId,
9860
- limit: limit ?? DEFAULT_LIMIT,
9861
- query,
9863
+ filters,
9864
+ limit: input.limit ?? DEFAULT_LIMIT,
9862
9865
  scope
9863
9866
  });
9864
9867
  const getPermalink = deps.getPermalink ?? getSlackMessagePermalink;
9865
- const threads = await Promise.all(
9868
+ const matchesOutput = await Promise.all(
9866
9869
  matches.map(async (match) => {
9867
9870
  const reference = parseSlackThreadId(match.conversationId);
9868
9871
  if (!reference || reference.channelId !== match.providerDestinationId) {
@@ -9881,14 +9884,17 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
9881
9884
  message_role: match.role,
9882
9885
  message_timestamp: new Date(match.messageCreatedAtMs).toISOString(),
9883
9886
  excerpt: match.excerpt,
9887
+ channel_id: match.providerDestinationId,
9888
+ ...match.channelName ? { channel_name: match.channelName } : {},
9884
9889
  ...permalink ? { permalink } : {}
9885
9890
  };
9886
9891
  })
9887
9892
  );
9888
9893
  return {
9889
- query,
9890
- count: threads.length,
9891
- threads
9894
+ ...filters.query ? { query: filters.query } : {},
9895
+ ...filters.channelId ? { channel_id: filters.channelId } : {},
9896
+ count: matchesOutput.length,
9897
+ matches: matchesOutput
9892
9898
  };
9893
9899
  }
9894
9900
  });
@@ -10523,45 +10529,6 @@ async function readCanvas(canvasIdOrUrl) {
10523
10529
  };
10524
10530
  }
10525
10531
 
10526
- // src/chat/slack/tools/canvas/context.ts
10527
- var MAX_RECENT_CANVASES = 5;
10528
- function mergeRecentCanvases(existing, created) {
10529
- const nextEntry = {
10530
- id: created.id,
10531
- title: created.title,
10532
- url: created.url,
10533
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
10534
- };
10535
- const prior = existing ?? [];
10536
- const deduped = prior.filter((entry) => entry.id !== created.id);
10537
- return [nextEntry, ...deduped].slice(0, MAX_RECENT_CANVASES);
10538
- }
10539
- function resolveCanvasTarget(canvas) {
10540
- const canvasId = extractCanvasId(canvas);
10541
- if (!canvasId) {
10542
- return {
10543
- ok: false,
10544
- error: "Could not parse a Slack canvas/file ID from input. Provide an F-prefixed ID or a Slack canvas/docs URL."
10545
- };
10546
- }
10547
- return { ok: true, canvasId };
10548
- }
10549
- function storedCanvasUrl(state, canvasId) {
10550
- const lastCanvasUrl = state.artifactState.lastCanvasUrl;
10551
- if (lastCanvasUrl && extractCanvasId(lastCanvasUrl) === canvasId) {
10552
- return lastCanvasUrl;
10553
- }
10554
- for (const canvas of state.artifactState.recentCanvases ?? []) {
10555
- if (extractCanvasId(canvas.id) === canvasId) {
10556
- return canvas.url;
10557
- }
10558
- if (canvas.url && extractCanvasId(canvas.url) === canvasId) {
10559
- return canvas.url;
10560
- }
10561
- }
10562
- return void 0;
10563
- }
10564
-
10565
10532
  // src/chat/slack/tools/canvas/create.ts
10566
10533
  import { z as z41 } from "zod";
10567
10534
  function createSlackCanvasCreateTool(context, state) {
@@ -10607,18 +10574,6 @@ function createSlackCanvasCreateTool(context, state) {
10607
10574
  markdown,
10608
10575
  channelId: targetChannelId
10609
10576
  });
10610
- await state.patchArtifactState({
10611
- lastCanvasId: created.canvasId,
10612
- lastCanvasUrl: created.permalink,
10613
- recentCanvases: mergeRecentCanvases(
10614
- state.artifactState.recentCanvases,
10615
- {
10616
- id: created.canvasId,
10617
- title,
10618
- url: created.permalink
10619
- }
10620
- )
10621
- });
10622
10577
  const response = {
10623
10578
  canvas_id: created.canvasId,
10624
10579
  permalink: created.permalink,
@@ -10630,6 +10585,18 @@ function createSlackCanvasCreateTool(context, state) {
10630
10585
  });
10631
10586
  }
10632
10587
 
10588
+ // src/chat/slack/tools/canvas/context.ts
10589
+ function resolveCanvasTarget(canvas) {
10590
+ const canvasId = extractCanvasId(canvas);
10591
+ if (!canvasId) {
10592
+ return {
10593
+ ok: false,
10594
+ error: "Could not parse a Slack canvas/file ID from input. Provide an F-prefixed ID or a Slack canvas/docs URL."
10595
+ };
10596
+ }
10597
+ return { ok: true, canvasId };
10598
+ }
10599
+
10633
10600
  // src/chat/slack/tools/canvas/edit.ts
10634
10601
  import { z as z42 } from "zod";
10635
10602
  function prepareCanvasEditArguments(input) {
@@ -10697,10 +10664,6 @@ function createSlackCanvasEditTool(state) {
10697
10664
  canvasId: target.canvasId,
10698
10665
  markdown: newContent
10699
10666
  });
10700
- await state.patchArtifactState({
10701
- lastCanvasId: target.canvasId,
10702
- lastCanvasUrl: current.permalink ?? state.artifactState.lastCanvasUrl
10703
- });
10704
10667
  const diff = buildCompactDiff(
10705
10668
  normalizeCanvasMarkdown(baseContent).markdown,
10706
10669
  written.markdown
@@ -10821,10 +10784,6 @@ function createSlackCanvasWriteTool(state) {
10821
10784
  canvasId: target.canvasId,
10822
10785
  markdown: content
10823
10786
  });
10824
- await state.patchArtifactState({
10825
- lastCanvasId: target.canvasId,
10826
- lastCanvasUrl: storedCanvasUrl(state, target.canvasId)
10827
- });
10828
10787
  const response = {
10829
10788
  canvas_id: target.canvasId,
10830
10789
  normalized_heading_count: written.normalizedHeadingCount,
@@ -10909,9 +10868,19 @@ async function createTodoList(name) {
10909
10868
  permalink
10910
10869
  };
10911
10870
  }
10871
+ async function getListColumnMap(listId) {
10872
+ const client = getSlackClient();
10873
+ const response = await withSlackRetries(
10874
+ () => client.files.info({ file: listId }),
10875
+ 3,
10876
+ { action: "files.info", idempotent: true }
10877
+ );
10878
+ const file = response.file;
10879
+ return inferListColumnMap(file?.list_metadata?.schema ?? []);
10880
+ }
10912
10881
  async function addListItems(input) {
10913
10882
  const client = getSlackClient();
10914
- const listColumnMap = input.listColumnMap ?? {};
10883
+ const listColumnMap = input.listColumnMap ?? await getListColumnMap(input.listId);
10915
10884
  if (!listColumnMap.titleColumnId) {
10916
10885
  throw new Error(
10917
10886
  "Cannot add list items because title column could not be inferred"
@@ -10980,19 +10949,20 @@ async function listItems(listId, limit = 100) {
10980
10949
  }
10981
10950
  async function updateListItem(input) {
10982
10951
  const client = getSlackClient();
10952
+ const listColumnMap = Object.keys(input.listColumnMap).length > 0 ? input.listColumnMap : await getListColumnMap(input.listId);
10983
10953
  const cells = [];
10984
- if (typeof input.completed === "boolean" && input.listColumnMap.completedColumnId) {
10954
+ if (typeof input.completed === "boolean" && listColumnMap.completedColumnId) {
10985
10955
  cells.push({
10986
10956
  row_id: input.itemId,
10987
- column_id: input.listColumnMap.completedColumnId,
10957
+ column_id: listColumnMap.completedColumnId,
10988
10958
  checkbox: input.completed
10989
10959
  });
10990
10960
  }
10991
- if (typeof input.title === "string" && input.title.trim() && input.listColumnMap.titleColumnId) {
10961
+ if (typeof input.title === "string" && input.title.trim() && listColumnMap.titleColumnId) {
10992
10962
  cells.push({
10993
10963
  row_id: input.itemId,
10994
10964
  ...richTextField(
10995
- input.listColumnMap.titleColumnId,
10965
+ listColumnMap.titleColumnId,
10996
10966
  input.title
10997
10967
  )
10998
10968
  });
@@ -11022,8 +10992,9 @@ function createSlackListAddItemsTool(state) {
11022
10992
  openWorldHint: true,
11023
10993
  readOnlyHint: false
11024
10994
  },
11025
- description: "Add tasks to the active Slack list tracked in artifact context. Use when the user wants actionable items recorded in the current thread list. Do not use when no list exists and list creation was not requested.",
10995
+ description: "Add tasks to a Slack list. Use the list_id from the list create result or conversation history.",
11026
10996
  inputSchema: z45.object({
10997
+ list_id: z45.string().min(1).describe("ID of the Slack list to update."),
11027
10998
  items: z45.array(z45.string().min(1)).min(1).max(25).describe("List item titles to create."),
11028
10999
  assignee_user_id: slackUserIdParam(
11029
11000
  "Optional Slack user ID assigned to all created items."
@@ -11031,17 +11002,13 @@ function createSlackListAddItemsTool(state) {
11031
11002
  due_date: z45.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Optional due date in YYYY-MM-DD format.").optional()
11032
11003
  }),
11033
11004
  outputSchema: juniorToolOutputSchema,
11034
- execute: async ({ items, assignee_user_id, due_date }) => {
11035
- const targetListId = state.getCurrentListId();
11036
- if (!targetListId) {
11037
- throw new ToolInputError("No active list found in artifact context");
11038
- }
11005
+ execute: async ({ list_id, items, assignee_user_id, due_date }) => {
11039
11006
  const parsedAssigneeUserId = assignee_user_id === void 0 ? void 0 : parseRequiredSlackUserIdParam("assignee_user_id", assignee_user_id);
11040
11007
  if (parsedAssigneeUserId?.ok === false) {
11041
11008
  throw new ToolInputError(parsedAssigneeUserId.error);
11042
11009
  }
11043
11010
  const operationKey = createOperationKey("slackListAddItems", {
11044
- list_id: targetListId,
11011
+ list_id,
11045
11012
  items,
11046
11013
  assignee_user_id: parsedAssigneeUserId?.value ?? null,
11047
11014
  due_date: due_date ?? null
@@ -11054,18 +11021,13 @@ function createSlackListAddItemsTool(state) {
11054
11021
  };
11055
11022
  }
11056
11023
  const result = await addListItems({
11057
- listId: targetListId,
11024
+ listId: list_id,
11058
11025
  titles: items,
11059
- listColumnMap: state.artifactState.listColumnMap,
11060
11026
  assigneeUserId: parsedAssigneeUserId?.value,
11061
11027
  dueDate: due_date
11062
11028
  });
11063
- await state.patchArtifactState({
11064
- lastListId: targetListId,
11065
- listColumnMap: result.listColumnMap
11066
- });
11067
11029
  const response = {
11068
- list_id: targetListId,
11030
+ list_id,
11069
11031
  created_item_ids: result.createdItemIds,
11070
11032
  created_count: result.createdItemIds.length
11071
11033
  };
@@ -11100,11 +11062,6 @@ function createSlackListCreateTool(state) {
11100
11062
  };
11101
11063
  }
11102
11064
  const list = await createTodoList(name);
11103
- await state.patchArtifactState({
11104
- lastListId: list.listId,
11105
- lastListUrl: list.permalink,
11106
- listColumnMap: list.listColumnMap
11107
- });
11108
11065
  const response = {
11109
11066
  list_id: list.listId,
11110
11067
  permalink: list.permalink,
@@ -11118,9 +11075,9 @@ function createSlackListCreateTool(state) {
11118
11075
 
11119
11076
  // src/chat/slack/tools/list/get-items.ts
11120
11077
  import { z as z47 } from "zod";
11121
- function createSlackListGetItemsTool(state) {
11078
+ function createSlackListGetItemsTool() {
11122
11079
  return zodTool({
11123
- description: "Read items from the active Slack list tracked in artifact context. Use when the user asks for task status, open items, or list contents. Do not use when list state is already known from the immediately prior result.",
11080
+ description: "Read items from a Slack list. Use the list_id from a prior tool result or conversation history.",
11124
11081
  annotations: {
11125
11082
  destructiveHint: false,
11126
11083
  idempotentHint: true,
@@ -11128,18 +11085,15 @@ function createSlackListGetItemsTool(state) {
11128
11085
  readOnlyHint: true
11129
11086
  },
11130
11087
  inputSchema: z47.object({
11088
+ list_id: z47.string().min(1).describe("ID of the Slack list to read."),
11131
11089
  limit: z47.coerce.number().int().min(1).max(200).describe("Maximum number of list items to return.").optional()
11132
11090
  }),
11133
11091
  outputSchema: juniorToolOutputSchema,
11134
- execute: async ({ limit }) => {
11135
- const targetListId = state.getCurrentListId();
11092
+ execute: async ({ list_id, limit }) => {
11136
11093
  const resolvedLimit = limit ?? 100;
11137
- if (!targetListId) {
11138
- throw new ToolInputError("No active list found in artifact context");
11139
- }
11140
- const items = await listItems(targetListId, resolvedLimit);
11094
+ const items = await listItems(list_id, resolvedLimit);
11141
11095
  return {
11142
- list_id: targetListId,
11096
+ list_id,
11143
11097
  items: items.map((item) => ({ id: item.id, fields: item.fields }))
11144
11098
  };
11145
11099
  }
@@ -11154,11 +11108,13 @@ var booleanInput3 = (description) => z48.preprocess(
11154
11108
  ).describe(description);
11155
11109
  var updateListItemInputSchema = z48.union([
11156
11110
  z48.object({
11111
+ list_id: z48.string().min(1).describe("ID of the Slack list to update."),
11157
11112
  item_id: z48.string().min(1).describe("ID of the Slack list item to update."),
11158
11113
  completed: booleanInput3("Optional completion status update."),
11159
11114
  title: z48.string().min(1).describe("Optional new item title.").optional()
11160
11115
  }),
11161
11116
  z48.object({
11117
+ list_id: z48.string().min(1).describe("ID of the Slack list to update."),
11162
11118
  item_id: z48.string().min(1).describe("ID of the Slack list item to update."),
11163
11119
  completed: booleanInput3("Optional completion status update.").optional(),
11164
11120
  title: z48.string().min(1).describe("Optional new item title.")
@@ -11172,16 +11128,12 @@ function createSlackListUpdateItemTool(state) {
11172
11128
  openWorldHint: true,
11173
11129
  readOnlyHint: false
11174
11130
  },
11175
- description: "Update an item in the active Slack list tracked in artifact context (title/completion). Use when the user asks to mark progress or rename a tracked task. Do not use to add new tasks.",
11131
+ description: "Update an item in a Slack list. Use list_id and item_id from prior tool results or conversation history.",
11176
11132
  inputSchema: updateListItemInputSchema,
11177
11133
  outputSchema: juniorToolOutputSchema,
11178
- execute: async ({ item_id, completed, title }) => {
11179
- const targetListId = state.getCurrentListId();
11180
- if (!targetListId) {
11181
- throw new ToolInputError("No active list found in artifact context");
11182
- }
11134
+ execute: async ({ list_id, item_id, completed, title }) => {
11183
11135
  const operationKey = createOperationKey("slackListUpdateItem", {
11184
- list_id: targetListId,
11136
+ list_id,
11185
11137
  item_id,
11186
11138
  completed: completed ?? null,
11187
11139
  title: title ?? null
@@ -11194,15 +11146,14 @@ function createSlackListUpdateItemTool(state) {
11194
11146
  };
11195
11147
  }
11196
11148
  await updateListItem({
11197
- listId: targetListId,
11149
+ listId: list_id,
11198
11150
  itemId: item_id,
11199
11151
  completed,
11200
11152
  title,
11201
- listColumnMap: state.artifactState.listColumnMap ?? {}
11153
+ listColumnMap: {}
11202
11154
  });
11203
- await state.patchArtifactState({ lastListId: targetListId });
11204
11155
  const response = {
11205
- list_id: targetListId,
11156
+ list_id,
11206
11157
  item_id,
11207
11158
  completed,
11208
11159
  title
@@ -11294,7 +11245,100 @@ function parseSlackMessageReference(input) {
11294
11245
  };
11295
11246
  }
11296
11247
 
11297
- // src/chat/slack/legacy-attachments.ts
11248
+ // src/chat/slack/message/blocks.ts
11249
+ var MAX_BLOCKS = 50;
11250
+ var MAX_CHILDREN = 50;
11251
+ var MAX_DEPTH = 16;
11252
+ var MAX_NODES = 5e3;
11253
+ var CHILD_KEYS = [
11254
+ "blocks",
11255
+ "elements",
11256
+ "fields",
11257
+ "accessory",
11258
+ "element",
11259
+ "rows",
11260
+ "cells"
11261
+ ];
11262
+ function toText(value) {
11263
+ return typeof value === "string" && value.length > 0 ? value : void 0;
11264
+ }
11265
+ function readText(value) {
11266
+ if (typeof value === "string") return toText(value);
11267
+ if (!value || typeof value !== "object") return void 0;
11268
+ return toText(value.text);
11269
+ }
11270
+ function parseChildren(value, budget, depth) {
11271
+ if (Array.isArray(value)) {
11272
+ return value.slice(0, MAX_CHILDREN).flatMap((child) => parseChildren(child, budget, depth));
11273
+ }
11274
+ return parseElement(value, budget, depth);
11275
+ }
11276
+ function parseElement(value, budget, depth) {
11277
+ if (!value || typeof value !== "object" || depth > MAX_DEPTH || budget.remainingNodes <= 0) {
11278
+ return [];
11279
+ }
11280
+ budget.remainingNodes -= 1;
11281
+ const element = value;
11282
+ const type = toText(element.type);
11283
+ const text = readText(element.text);
11284
+ if (type === "link") {
11285
+ const url = toText(element.url);
11286
+ return [
11287
+ text && url && text !== url ? `${text} (${url})` : text || url
11288
+ ].filter((part) => Boolean(part));
11289
+ }
11290
+ if (type === "button") {
11291
+ const url = toText(element.url);
11292
+ return [text && url ? `${text} (${url})` : text].filter(
11293
+ (part) => Boolean(part)
11294
+ );
11295
+ }
11296
+ if (type === "emoji") {
11297
+ const name = toText(element.name);
11298
+ return name ? [`:${name}:`] : [];
11299
+ }
11300
+ if (type === "user") {
11301
+ const userId = toText(element.user_id);
11302
+ return userId ? [`<@${userId}>`] : [];
11303
+ }
11304
+ if (type === "channel") {
11305
+ const channelId = toText(element.channel_id);
11306
+ return channelId ? [`<#${channelId}>`] : [];
11307
+ }
11308
+ if (type === "usergroup") {
11309
+ const usergroupId = toText(element.usergroup_id);
11310
+ return usergroupId ? [`<!subteam^${usergroupId}>`] : [];
11311
+ }
11312
+ if (type === "broadcast") {
11313
+ const range = toText(element.range);
11314
+ return range ? [`<!${range}>`] : [];
11315
+ }
11316
+ const parts = [
11317
+ text,
11318
+ readText(element.title),
11319
+ readText(element.description),
11320
+ readText(element.label),
11321
+ readText(element.hint),
11322
+ readText(element.placeholder),
11323
+ toText(element.alt_text),
11324
+ toText(element.provider_name),
11325
+ toText(element.fallback)
11326
+ ].filter((part) => Boolean(part));
11327
+ for (const key of CHILD_KEYS) {
11328
+ parts.push(...parseChildren(element[key], budget, depth + 1));
11329
+ }
11330
+ if (type === "checkboxes" || type === "radio_buttons") {
11331
+ parts.push(...parseChildren(element.options, budget, depth + 1));
11332
+ }
11333
+ return parts;
11334
+ }
11335
+ function renderBlockText(value) {
11336
+ if (!Array.isArray(value)) return "";
11337
+ const budget = { remainingNodes: MAX_NODES };
11338
+ return value.slice(0, MAX_BLOCKS).flatMap((block) => parseElement(block, budget, 0)).join("\n");
11339
+ }
11340
+
11341
+ // src/chat/slack/message/attachments.ts
11298
11342
  var MAX_ATTACHMENTS = 10;
11299
11343
  var MAX_FIELDS_PER_ATTACHMENT = 20;
11300
11344
  var MAX_FIELD_CHARS = 1e3;
@@ -11332,6 +11376,7 @@ function renderAttachment(raw) {
11332
11376
  const text = toStr(obj.text);
11333
11377
  const footer = toStr(obj.footer);
11334
11378
  const fields = Array.isArray(obj.fields) ? obj.fields : [];
11379
+ const blockText = renderBlockText(obj.blocks);
11335
11380
  const add = (value) => {
11336
11381
  if (!value) return;
11337
11382
  const normalized = normalizeAttachmentText(value);
@@ -11339,7 +11384,7 @@ function renderAttachment(raw) {
11339
11384
  seen.add(normalized);
11340
11385
  parts.push(normalized);
11341
11386
  };
11342
- const hasRichContent = pretext || title || text;
11387
+ const hasRichContent = pretext || title || text || blockText;
11343
11388
  if (!hasRichContent) {
11344
11389
  add(fallback);
11345
11390
  }
@@ -11355,28 +11400,19 @@ function renderAttachment(raw) {
11355
11400
  for (const field of fields.slice(0, MAX_FIELDS_PER_ATTACHMENT)) {
11356
11401
  add(renderField(field));
11357
11402
  }
11403
+ add(blockText);
11358
11404
  add(footer);
11359
11405
  return parts.join("\n");
11360
11406
  }
11361
- function renderSlackLegacyAttachmentText(input) {
11407
+ function renderAttachmentText(input) {
11362
11408
  const rendered = getAttachmentPayload(input).slice(0, MAX_ATTACHMENTS).map(renderAttachment).filter((line) => line.length > 0).map((line) => `[attachment] ${line}`).join("\n");
11363
11409
  return rendered.slice(0, MAX_ATTACHMENT_TEXT_CHARS);
11364
11410
  }
11365
- function appendSlackLegacyAttachmentText(baseText, rawMessageOrAttachments) {
11366
- const base = baseText?.trim() ?? "";
11367
- const attachmentText = renderSlackLegacyAttachmentText(
11368
- rawMessageOrAttachments
11369
- );
11370
- if (!attachmentText) return base;
11371
- if (!base) return attachmentText;
11372
- return `${base}
11373
- ${attachmentText}`;
11374
- }
11375
11411
 
11376
11412
  // src/chat/slack/tools/thread-read.ts
11377
11413
  var MAX_THREAD_READ_CHARS = 4e4;
11378
11414
  function sanitizeMessage(msg) {
11379
- const attachmentText = renderSlackLegacyAttachmentText(msg.attachments);
11415
+ const attachmentText = renderAttachmentText(msg.attachments);
11380
11416
  return {
11381
11417
  ts: msg.ts,
11382
11418
  user: msg.user,
@@ -11517,168 +11553,152 @@ function createSlackThreadReadTool(context, deps = {}) {
11517
11553
  });
11518
11554
  }
11519
11555
 
11520
- // src/chat/slack/users.ts
11521
- function normalizeUser(raw) {
11522
- const rawFields = raw.profile?.fields;
11523
- const profileFields = [];
11524
- if (rawFields && typeof rawFields === "object") {
11525
- for (const [id, field] of Object.entries(rawFields)) {
11526
- if (!field) continue;
11527
- profileFields.push({
11528
- id,
11529
- label: field.label || void 0,
11530
- value: field.value || void 0,
11531
- alt: field.alt || void 0
11532
- });
11533
- }
11534
- }
11535
- return {
11536
- id: raw.id ?? "",
11537
- team_id: raw.team_id || void 0,
11538
- name: raw.name || void 0,
11539
- real_name: raw.real_name || raw.profile?.real_name || void 0,
11540
- display_name: raw.profile?.display_name || void 0,
11541
- title: raw.profile?.title || void 0,
11542
- email: raw.profile?.email || void 0,
11543
- status_text: raw.profile?.status_text ?? void 0,
11544
- status_emoji: raw.profile?.status_emoji ?? void 0,
11545
- is_bot: raw.is_bot ?? false,
11546
- is_deleted: raw.deleted ?? false,
11547
- timezone: raw.tz || void 0,
11548
- ...profileFields.length > 0 ? { profile_fields: profileFields } : {}
11549
- };
11550
- }
11551
- async function lookupSlackUserProfile(userId) {
11552
- const client = getSlackClient();
11553
- const result = await withSlackRetries(
11554
- () => client.users.info({ user: userId }),
11555
- 3,
11556
- { action: "users.info" }
11557
- );
11558
- const user = result.user;
11559
- if (!user) {
11560
- throw new Error(`Slack users.info returned no user for ${userId}`);
11561
- }
11562
- return normalizeUser(user);
11563
- }
11564
- async function lookupSlackUserByEmail(email) {
11565
- const client = getSlackClient();
11566
- let result;
11567
- try {
11568
- result = await withSlackRetries(
11569
- () => client.users.lookupByEmail({ email }),
11570
- 3,
11571
- { action: "users.lookupByEmail" }
11572
- );
11573
- } catch (error) {
11574
- const apiError = error.apiError;
11575
- if (apiError === "users_not_found") {
11576
- return null;
11577
- }
11578
- throw error;
11579
- }
11580
- const user = result.user;
11581
- if (!user) {
11582
- return null;
11583
- }
11584
- return normalizeUser(user);
11585
- }
11586
- function scoreMatch(user, queryLower) {
11587
- const name = (user.name ?? "").toLowerCase();
11588
- const realName = (user.real_name ?? user.profile?.real_name ?? "").toLowerCase();
11589
- const displayName = (user.profile?.display_name ?? "").toLowerCase();
11590
- if (name === queryLower || displayName === queryLower) return 100;
11591
- if (realName === queryLower) return 90;
11592
- if (name.startsWith(queryLower) || displayName.startsWith(queryLower))
11593
- return 70;
11594
- if (realName.startsWith(queryLower)) return 60;
11595
- const realNameWords = realName.split(/\s+/);
11596
- if (realNameWords.some((w) => w === queryLower)) return 55;
11597
- if (realNameWords.some((w) => w.startsWith(queryLower))) return 50;
11598
- if (name.includes(queryLower) || displayName.includes(queryLower)) return 30;
11599
- if (realName.includes(queryLower)) return 20;
11600
- return 0;
11601
- }
11602
- async function searchSlackUsers(options) {
11603
- const {
11604
- query,
11605
- limit = 10,
11606
- maxPages = 3,
11607
- includeDeleted = false,
11608
- includeBots = false
11609
- } = options;
11610
- const queryLower = query.toLowerCase().trim();
11611
- const client = getSlackClient();
11612
- const matches = [];
11613
- let cursor;
11614
- let pages = 0;
11615
- let totalScanned = 0;
11616
- let truncated = false;
11617
- while (pages < maxPages) {
11618
- pages++;
11619
- const result = await withSlackRetries(
11620
- () => client.users.list({
11621
- limit: 200,
11622
- ...cursor ? { cursor } : {}
11623
- }),
11624
- 3,
11625
- { action: "users.list" }
11626
- );
11627
- const members = result.members ?? [];
11628
- totalScanned += members.length;
11629
- for (const member of members) {
11630
- if (!includeDeleted && member.deleted) continue;
11631
- if (!includeBots && member.is_bot) continue;
11632
- if (member.id === "USLACKBOT") continue;
11633
- const score = scoreMatch(member, queryLower);
11634
- if (score > 0) {
11635
- matches.push({ user: member, score });
11636
- }
11637
- }
11638
- const nextCursor = result.response_metadata?.next_cursor;
11639
- if (!nextCursor) {
11640
- break;
11641
- }
11642
- cursor = nextCursor;
11643
- }
11644
- if (pages >= maxPages && cursor) {
11645
- truncated = true;
11646
- }
11647
- matches.sort((a, b) => {
11648
- if (b.score !== a.score) return b.score - a.score;
11649
- return (a.user.name ?? "").localeCompare(b.user.name ?? "");
11650
- });
11651
- return {
11652
- users: matches.slice(0, limit).map((m) => normalizeUser(m.user)),
11653
- searched_pages: pages,
11654
- searched_user_count: totalScanned,
11655
- truncated
11656
- };
11657
- }
11658
-
11659
- // src/chat/slack/tools/user-lookup.ts
11556
+ // src/chat/tools/user-lookup.ts
11557
+ import { and, eq, or, sql } from "drizzle-orm";
11558
+ import { alias } from "drizzle-orm/pg-core";
11660
11559
  import { z as z50 } from "zod";
11560
+ var linkedSlackIdentity = alias(juniorIdentities, "user_lookup_slack_identity");
11661
11561
  function explicitUserLookupError(error) {
11662
- if (error.apiError === "user_not_found") {
11562
+ if (error.apiError === "user_not_found" || error.code === "not_found") {
11663
11563
  return "No Slack user found for the supplied user ID.";
11664
11564
  }
11665
11565
  if (error.code === "missing_scope") {
11666
- return error.needed ? `Slack user lookup is unavailable because this installation is missing the \`${error.needed}\` scope.` : "Slack user lookup is unavailable because this installation is missing a required Slack scope.";
11667
- }
11668
- if (error.code === "not_found") {
11669
- return "No Slack user found for the supplied user ID.";
11566
+ return error.needed ? `User lookup is unavailable because this installation is missing the \`${error.needed}\` scope.` : "User lookup is unavailable because this installation is missing a required Slack scope.";
11670
11567
  }
11671
11568
  if (error.code === "invalid_arguments") {
11672
11569
  return `Slack rejected the user lookup arguments (${error.apiError ?? error.code}).`;
11673
11570
  }
11674
11571
  if (error.code === "feature_unavailable") {
11675
- return "Slack user lookup is not available for this workspace or app installation.";
11572
+ return "User lookup is not available for this workspace or app installation.";
11676
11573
  }
11677
11574
  return void 0;
11678
11575
  }
11679
- function createSlackUserLookupTool() {
11576
+ function slackMention(userId) {
11577
+ return `<@${userId}>`;
11578
+ }
11579
+ function asMatch(user) {
11580
+ return { ...user, mention: slackMention(user.id) };
11581
+ }
11582
+ function lookupResult(args) {
11583
+ const users = args.users.map(asMatch);
11584
+ if (users.length === 1) {
11585
+ return {
11586
+ provider: args.provider,
11587
+ query: args.query,
11588
+ count: 1,
11589
+ mention: users[0].mention,
11590
+ user: users[0],
11591
+ ...args.search
11592
+ };
11593
+ }
11594
+ return {
11595
+ provider: args.provider,
11596
+ query: args.query,
11597
+ count: users.length,
11598
+ users,
11599
+ ...args.search
11600
+ };
11601
+ }
11602
+ function slackProfileFromIdentity(identity) {
11603
+ return {
11604
+ id: identity.providerSubjectId,
11605
+ name: identity.handle ?? void 0,
11606
+ real_name: identity.displayName ?? void 0,
11607
+ display_name: identity.displayName ?? void 0,
11608
+ email: identity.email ?? void 0,
11609
+ is_bot: false,
11610
+ is_deleted: false
11611
+ };
11612
+ }
11613
+ function slackMentionProfileFromIdentity(identity) {
11614
+ return {
11615
+ id: identity.providerSubjectId,
11616
+ name: identity.handle ?? void 0
11617
+ };
11618
+ }
11619
+ async function storedSlackUserByEmail(teamId, email) {
11620
+ const emailNormalized = normalizeIdentityEmail(email);
11621
+ if (!emailNormalized) return void 0;
11622
+ const identities = await getSqlExecutor().db().select().from(juniorIdentities).where(
11623
+ and(
11624
+ eq(juniorIdentities.provider, "slack"),
11625
+ eq(juniorIdentities.providerTenantId, teamId),
11626
+ eq(juniorIdentities.kind, "user"),
11627
+ eq(juniorIdentities.emailVerified, true),
11628
+ eq(juniorIdentities.emailNormalized, emailNormalized)
11629
+ )
11630
+ ).limit(2);
11631
+ if (identities.length > 1) {
11632
+ throw new Error(
11633
+ `Multiple Slack users share verified email ${emailNormalized} in workspace ${teamId}`
11634
+ );
11635
+ }
11636
+ return identities[0] ? slackProfileFromIdentity(identities[0]) : void 0;
11637
+ }
11638
+ function looksLikeEmail(query) {
11639
+ return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(query);
11640
+ }
11641
+ async function resolveSlack(teamId, query) {
11642
+ const userId = parseSlackUserId(query);
11643
+ if (userId) {
11644
+ const user = await lookupSlackUserProfile(userId);
11645
+ return lookupResult({ provider: "slack", query, users: [user] });
11646
+ }
11647
+ if (looksLikeEmail(query)) {
11648
+ const stored = await storedSlackUserByEmail(teamId, query);
11649
+ if (stored) {
11650
+ return lookupResult({ provider: "slack", query, users: [stored] });
11651
+ }
11652
+ const profile = await lookupSlackUserByEmail(query);
11653
+ if (!profile) {
11654
+ throw new ToolInputError(
11655
+ `No Slack user found with email address ${query}.`
11656
+ );
11657
+ }
11658
+ return lookupResult({ provider: "slack", query, users: [profile] });
11659
+ }
11660
+ const result = await searchSlackUsers({
11661
+ query,
11662
+ limit: 10,
11663
+ maxPages: 3,
11664
+ includeBots: false
11665
+ });
11666
+ return lookupResult({
11667
+ provider: "slack",
11668
+ query,
11669
+ users: result.users,
11670
+ search: {
11671
+ searched_pages: result.searched_pages,
11672
+ searched_user_count: result.searched_user_count,
11673
+ truncated: result.truncated
11674
+ }
11675
+ });
11676
+ }
11677
+ async function resolveStoredProvider(teamId, provider, query) {
11678
+ const rows = await getSqlExecutor().db().select({ slack: linkedSlackIdentity }).from(juniorIdentities).innerJoin(
11679
+ linkedSlackIdentity,
11680
+ and(
11681
+ eq(linkedSlackIdentity.userId, juniorIdentities.userId),
11682
+ eq(linkedSlackIdentity.kind, "user"),
11683
+ eq(linkedSlackIdentity.provider, "slack"),
11684
+ eq(linkedSlackIdentity.providerTenantId, teamId)
11685
+ )
11686
+ ).where(
11687
+ and(
11688
+ eq(juniorIdentities.kind, "user"),
11689
+ eq(juniorIdentities.provider, provider),
11690
+ or(
11691
+ eq(juniorIdentities.providerSubjectId, query),
11692
+ sql`lower(${juniorIdentities.handle}) = lower(${query})`
11693
+ )
11694
+ )
11695
+ ).limit(11);
11696
+ const users = rows.slice(0, 10).map((row) => slackMentionProfileFromIdentity(row.slack));
11697
+ return lookupResult({ provider, query, users });
11698
+ }
11699
+ function createUserLookupTool(teamId, providers) {
11680
11700
  return zodTool({
11681
- description: "Look up Slack user profiles by user ID, email, or name search. Set mode to match the identifier in value. Returns profile fields including title, status, and custom fields.",
11701
+ description: "Look up people by identity provider and query. Pass an enabled `provider` and its provider subject ID or handle. The `slack` provider also accepts email and name searches. Returns Slack `mention` values (`<@U\u2026>`) for the current workspace. Use a mention only when one person clearly matches; otherwise ask which person the user means.",
11682
11702
  annotations: {
11683
11703
  destructiveHint: false,
11684
11704
  idempotentHint: true,
@@ -11686,53 +11706,13 @@ function createSlackUserLookupTool() {
11686
11706
  readOnlyHint: true
11687
11707
  },
11688
11708
  inputSchema: z50.object({
11689
- mode: z50.enum(["user_id", "email", "query"]).describe(
11690
- "Lookup method: user_id for Slack IDs, email for email addresses, or query for name searches."
11691
- ),
11692
- value: z50.string().trim().min(2).describe(
11693
- "The Slack user ID, email address, or name to look up, interpreted according to mode."
11694
- )
11709
+ provider: z50.enum(providers).describe("Enabled identity provider to query."),
11710
+ query: z50.string().trim().min(1).describe("Provider subject ID, handle, Slack email, or Slack name.")
11695
11711
  }).strict(),
11696
11712
  outputSchema: juniorToolOutputSchema,
11697
- execute: async ({ mode, value }) => {
11713
+ execute: async ({ provider, query }) => {
11698
11714
  try {
11699
- if (mode === "user_id") {
11700
- const parsedUserId = parseRequiredSlackUserIdParam("value", value);
11701
- if (!parsedUserId.ok) {
11702
- throw new ToolInputError(parsedUserId.error);
11703
- }
11704
- return {
11705
- mode: "user_id",
11706
- user: await lookupSlackUserProfile(parsedUserId.value)
11707
- };
11708
- }
11709
- if (mode === "email") {
11710
- const profile = await lookupSlackUserByEmail(value);
11711
- if (!profile) {
11712
- throw new ToolInputError(
11713
- `No Slack user found with email address ${value}.`
11714
- );
11715
- }
11716
- return {
11717
- mode: "email",
11718
- user: profile
11719
- };
11720
- }
11721
- const result = await searchSlackUsers({
11722
- query: value,
11723
- limit: 10,
11724
- maxPages: 3,
11725
- includeBots: false
11726
- });
11727
- return {
11728
- mode: "query",
11729
- query: value,
11730
- count: result.users.length,
11731
- searched_pages: result.searched_pages,
11732
- searched_user_count: result.searched_user_count,
11733
- truncated: result.truncated,
11734
- users: result.users
11735
- };
11715
+ return provider === "slack" ? await resolveSlack(teamId, query) : await resolveStoredProvider(teamId, provider, query);
11736
11716
  } catch (error) {
11737
11717
  if (error instanceof SlackActionError) {
11738
11718
  const message = explicitUserLookupError(error);
@@ -11837,7 +11817,7 @@ function getTimeZoneOffsetMinutes(timestampMs, timezone) {
11837
11817
  return Math.round((timestampMs - asUtcMs) / 6e4);
11838
11818
  }
11839
11819
 
11840
- // src/chat/tools/query-conversation-events.ts
11820
+ // src/chat/tools/search-conversation-events.ts
11841
11821
  import { z as z52 } from "zod";
11842
11822
  var DEFAULT_LIMIT3 = 25;
11843
11823
  var MAX_LIMIT = 100;
@@ -11845,40 +11825,26 @@ var MAX_EVENT_DATA_BYTES = 4e3;
11845
11825
  var MAX_EVENTS_JSON_BYTES = 2e4;
11846
11826
  var MAX_IDENTITY_CHARS = 256;
11847
11827
  var textEncoder = new TextEncoder();
11848
- var CONVERSATION_EVENTS_TOOL_SOURCE = {
11849
- id: "conversation-events",
11850
- description: "Inspect Junior's durable conversation event log for debugging runtime behavior."
11851
- };
11852
11828
  var knownEventTypeSchema = z52.enum(KNOWN_CONVERSATION_EVENT_TYPES);
11853
11829
  var projectedEventSchema = z52.object({
11854
- seq: z52.number().int().nonnegative().describe("Stable event position; use it for pagination bounds."),
11855
- history_version: z52.number().int().nonnegative().describe(
11856
- "Model-history generation. It increments when handoff or compaction replaces active model context."
11857
- ),
11830
+ seq: z52.number().int().nonnegative().describe("Stable event position for pagination."),
11831
+ history_version: z52.number().int().nonnegative().describe("Agent history generation after replacement."),
11858
11832
  created_at: z52.iso.datetime().describe("When the event was recorded."),
11859
- idempotency_key: z52.string().min(1).optional().describe("Retry-stable event identity, when one was assigned."),
11860
- data: z52.record(z52.string(), z52.unknown()).describe(
11861
- "Event data. Oversized payloads are replaced by identifying fields, payload_omitted, and payload_json_bytes."
11862
- )
11833
+ idempotency_key: z52.string().min(1).optional().describe("Retry-stable event identity, when assigned."),
11834
+ data: z52.record(z52.string(), z52.unknown()).describe("Bounded event data.")
11863
11835
  }).strict();
11864
- var queryConversationEventsOutputSchema = juniorToolOutputSchema.extend({
11836
+ var searchConversationEventsOutputSchema = juniorToolOutputSchema.extend({
11865
11837
  conversation_id: z52.string().min(1),
11866
11838
  events: z52.array(projectedEventSchema),
11867
- has_older: z52.boolean().describe(
11868
- "Whether matching events exist before this page; request them with before_seq set to the first returned seq."
11869
- ),
11870
- has_newer: z52.boolean().describe(
11871
- "Whether matching events exist after this page; request them with after_seq set to the last returned seq."
11872
- ),
11873
- omitted_event_count: z52.number().int().nonnegative().optional().describe(
11874
- "Fetched events omitted to keep this response bounded. Continue with the pagination cursor for the omitted direction."
11875
- )
11839
+ has_older: z52.boolean().describe("Whether matching older events exist."),
11840
+ has_newer: z52.boolean().describe("Whether matching newer events exist."),
11841
+ omitted_event_count: z52.number().int().nonnegative().optional().describe("Events omitted by the response byte limit.")
11876
11842
  });
11877
- function createQueryConversationEventsTool(context) {
11843
+ function createSearchConversationEventsTool(context) {
11878
11844
  return zodTool({
11879
- description: "Inspect Junior's stored turns, tool calls, handoffs, and compaction events when debugging its behavior. Returns events from the current conversation tree or another retained public conversation in the same Slack workspace, newest first by default.",
11845
+ description: "Search the durable event log for one conversation, including messages, agent history, tool results, handoffs, and compactions. Defaults to the current conversation. Outside the current conversation tree, only retained public conversations in the current Slack workspace are accessible.",
11880
11846
  exposure: "deferred",
11881
- source: CONVERSATION_EVENTS_TOOL_SOURCE,
11847
+ source: CONVERSATIONS_TOOL_SOURCE,
11882
11848
  annotations: {
11883
11849
  destructiveHint: false,
11884
11850
  idempotentHint: true,
@@ -11886,31 +11852,25 @@ function createQueryConversationEventsTool(context) {
11886
11852
  readOnlyHint: true
11887
11853
  },
11888
11854
  inputSchema: z52.object({
11889
- conversation_id: z52.string().trim().min(1).describe(
11890
- "Conversation ID to inspect, such as slack:{channelId}:{threadTs} or a child conversation id."
11891
- ),
11892
- after_seq: z52.number().int().nonnegative().nullable().describe(
11893
- "Exclusive lower bound on event seq. When set, returns the next newer page in ascending order."
11894
- ).optional(),
11895
- before_seq: z52.number().int().nonnegative().nullable().describe(
11896
- "Exclusive upper bound on event seq. Combine with defaults or after_seq to page older or bounded ranges."
11855
+ conversation_id: z52.string().trim().min(1).nullable().describe(
11856
+ "Conversation ID to search. Omit or null for the current conversation."
11897
11857
  ).optional(),
11858
+ after_seq: z52.number().int().nonnegative().nullable().describe("Exclusive event sequence lower bound; returns ascending.").optional(),
11859
+ before_seq: z52.number().int().nonnegative().nullable().describe("Exclusive event sequence upper bound.").optional(),
11898
11860
  limit: z52.number().int().min(1).max(MAX_LIMIT).nullable().describe(
11899
- `Maximum events to return. Defaults to ${DEFAULT_LIMIT3}; max ${MAX_LIMIT}.`
11861
+ `Maximum events. Default ${DEFAULT_LIMIT3}; max ${MAX_LIMIT}.`
11900
11862
  ).optional(),
11901
- types: z52.array(knownEventTypeSchema).min(1).nullable().describe(
11902
- "Optional event-type filter. Omit to return every durable event type."
11903
- ).optional()
11863
+ types: z52.array(knownEventTypeSchema).min(1).nullable().describe("Event types to include; omit for all types.").optional()
11904
11864
  }).strict(),
11905
- outputSchema: queryConversationEventsOutputSchema,
11865
+ outputSchema: searchConversationEventsOutputSchema,
11906
11866
  execute: async (input) => {
11907
11867
  const currentConversationId = context.conversationId?.trim();
11908
11868
  if (!currentConversationId) {
11909
11869
  throw new ToolInputError(
11910
- "queryConversationEvents requires an active conversation"
11870
+ "searchConversationEvents requires an active conversation"
11911
11871
  );
11912
11872
  }
11913
- const conversationId = input.conversation_id;
11873
+ const conversationId = input.conversation_id?.trim() || currentConversationId;
11914
11874
  const afterSeq = input.after_seq ?? void 0;
11915
11875
  const beforeSeq = input.before_seq ?? void 0;
11916
11876
  const limit = input.limit ?? DEFAULT_LIMIT3;
@@ -11943,7 +11903,7 @@ function createQueryConversationEventsTool(context) {
11943
11903
  const targetRoot = targetRootConversationId === conversationId ? target : await conversationStore.get({
11944
11904
  conversationId: targetRootConversationId
11945
11905
  });
11946
- assertCanQueryConversationEvents({
11906
+ assertCanSearchConversationEvents({
11947
11907
  accessScope,
11948
11908
  targetConversationId: conversationId,
11949
11909
  targetRootConversationId,
@@ -12021,7 +11981,7 @@ async function resolveRootConversationId(conversationStore, conversationId, pare
12021
11981
  }
12022
11982
  return conversationId;
12023
11983
  }
12024
- function assertCanQueryConversationEvents(args) {
11984
+ function assertCanSearchConversationEvents(args) {
12025
11985
  const {
12026
11986
  accessScope,
12027
11987
  targetConversationId,
@@ -12785,28 +12745,9 @@ function createWriteFileTool() {
12785
12745
  }
12786
12746
 
12787
12747
  // src/chat/tools/index.ts
12788
- function createToolState(hooks, context) {
12748
+ function createToolState() {
12789
12749
  const operationResultCache = /* @__PURE__ */ new Map();
12790
- const artifactState = {
12791
- ...context.artifactState ?? {},
12792
- listColumnMap: {
12793
- ...context.artifactState?.listColumnMap ?? {}
12794
- }
12795
- };
12796
- const patchArtifactState = async (patch) => {
12797
- Object.assign(artifactState, patch);
12798
- if (patch.listColumnMap) {
12799
- artifactState.listColumnMap = {
12800
- ...artifactState.listColumnMap ?? {},
12801
- ...patch.listColumnMap
12802
- };
12803
- }
12804
- await hooks.onArtifactStatePatch?.(patch);
12805
- };
12806
12750
  return {
12807
- artifactState,
12808
- patchArtifactState,
12809
- getCurrentListId: () => artifactState.lastListId,
12810
12751
  getOperationResult: (operationKey) => operationResultCache.get(operationKey),
12811
12752
  setOperationResult: (operationKey, result) => {
12812
12753
  operationResultCache.set(operationKey, result);
@@ -12814,7 +12755,7 @@ function createToolState(hooks, context) {
12814
12755
  };
12815
12756
  }
12816
12757
  function createTools(availableSkills, hooks = {}, context, options = {}) {
12817
- const state = createToolState(hooks, context);
12758
+ const state = createToolState();
12818
12759
  const slackContext = getSlackToolContext(context);
12819
12760
  const slackSourceCapabilities = slackContext ? resolveChannelCapabilities(slackContext.sourceChannelId) : void 0;
12820
12761
  const canSendFilesToActiveConversation = Boolean(
@@ -12848,7 +12789,7 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
12848
12789
  ...createScheduledTaskTools(context)
12849
12790
  };
12850
12791
  if (context.conversationId) {
12851
- tools.queryConversationEvents = createQueryConversationEventsTool(context);
12792
+ tools.searchConversationEvents = createSearchConversationEventsTool(context);
12852
12793
  }
12853
12794
  if (context.supportsImageInput) {
12854
12795
  tools.viewImage = createViewImageTool(
@@ -12885,7 +12826,7 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
12885
12826
  tools.slackCanvasWrite = createSlackCanvasWriteTool(state);
12886
12827
  tools.slackThreadRead = createSlackThreadReadTool(slackContext);
12887
12828
  if (context.conversationId && slackContext.source.visibility === "public") {
12888
- tools.searchConversationHistory = createSlackConversationSearchTool(
12829
+ tools.searchConversationMessages = createSlackConversationMessageSearchTool(
12889
12830
  {
12890
12831
  kind: "public_provider_tenant",
12891
12832
  provider: "slack",
@@ -12899,10 +12840,17 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
12899
12840
  context.slackActionToken
12900
12841
  );
12901
12842
  }
12902
- tools.slackUserLookup = createSlackUserLookupTool();
12843
+ const identityProviders = [
12844
+ "slack",
12845
+ ...getOAuthAccountProviders().filter((provider) => provider !== "slack")
12846
+ ];
12847
+ tools.userLookup = createUserLookupTool(
12848
+ slackContext.teamId,
12849
+ identityProviders
12850
+ );
12903
12851
  tools.slackListCreate = createSlackListCreateTool(state);
12904
12852
  tools.slackListAddItems = createSlackListAddItemsTool(state);
12905
- tools.slackListGetItems = createSlackListGetItemsTool(state);
12853
+ tools.slackListGetItems = createSlackListGetItemsTool();
12906
12854
  tools.slackListUpdateItem = createSlackListUpdateItemTool(state);
12907
12855
  const outputChannelId = slackContext.destinationChannelId;
12908
12856
  const outputCapabilities = outputChannelId ? resolveChannelCapabilities(outputChannelId) : void 0;
@@ -13544,6 +13492,46 @@ var SEARCH_TOOLS_NAME = "searchTools";
13544
13492
  var DEFAULT_MAX_RESULTS2 = 5;
13545
13493
  var MAX_RESULTS3 = 20;
13546
13494
  var MODEL_VISIBLE_DESCRIPTION_CAP = 180;
13495
+ var SEARCH_FIELD_WEIGHTS = [8, 4, 1];
13496
+ var BM25_K1 = 1.2;
13497
+ var BM25_B = 0.75;
13498
+ var SEARCH_STOP_WORDS = /* @__PURE__ */ new Set([
13499
+ "a",
13500
+ "an",
13501
+ "and",
13502
+ "are",
13503
+ "as",
13504
+ "at",
13505
+ "be",
13506
+ "by",
13507
+ "do",
13508
+ "for",
13509
+ "from",
13510
+ "how",
13511
+ "i",
13512
+ "in",
13513
+ "is",
13514
+ "it",
13515
+ "me",
13516
+ "my",
13517
+ "of",
13518
+ "on",
13519
+ "or",
13520
+ "please",
13521
+ "that",
13522
+ "the",
13523
+ "this",
13524
+ "to",
13525
+ "use",
13526
+ "we",
13527
+ "what",
13528
+ "when",
13529
+ "where",
13530
+ "which",
13531
+ "with",
13532
+ "you",
13533
+ "your"
13534
+ ]);
13547
13535
  var searchToolsSourceSchema = z58.object({
13548
13536
  id: z58.string(),
13549
13537
  description: z58.string()
@@ -13568,8 +13556,26 @@ var searchToolsOutputSchema = juniorToolOutputSchema.extend({
13568
13556
  execution_tool: z58.literal("executeTool"),
13569
13557
  tools: z58.array(searchToolsToolSchema)
13570
13558
  }).strict();
13571
- function normalize2(value) {
13572
- return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
13559
+ function terms(value) {
13560
+ const chunks = value.match(/[\p{L}\p{N}]+/gu) ?? [];
13561
+ const result = [];
13562
+ for (const chunk of chunks) {
13563
+ result.push(chunk.toLowerCase());
13564
+ const expanded = chunk.replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").toLowerCase().split(/\s+/);
13565
+ if (expanded.length > 1) {
13566
+ result.push(...expanded);
13567
+ }
13568
+ }
13569
+ return result;
13570
+ }
13571
+ function queryTerms(query) {
13572
+ return [
13573
+ ...new Set(
13574
+ terms(query).filter(
13575
+ (term) => term.length >= 2 && !SEARCH_STOP_WORDS.has(term)
13576
+ )
13577
+ )
13578
+ ];
13573
13579
  }
13574
13580
  function summarizeModelVisibleDescription(description) {
13575
13581
  const paragraph = description.split(/\n\s*\n/).map((part) => part.trim()).find(Boolean) ?? "";
@@ -13586,36 +13592,114 @@ function schemaText(schema) {
13586
13592
  return "";
13587
13593
  }
13588
13594
  }
13589
- function searchableToolText2(name, definition) {
13590
- return normalize2(
13591
- [
13592
- name,
13593
- definition.identity?.id,
13594
- definition.identity?.name,
13595
- definition.identity?.plugin,
13596
- definition.source?.id,
13597
- definition.source?.description,
13598
- definition.description,
13599
- definition.promptSnippet,
13600
- ...definition.promptGuidelines ?? [],
13601
- schemaText(definition.inputSchema),
13602
- JSON.stringify(definition.annotations ?? {})
13603
- ].filter(Boolean).join(" ")
13595
+ function searchableToolFields(name, definition) {
13596
+ return [
13597
+ terms(
13598
+ [
13599
+ name,
13600
+ definition.identity?.id,
13601
+ definition.identity?.name,
13602
+ definition.identity?.plugin
13603
+ ].filter(Boolean).join(" ")
13604
+ ),
13605
+ terms(
13606
+ [
13607
+ definition.description,
13608
+ definition.promptSnippet,
13609
+ ...definition.promptGuidelines ?? []
13610
+ ].filter(Boolean).join(" ")
13611
+ ),
13612
+ terms(
13613
+ [
13614
+ definition.source?.id,
13615
+ definition.source?.description,
13616
+ schemaText(definition.inputSchema),
13617
+ schemaText(definition.annotations ?? {})
13618
+ ].filter(Boolean).join(" ")
13619
+ )
13620
+ ];
13621
+ }
13622
+ function prepareSearchDocuments(tools, source) {
13623
+ return Object.entries(tools).filter(
13624
+ ([, definition]) => source ? definition.source?.id === source : true
13625
+ ).map(([name, definition]) => ({
13626
+ name,
13627
+ fields: searchableToolFields(name, definition)
13628
+ }));
13629
+ }
13630
+ function averageFieldLengths(documents) {
13631
+ if (documents.length === 0) {
13632
+ return SEARCH_FIELD_WEIGHTS.map(() => 0);
13633
+ }
13634
+ return SEARCH_FIELD_WEIGHTS.map(
13635
+ (_, fieldIndex) => documents.reduce(
13636
+ (total, document) => total + document.fields[fieldIndex].length,
13637
+ 0
13638
+ ) / documents.length
13604
13639
  );
13605
13640
  }
13641
+ function documentFrequencies(documents) {
13642
+ const frequencies = /* @__PURE__ */ new Map();
13643
+ for (const document of documents) {
13644
+ const uniqueTerms = new Set(document.fields.flat());
13645
+ for (const term of uniqueTerms) {
13646
+ frequencies.set(term, (frequencies.get(term) ?? 0) + 1);
13647
+ }
13648
+ }
13649
+ return frequencies;
13650
+ }
13651
+ function scoreSearchDocument(document, query, frequencies, documentCount, averageLengths) {
13652
+ return query.reduce((score, term) => {
13653
+ const documentFrequency = frequencies.get(term) ?? 0;
13654
+ if (documentFrequency === 0) {
13655
+ return score;
13656
+ }
13657
+ const weightedTermFrequency = document.fields.reduce(
13658
+ (weighted, field, fieldIndex) => {
13659
+ const termFrequency = field.filter(
13660
+ (candidate) => candidate === term
13661
+ ).length;
13662
+ if (termFrequency === 0) {
13663
+ return weighted;
13664
+ }
13665
+ const averageLength = averageLengths[fieldIndex] ?? 0;
13666
+ const lengthRatio = averageLength === 0 ? 1 : field.length / averageLength;
13667
+ return weighted + SEARCH_FIELD_WEIGHTS[fieldIndex] * (termFrequency / (1 - BM25_B + BM25_B * lengthRatio));
13668
+ },
13669
+ 0
13670
+ );
13671
+ if (weightedTermFrequency === 0) {
13672
+ return score;
13673
+ }
13674
+ const inverseDocumentFrequency = Math.log(
13675
+ 1 + (documentCount - documentFrequency + 0.5) / (documentFrequency + 0.5)
13676
+ );
13677
+ return score + inverseDocumentFrequency * weightedTermFrequency * (BM25_K1 + 1) / (weightedTermFrequency + BM25_K1);
13678
+ }, 0);
13679
+ }
13606
13680
  function searchCatalogTools(tools, query, source) {
13607
- const entries = Object.entries(tools).sort(
13608
- ([left], [right]) => left.localeCompare(right)
13609
- );
13610
- const sourceEntries = source ? entries.filter(([, definition]) => definition.source?.id === source) : entries;
13611
- if (!normalize2(query)) {
13612
- return sourceEntries.map(([name]) => name);
13681
+ const documents = prepareSearchDocuments(tools, source);
13682
+ if (!query.trim()) {
13683
+ return documents.map(({ name }) => name).sort((left, right) => left.localeCompare(right));
13684
+ }
13685
+ const searchTerms = queryTerms(query);
13686
+ if (searchTerms.length === 0) {
13687
+ return [];
13613
13688
  }
13614
- const terms = normalize2(query).split(/\s+/).filter(Boolean);
13615
- return sourceEntries.filter(([name, definition]) => {
13616
- const text = searchableToolText2(name, definition);
13617
- return terms.every((term) => text.includes(term));
13618
- }).map(([name]) => name);
13689
+ const averageLengths = averageFieldLengths(documents);
13690
+ const frequencies = documentFrequencies(documents);
13691
+ return documents.map((document) => ({
13692
+ name: document.name,
13693
+ score: scoreSearchDocument(
13694
+ document,
13695
+ searchTerms,
13696
+ frequencies,
13697
+ documents.length,
13698
+ averageLengths
13699
+ )
13700
+ })).filter(({ score }) => score > 0).sort(
13701
+ (left, right) => right.score - left.score || left.name.localeCompare(right.name)
13702
+ ).map(({ name }) => name);
13619
13703
  }
13620
13704
  function callNotes(definition) {
13621
13705
  return [
@@ -14020,7 +14104,6 @@ function createMcpAuthOrchestration(input) {
14020
14104
  ...input.threadTs ? { threadTs: input.threadTs } : {},
14021
14105
  ...input.toolChannelId ? { toolChannelId: input.toolChannelId } : {},
14022
14106
  configuration: input.getConfiguration(),
14023
- artifactState: input.getArtifactState(),
14024
14107
  createAuthorizationState: input.authorization?.createState
14025
14108
  });
14026
14109
  authSessionIdsByProvider.set(plugin.manifest.name, provider.authSessionId);
@@ -14058,11 +14141,9 @@ function createMcpAuthOrchestration(input) {
14058
14141
  });
14059
14142
  const reusedAuthSessionId = reusingPendingLink && input.pendingAuth?.kind === "mcp" ? input.pendingAuth.authSessionId : void 0;
14060
14143
  const activeAuthSessionId = reusedAuthSessionId ?? authSessionId;
14061
- const latestArtifactState = input.getMergedArtifactState();
14062
14144
  await patchMcpAuthSession(activeAuthSessionId, {
14063
14145
  configuration: { ...input.getConfiguration() },
14064
- artifactState: latestArtifactState,
14065
- toolChannelId: input.toolChannelId ?? latestArtifactState.assistantContextChannelId ?? input.channelId
14146
+ toolChannelId: input.toolChannelId ?? input.channelId
14066
14147
  });
14067
14148
  const providerLabel = formatProviderLabel(provider);
14068
14149
  const nextPendingAuth = {
@@ -15039,6 +15120,7 @@ function createGuardianActionReviewer(options) {
15039
15120
  maxTokens: GUARDIAN_REVIEW_MAX_TOKENS,
15040
15121
  recordTelemetryPayloads: false,
15041
15122
  temperature: 0,
15123
+ promptName: "junior.guardian_action_review",
15042
15124
  signal,
15043
15125
  metadata: {
15044
15126
  conversationId: proposal.context.conversationId,
@@ -15271,7 +15353,7 @@ async function wireAgentTools(args) {
15271
15353
  egressSignals: args.policy.sandboxEgressSignals,
15272
15354
  credentialEgress: args.routing.credentialContext,
15273
15355
  actor: args.currentActor,
15274
- channelConfiguration: args.policy.channelConfiguration,
15356
+ locationConfiguration: args.policy.locationConfiguration,
15275
15357
  configurationValues: args.configurationValues,
15276
15358
  getActiveSkill: () => args.skillSandbox.getActiveSkill(),
15277
15359
  prepareSandbox: pluginHooks.prepareSandbox,
@@ -15293,11 +15375,6 @@ async function wireAgentTools(args) {
15293
15375
  userMessage: args.userInput,
15294
15376
  pendingAuth: args.state.pendingAuth,
15295
15377
  getConfiguration: () => args.configurationValues,
15296
- getArtifactState: () => args.state.artifactState,
15297
- getMergedArtifactState: () => mergeArtifactsState(
15298
- args.state.artifactState ?? {},
15299
- args.artifactStatePatch
15300
- ),
15301
15378
  recordPendingAuth: args.durability.recordPendingAuth,
15302
15379
  interactiveAuthEnabled: !isAgentRunFeatureDisabled(
15303
15380
  args.policy,
@@ -15310,6 +15387,7 @@ async function wireAgentTools(args) {
15310
15387
  conversationId: args.conversationId,
15311
15388
  sessionId: args.turnId,
15312
15389
  actorId: credentialUserId,
15390
+ actor: args.currentActor,
15313
15391
  channelId: slackChannelId,
15314
15392
  destination: args.routing.destination,
15315
15393
  source: runSource,
@@ -15347,7 +15425,6 @@ async function wireAgentTools(args) {
15347
15425
  const commonToolRuntimeContext = {
15348
15426
  conversationId: args.conversationId,
15349
15427
  userText: args.userInput,
15350
- artifactState: args.state.artifactState,
15351
15428
  configuration: args.configurationValues,
15352
15429
  egress: createPluginEgress({
15353
15430
  credentialContext: args.routing.credentialContext,
@@ -15435,15 +15512,6 @@ async function wireAgentTools(args) {
15435
15512
  args.generatedFiles.push(...files);
15436
15513
  return refs;
15437
15514
  },
15438
- onArtifactStatePatch: async (patch) => {
15439
- Object.assign(args.artifactStatePatch, patch);
15440
- await args.durability.onArtifactStateUpdated?.(
15441
- mergeArtifactsState(
15442
- args.state.artifactState ?? {},
15443
- args.artifactStatePatch
15444
- )
15445
- );
15446
- },
15447
15515
  toolOverrides: args.policy.toolOverrides,
15448
15516
  onSkillLoaded: async (loadedSkill) => {
15449
15517
  const resolvedSkill = await args.skillSandbox.loadSkill(
@@ -15451,7 +15519,6 @@ async function wireAgentTools(args) {
15451
15519
  );
15452
15520
  const effective = resolvedSkill ?? loadedSkill;
15453
15521
  upsertActiveSkill(args.activeSkills, effective);
15454
- args.syncLoadedSkillNamesForResume();
15455
15522
  if (await mcpToolManager.activateForSkill(effective)) {
15456
15523
  await args.recordConnectedMcpProvider(effective.pluginProvider);
15457
15524
  }
@@ -15617,14 +15684,11 @@ function createResumeState(args) {
15617
15684
  const writeBase = () => ({
15618
15685
  conversationId: args.conversationId,
15619
15686
  turnId: args.turnId,
15620
- modelId: args.getModelId(),
15621
15687
  channelName: args.channelName,
15622
15688
  destination: args.destination,
15623
15689
  destinationVisibility: args.destinationVisibility,
15624
15690
  dispatchId: args.dispatchId,
15625
15691
  source: args.runSource,
15626
- loadedSkillNames: args.getLoadedSkillNames(),
15627
- reasoningLevel: args.getReasoningLevel(),
15628
15692
  actor: args.actor,
15629
15693
  surface: args.surface
15630
15694
  });
@@ -16026,6 +16090,7 @@ async function summarizeContext(args, deps) {
16026
16090
  messageAttributeMode: "metadata",
16027
16091
  temperature: 0,
16028
16092
  signal: args.signal,
16093
+ promptName: "junior.context_compaction",
16029
16094
  messages: [
16030
16095
  {
16031
16096
  role: "user",
@@ -16491,10 +16556,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16491
16556
  const skillInvocation = parseSkillInvocation(userInput, availableSkills);
16492
16557
  const invokedSkill = skillInvocation ? findSkillByName(skillInvocation.skillName, availableSkills) : null;
16493
16558
  const activeSkills = [];
16494
- let loadedSkillNamesForResume = [];
16495
- const syncLoadedSkillNamesForResume = () => {
16496
- loadedSkillNamesForResume = activeSkills.map((skill) => skill.name);
16497
- };
16498
16559
  const skillSandbox = new SkillSandbox(availableSkills, activeSkills);
16499
16560
  const checkpoint = await loadTurnCheckpoint({ conversationId, turnId });
16500
16561
  const resumedFromSessionRecord = checkpoint.resumed;
@@ -16529,9 +16590,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16529
16590
  ...routing.destinationVisibility ? { destinationVisibility: routing.destinationVisibility } : {},
16530
16591
  ...routing.dispatch?.id ? { dispatchId: routing.dispatch.id } : {},
16531
16592
  durability,
16532
- getLoadedSkillNames: () => loadedSkillNamesForResume,
16533
- getReasoningLevel: () => turnRoute?.reasoningLevel,
16534
- getModelId: () => activeModelId,
16535
16593
  recordActiveMcpProviders,
16536
16594
  actor,
16537
16595
  runSource,
@@ -16555,7 +16613,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16555
16613
  });
16556
16614
  }
16557
16615
  };
16558
- const persistedConfigurationValues = policy.channelConfiguration ? await policy.channelConfiguration.resolveValues() : {};
16616
+ const persistedConfigurationValues = policy.locationConfiguration ? await policy.locationConfiguration.resolveValues() : {};
16559
16617
  const configurationValues = {
16560
16618
  ...getConfigDefaults(),
16561
16619
  ...policy.configuration ?? {},
@@ -16569,8 +16627,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16569
16627
  activeSkills,
16570
16628
  invokedSkill,
16571
16629
  priorPiMessages,
16572
- skillSandbox,
16573
- syncLoadedSkillNamesForResume
16630
+ skillSandbox
16574
16631
  });
16575
16632
  const explicitSkill = invokedSkill ? activeSkills.find((skill) => skill.name === invokedSkill.name) ?? null : null;
16576
16633
  const { contextContentParts, routerBlocks, userContentParts } = buildPromptInput(input);
@@ -16584,10 +16641,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16584
16641
  botConfig,
16585
16642
  activeModelProfile
16586
16643
  );
16587
- const resumedReasoningLevel = existingSessionRecord?.reasoningLevel ? parseTurnReasoningLevel(existingSessionRecord.reasoningLevel) : void 0;
16588
16644
  turnRoute = {
16589
16645
  profile: activeModelProfile,
16590
- reasoningLevel: activeProfileConfig.reasoningLevel ?? resumedReasoningLevel ?? storedTurnRoute.reasoningLevel,
16646
+ reasoningLevel: activeProfileConfig.reasoningLevel ?? storedTurnRoute.reasoningLevel,
16591
16647
  reason: `resumed_handoff:${storedTurnRoute.modelProfile}:${activeModelProfile}`
16592
16648
  };
16593
16649
  } else {
@@ -16652,6 +16708,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16652
16708
  turnId,
16653
16709
  modelProfile: routedModelProfile,
16654
16710
  modelId: routedModelId,
16711
+ ...turnRoute.costUsd !== void 0 ? { costUsd: turnRoute.costUsd } : {},
16655
16712
  reasoningLevel: turnRoute.reasoningLevel,
16656
16713
  ...turnRoute.confidence !== void 0 ? { confidence: turnRoute.confidence } : {},
16657
16714
  source: turnRoute.source ?? "configured"
@@ -16660,7 +16717,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16660
16717
  activeModelProfile = routedModelProfile;
16661
16718
  activeModelId = routedModelId;
16662
16719
  const generatedFiles = [];
16663
- const artifactStatePatch = {};
16664
16720
  const toolCalls = [];
16665
16721
  let agent;
16666
16722
  let pendingPiHookError;
@@ -16766,7 +16822,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16766
16822
  currentAgentMessages,
16767
16823
  currentTurnMessages,
16768
16824
  currentUserIntent,
16769
- artifactStatePatch,
16770
16825
  availableSkills,
16771
16826
  configurationValues,
16772
16827
  connectedMcpProviders,
@@ -16797,7 +16852,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16797
16852
  state,
16798
16853
  supportsImageInput: () => resolveGatewayModel(activeModelId).input.includes("image"),
16799
16854
  surface,
16800
- syncLoadedSkillNamesForResume,
16801
16855
  toolCalls,
16802
16856
  userInput
16803
16857
  });
@@ -16856,7 +16910,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16856
16910
  } = await assemblePrompt({
16857
16911
  activeMcpCatalogs: wiring.activeMcpCatalogs,
16858
16912
  currentActor: actor,
16859
- artifactState: state.artifactState,
16860
16913
  availableSkills,
16861
16914
  configurationValues,
16862
16915
  contextContentParts: [
@@ -17066,13 +17119,13 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
17066
17119
  return void 0;
17067
17120
  },
17068
17121
  afterToolCall: async ({ result: result2, toolCall }, signal2) => {
17069
- const deadlineResult = runResume.timedOut && signal2?.aborted ? annotateTurnDeadlineToolResult(result2) : void 0;
17070
- const sourceResult = deadlineResult ?? result2;
17122
+ const timedOutResult = runResume.timedOut && signal2?.aborted ? projectTimedOutToolResult(result2) : void 0;
17123
+ const sourceResult = timedOutResult ?? result2;
17071
17124
  const projectedResult = wiring.projectActionReviewResult(
17072
17125
  toolCall.id,
17073
17126
  sourceResult
17074
17127
  );
17075
- return deadlineResult || projectedResult !== result2 ? projectedResult : void 0;
17128
+ return timedOutResult || projectedResult !== result2 ? projectedResult : void 0;
17076
17129
  },
17077
17130
  prepareNextTurnWithContext: async (nextTurn, hookSignal) => {
17078
17131
  try {
@@ -17442,7 +17495,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
17442
17495
  const result = buildTurnResult({
17443
17496
  newMessages,
17444
17497
  userInput,
17445
- artifactStatePatch,
17446
17498
  toolCalls,
17447
17499
  sandboxRef: wiring.getSandboxRef(),
17448
17500
  piMessages: [...agent.state.messages],
@@ -17577,8 +17629,8 @@ export {
17577
17629
  deliverResourceEventSubscription,
17578
17630
  sanitizeScheduledTaskPrincipal,
17579
17631
  listThreadReplies,
17580
- renderSlackLegacyAttachmentText,
17581
- appendSlackLegacyAttachmentText,
17632
+ renderBlockText,
17633
+ renderAttachmentText,
17582
17634
  latestReportedProgress,
17583
17635
  executeCredentialedEgressRequest,
17584
17636
  createContextCompactor,