@sentry/junior 0.145.0 → 0.146.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 (73) hide show
  1. package/dist/{agent-hooks-L7D2BDVV.js → agent-hooks-SLJADYE5.js} +10 -10
  2. package/dist/api.js +19 -19
  3. package/dist/app.js +97 -84
  4. package/dist/{catalog-runtime-QLAC4Q3W.js → catalog-runtime-RQIMSDPR.js} +5 -5
  5. package/dist/chat/agent/resume.d.ts +0 -3
  6. package/dist/chat/agent/skills.d.ts +0 -1
  7. package/dist/chat/agent/tools.d.ts +0 -1
  8. package/dist/chat/conversations/message-search.d.ts +32 -0
  9. package/dist/chat/conversations/sql/message-search.d.ts +4 -0
  10. package/dist/chat/conversations/tool-source.d.ts +5 -0
  11. package/dist/chat/db.d.ts +2 -2
  12. package/dist/chat/slack/message/attachments.d.ts +2 -0
  13. package/dist/chat/slack/message/blocks.d.ts +2 -0
  14. package/dist/chat/slack/message/content.d.ts +18 -0
  15. package/dist/chat/slack/message/identity.d.ts +7 -0
  16. package/dist/chat/slack/tools/{conversation-search.d.ts → conversation-message-search.d.ts} +21 -14
  17. package/dist/chat/slack/tools/user-lookup.d.ts +2 -1
  18. package/dist/chat/task-execution/checkpoint.d.ts +1 -3
  19. package/dist/chat/task-execution/turn-cursor.d.ts +0 -9
  20. package/dist/chat/tools/{query-conversation-events.d.ts → search-conversation-events.d.ts} +3 -3
  21. package/dist/{chunk-2UH3JI64.js → chunk-37EVZP66.js} +41 -29
  22. package/dist/{chunk-CD2XFGYQ.js → chunk-37JJDS4H.js} +1 -1
  23. package/dist/{chunk-I47UGQPJ.js → chunk-47OSH2ZO.js} +7 -7
  24. package/dist/{chunk-RUSS62EN.js → chunk-AISNSNDV.js} +3 -3
  25. package/dist/{chunk-2LWPFSB4.js → chunk-B63BF443.js} +1 -1
  26. package/dist/{chunk-64SBYW2O.js → chunk-BLETMLRX.js} +455 -162
  27. package/dist/{chunk-GDV5LXRA.js → chunk-F7REGDKO.js} +1 -1
  28. package/dist/{chunk-B46ZMVOV.js → chunk-FEKQHPVA.js} +5 -5
  29. package/dist/{chunk-5PNPQYTO.js → chunk-FGHADGIC.js} +2 -2
  30. package/dist/{chunk-GUWLDMGF.js → chunk-FXDDDSPL.js} +4 -4
  31. package/dist/{chunk-ZIAMN2UW.js → chunk-GDQEU4I7.js} +16 -28
  32. package/dist/{chunk-QUG4JSZK.js → chunk-GYEKOX7N.js} +1 -1
  33. package/dist/{chunk-QJBDABQA.js → chunk-H6U2U3EP.js} +10 -10
  34. package/dist/{chunk-DS3J6WGY.js → chunk-HQE6EJS5.js} +1 -1
  35. package/dist/{chunk-HISR3DTV.js → chunk-JUA6VU2Z.js} +5 -7
  36. package/dist/{chunk-PJ4NMVQB.js → chunk-LVW7BLLT.js} +2 -2
  37. package/dist/{chunk-LVVSIMBB.js → chunk-M6ZWP4RI.js} +1 -1
  38. package/dist/{chunk-27TEJTZO.js → chunk-MCFIXAV5.js} +1 -1
  39. package/dist/{chunk-XFKIRN3Q.js → chunk-MKRIZ4VG.js} +2 -3
  40. package/dist/{chunk-2XET6PKP.js → chunk-OFPYOC3M.js} +15 -16
  41. package/dist/{chunk-SIN3MXH6.js → chunk-PB222GIA.js} +1 -1
  42. package/dist/{chunk-DXEQAIUV.js → chunk-PH4Q3A6W.js} +1 -1
  43. package/dist/{chunk-JTGS3ZZE.js → chunk-QG7OOKIN.js} +1 -1
  44. package/dist/{chunk-EIX2LQ6L.js → chunk-QSXZ42KX.js} +3 -3
  45. package/dist/{chunk-ZIMRGFYL.js → chunk-SCGVWUZX.js} +6 -6
  46. package/dist/{chunk-VTDMB7XX.js → chunk-T5GXFFLA.js} +1 -1
  47. package/dist/{chunk-WF5HVH3M.js → chunk-TCEJ7XXM.js} +1 -1
  48. package/dist/{chunk-TZRXYWRE.js → chunk-V6SRLKUB.js} +2 -2
  49. package/dist/{chunk-ZYAJMESY.js → chunk-W65V465O.js} +2 -2
  50. package/dist/{chunk-YD54Q45G.js → chunk-X22KCSCO.js} +4 -4
  51. package/dist/{chunk-HLOUZC5C.js → chunk-X2WMBTS3.js} +4 -4
  52. package/dist/{chunk-FUBRJA5F.js → chunk-ZDGHGY74.js} +6 -6
  53. package/dist/cli/chat.js +32 -32
  54. package/dist/cli/check.js +6 -6
  55. package/dist/cli/plugins.js +13 -13
  56. package/dist/cli/snapshot-create.js +9 -9
  57. package/dist/cli/upgrade.js +7 -7
  58. package/dist/{db-62PW6LM3.js → db-WWOMXWTT.js} +9 -9
  59. package/dist/instrumentation.js +4 -4
  60. package/dist/nitro.js +2 -2
  61. package/dist/{oauth-callback-server-6NZNHJAM.js → oauth-callback-server-A6ZZX74U.js} +23 -23
  62. package/dist/{runner-GCRPG3GQ.js → runner-KSGB2UAV.js} +15 -17
  63. package/dist/{skills-2S3MDFIQ.js → skills-26QPWKVS.js} +6 -6
  64. package/dist/{spawn-7WK37BTD.js → spawn-5LAJXZ2P.js} +17 -17
  65. package/dist/{validation-HAOLCJ5A.js → validation-OPSRGFGH.js} +6 -6
  66. package/dist/version.js +1 -1
  67. package/dist/{work-R4XYKMUW.js → work-VMSW7STJ.js} +16 -16
  68. package/dist/{worker-U2UCVR7M.js → worker-2JNFB7C7.js} +10 -10
  69. package/package.json +5 -5
  70. package/dist/chat/conversations/search.d.ts +0 -24
  71. package/dist/chat/conversations/sql/search.d.ts +0 -4
  72. package/dist/chat/slack/legacy-attachments.d.ts +0 -4
  73. package/dist/chat/slack/message.d.ts +0 -12
@@ -7,7 +7,7 @@ import {
7
7
  PluginCredentialFailureError,
8
8
  agentNameSchema,
9
9
  createPluginAuthOrchestration
10
- } from "./chunk-B46ZMVOV.js";
10
+ } from "./chunk-FEKQHPVA.js";
11
11
  import {
12
12
  authorizationId
13
13
  } from "./chunk-DIB4GX3G.js";
@@ -28,7 +28,7 @@ import {
28
28
  patchMcpAuthSession,
29
29
  selectPluginGrant,
30
30
  toMcpProviderError
31
- } from "./chunk-I47UGQPJ.js";
31
+ } from "./chunk-47OSH2ZO.js";
32
32
  import {
33
33
  RetryableDeliveryError,
34
34
  actorFromRouting,
@@ -44,12 +44,12 @@ import {
44
44
  getSlackMessagePermalink,
45
45
  resolveBaseUrl,
46
46
  uploadFilesToConversation
47
- } from "./chunk-FUBRJA5F.js";
47
+ } from "./chunk-ZDGHGY74.js";
48
48
  import {
49
49
  estimateTextTokens,
50
50
  getAgentContextCompactionTriggerTokens,
51
51
  getAgentContextInputLimitTokens
52
- } from "./chunk-VTDMB7XX.js";
52
+ } from "./chunk-T5GXFFLA.js";
53
53
  import {
54
54
  AGENTS_REMOVAL_NOTICE,
55
55
  AGENTS_REPLACEMENT_NOTICE,
@@ -111,7 +111,7 @@ import {
111
111
  stripRuntimeTurnContext,
112
112
  trimTrailingAssistantMessages,
113
113
  truncateText
114
- } from "./chunk-ZIAMN2UW.js";
114
+ } from "./chunk-GDQEU4I7.js";
115
115
  import {
116
116
  JUNIOR_THREAD_STATE_TTL_MS
117
117
  } from "./chunk-3Y47VMHV.js";
@@ -143,7 +143,7 @@ import {
143
143
  runNonInteractiveCommand,
144
144
  throwSandboxOperationError,
145
145
  wrapSandboxSetupError
146
- } from "./chunk-GUWLDMGF.js";
146
+ } from "./chunk-FXDDDSPL.js";
147
147
  import {
148
148
  SCHEDULED_TASK_SYSTEM_ACTOR,
149
149
  compactEventTask,
@@ -175,15 +175,15 @@ import {
175
175
  saveEventTask,
176
176
  scheduledTaskAttributes,
177
177
  writableEventTask
178
- } from "./chunk-YD54Q45G.js";
178
+ } from "./chunk-X22KCSCO.js";
179
179
  import {
180
180
  parseSlackThreadId
181
- } from "./chunk-DXEQAIUV.js";
181
+ } from "./chunk-PH4Q3A6W.js";
182
182
  import {
183
183
  SHORT_TITLE_MAX_LENGTH,
184
184
  generateShortTitle,
185
185
  resolveTaskTitle
186
- } from "./chunk-ZYAJMESY.js";
186
+ } from "./chunk-W65V465O.js";
187
187
  import {
188
188
  ToolInputError,
189
189
  addAgentTurnUsage,
@@ -201,7 +201,7 @@ import {
201
201
  getSlackToolContext,
202
202
  readActorIdentity,
203
203
  resolveChannelCapabilities
204
- } from "./chunk-ZIMRGFYL.js";
204
+ } from "./chunk-SCGVWUZX.js";
205
205
  import {
206
206
  SlackActionError,
207
207
  downloadPrivateSlackFile,
@@ -210,18 +210,23 @@ import {
210
210
  isConversationScopedChannel,
211
211
  normalizeSlackConversationId,
212
212
  withSlackRetries
213
- } from "./chunk-TZRXYWRE.js";
213
+ } from "./chunk-V6SRLKUB.js";
214
214
  import {
215
215
  KNOWN_CONVERSATION_EVENT_TYPES,
216
216
  contextProvenance,
217
217
  getConversationEventStore,
218
- getConversationSearchStore,
218
+ getConversationMessageSearchStore,
219
219
  getConversationStore,
220
220
  getDb,
221
+ getSqlExecutor,
221
222
  instructionActors,
222
223
  instructionProvenanceFor,
223
- sameActorIdentity
224
- } from "./chunk-2UH3JI64.js";
224
+ sameActorIdentity,
225
+ upsertIdentity
226
+ } from "./chunk-37EVZP66.js";
227
+ import {
228
+ juniorIdentities
229
+ } from "./chunk-MCFIXAV5.js";
225
230
  import {
226
231
  SANDBOX_DATA_ROOT,
227
232
  SANDBOX_SKILLS_ROOT,
@@ -233,7 +238,7 @@ import {
233
238
  } from "./chunk-EM225ITJ.js";
234
239
  import {
235
240
  getStateAdapter
236
- } from "./chunk-QUG4JSZK.js";
241
+ } from "./chunk-GYEKOX7N.js";
237
242
  import {
238
243
  ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
239
244
  COMPACTION_SUMMARY_PREFIX,
@@ -261,13 +266,12 @@ import {
261
266
  modelIdForProfile,
262
267
  modelProfileSchema,
263
268
  normalizeSlackEmojiName,
264
- parseTurnReasoningLevel,
265
269
  profileConfig,
266
270
  renderCurrentInstruction,
267
271
  resolveGatewayCredential,
268
272
  resolveGatewayModel,
269
273
  unwrapCurrentInstruction
270
- } from "./chunk-XFKIRN3Q.js";
274
+ } from "./chunk-MKRIZ4VG.js";
271
275
  import {
272
276
  canExposeConversationPayload,
273
277
  resolveConversationPrivacy,
@@ -277,16 +281,16 @@ import {
277
281
  toGenAiMessagesTraceAttributes,
278
282
  toGenAiPayloadMetadata,
279
283
  toGenAiPayloadTraceAttributes
280
- } from "./chunk-JTGS3ZZE.js";
284
+ } from "./chunk-QG7OOKIN.js";
281
285
  import {
282
286
  discoverSkills,
283
287
  findSkillByName,
284
288
  loadSkillsByName,
285
289
  parseSkillInvocation
286
- } from "./chunk-5PNPQYTO.js";
290
+ } from "./chunk-FGHADGIC.js";
287
291
  import {
288
292
  pluginCatalogRuntime
289
- } from "./chunk-SIN3MXH6.js";
293
+ } from "./chunk-PB222GIA.js";
290
294
  import {
291
295
  CredentialUnavailableError,
292
296
  OAuthProviderError,
@@ -294,7 +298,7 @@ import {
294
298
  getOAuthProviderErrorAttributes,
295
299
  resolveAuthTokenPlaceholder,
296
300
  resolvePluginCommandEnv
297
- } from "./chunk-CD2XFGYQ.js";
301
+ } from "./chunk-37JJDS4H.js";
298
302
  import {
299
303
  credentialUserSubjectId
300
304
  } from "./chunk-RUIXF3YQ.js";
@@ -316,6 +320,7 @@ import {
316
320
  logInfo,
317
321
  logWarn,
318
322
  normalizeGenAiFinishReason,
323
+ normalizeIdentityEmail,
319
324
  serializeGenAiAttribute,
320
325
  setSpanAttributes,
321
326
  setSpanStatus,
@@ -323,7 +328,7 @@ import {
323
328
  summarizeMessageText,
324
329
  withLogContext,
325
330
  withSpan
326
- } from "./chunk-2LWPFSB4.js";
331
+ } from "./chunk-B63BF443.js";
327
332
  import {
328
333
  startInactiveSpan,
329
334
  withActiveSpan
@@ -1573,7 +1578,6 @@ async function restoreSkillRuntime(args) {
1573
1578
  const restoredSkill = await args.skillSandbox.loadSkill(skillName);
1574
1579
  if (restoredSkill) {
1575
1580
  upsertActiveSkill(args.activeSkills, restoredSkill);
1576
- args.syncLoadedSkillNamesForResume();
1577
1581
  }
1578
1582
  }
1579
1583
  if (args.invokedSkill) {
@@ -1582,7 +1586,6 @@ async function restoreSkillRuntime(args) {
1582
1586
  );
1583
1587
  if (restoredSkill) {
1584
1588
  upsertActiveSkill(args.activeSkills, restoredSkill);
1585
- args.syncLoadedSkillNamesForResume();
1586
1589
  }
1587
1590
  }
1588
1591
  }
@@ -8132,7 +8135,7 @@ function createSearchResourceEventTypesTool(catalog) {
8132
8135
  outputSchema: outputSchema2,
8133
8136
  async execute({ query, namespace, maxResults }) {
8134
8137
  const normalizedQuery = normalizeSearchText(query ?? "");
8135
- const terms = normalizedQuery.split(/\s+/).filter(Boolean);
8138
+ const terms2 = normalizedQuery.split(/\s+/).filter(Boolean);
8136
8139
  const matches = searchableResourceTypes(catalog).filter(
8137
8140
  (resourceType) => {
8138
8141
  if (namespace && resourceType.namespace !== namespace) return false;
@@ -8144,7 +8147,7 @@ function createSearchResourceEventTypesTool(catalog) {
8144
8147
  ...resourceType.suggestedEvents ?? []
8145
8148
  ].join(" ")
8146
8149
  );
8147
- return terms.every((term) => text.includes(term));
8150
+ return terms2.every((term) => text.includes(term));
8148
8151
  }
8149
8152
  );
8150
8153
  const resourceTypes = matches.slice(
@@ -9816,32 +9819,63 @@ function createSlackChannelListMessagesTool(context) {
9816
9819
  });
9817
9820
  }
9818
9821
 
9819
- // src/chat/slack/tools/conversation-search.ts
9822
+ // src/chat/slack/tools/conversation-message-search.ts
9820
9823
  import { z as z37 } from "zod";
9824
+
9825
+ // src/chat/conversations/tool-source.ts
9826
+ var CONVERSATIONS_TOOL_SOURCE = {
9827
+ id: "conversations",
9828
+ description: "Search messages and events in retained Junior conversations."
9829
+ };
9830
+
9831
+ // src/chat/slack/tools/conversation-message-search.ts
9821
9832
  var DEFAULT_LIMIT = 5;
9822
- var conversationSearchOutputSchema = juniorToolOutputSchema.extend({
9823
- query: z37.string(),
9833
+ var conversationMessageSearchOutputSchema = juniorToolOutputSchema.extend({
9834
+ channel_id: z37.string().min(1).optional(),
9824
9835
  count: z37.number().int().nonnegative(),
9825
- threads: z37.array(
9836
+ query: z37.string().optional(),
9837
+ matches: z37.array(
9826
9838
  z37.object({
9839
+ channel_id: z37.string().min(1),
9840
+ channel_name: z37.string().min(1).optional(),
9827
9841
  conversation_id: z37.string().min(1),
9828
- thread_ts: z37.string().min(1),
9842
+ excerpt: z37.string(),
9829
9843
  message_id: z37.string().min(1),
9830
9844
  message_role: z37.enum(["assistant", "user"]),
9831
9845
  message_timestamp: z37.string().datetime(),
9832
- excerpt: z37.string(),
9833
- permalink: z37.string().url().optional()
9846
+ permalink: z37.string().url().optional(),
9847
+ thread_ts: z37.string().min(1)
9834
9848
  }).strict()
9835
9849
  )
9836
9850
  });
9837
- function createSlackConversationSearchTool(scope, currentConversationId, deps = {}) {
9851
+ function resolveSearchFilters(input) {
9852
+ const query = input.query?.trim() || void 0;
9853
+ let channelId;
9854
+ if (input.channel_id != null) {
9855
+ const parsed = parseRequiredSlackChannelIdParam(
9856
+ "channel_id",
9857
+ input.channel_id
9858
+ );
9859
+ if (!parsed.ok) {
9860
+ throw new ToolInputError(parsed.error);
9861
+ }
9862
+ channelId = parsed.value;
9863
+ }
9864
+ if (!query && !channelId) {
9865
+ throw new ToolInputError(
9866
+ "Provide at least one of `query` or `channel_id`."
9867
+ );
9868
+ }
9869
+ return {
9870
+ ...channelId ? { channelId } : {},
9871
+ ...query ? { query } : {}
9872
+ };
9873
+ }
9874
+ function createSlackConversationMessageSearchTool(scope, currentConversationId, deps = {}) {
9838
9875
  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.",
9876
+ description: "Search retained user and assistant messages in public Junior conversations across the current Slack workspace. Excludes the current conversation.",
9840
9877
  exposure: "deferred",
9841
- source: {
9842
- id: "conversation-history",
9843
- description: "Search retained public Junior conversation threads in the current Slack workspace."
9844
- },
9878
+ source: CONVERSATIONS_TOOL_SOURCE,
9845
9879
  annotations: {
9846
9880
  destructiveHint: false,
9847
9881
  idempotentHint: true,
@@ -9849,20 +9883,24 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
9849
9883
  readOnlyHint: true
9850
9884
  },
9851
9885
  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();
9886
+ channel_id: slackChannelIdParam(
9887
+ "Destination Slack channel ID; no active-channel default."
9888
+ ).nullable().optional(),
9889
+ query: z37.string().trim().min(1).max(200).nullable().describe("Words or phrase to match in message text.").optional(),
9890
+ limit: z37.number().int().min(1).max(10).describe(`Maximum matches. Default ${DEFAULT_LIMIT}; max 10.`).nullable().optional()
9891
+ }).strict(),
9892
+ outputSchema: conversationMessageSearchOutputSchema,
9893
+ execute: async (input) => {
9894
+ const filters = resolveSearchFilters(input);
9895
+ const store = deps.store ?? getConversationMessageSearchStore();
9858
9896
  const matches = await store.search({
9859
9897
  currentConversationId,
9860
- limit: limit ?? DEFAULT_LIMIT,
9861
- query,
9898
+ filters,
9899
+ limit: input.limit ?? DEFAULT_LIMIT,
9862
9900
  scope
9863
9901
  });
9864
9902
  const getPermalink = deps.getPermalink ?? getSlackMessagePermalink;
9865
- const threads = await Promise.all(
9903
+ const matchesOutput = await Promise.all(
9866
9904
  matches.map(async (match) => {
9867
9905
  const reference = parseSlackThreadId(match.conversationId);
9868
9906
  if (!reference || reference.channelId !== match.providerDestinationId) {
@@ -9881,14 +9919,17 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
9881
9919
  message_role: match.role,
9882
9920
  message_timestamp: new Date(match.messageCreatedAtMs).toISOString(),
9883
9921
  excerpt: match.excerpt,
9922
+ channel_id: match.providerDestinationId,
9923
+ ...match.channelName ? { channel_name: match.channelName } : {},
9884
9924
  ...permalink ? { permalink } : {}
9885
9925
  };
9886
9926
  })
9887
9927
  );
9888
9928
  return {
9889
- query,
9890
- count: threads.length,
9891
- threads
9929
+ ...filters.query ? { query: filters.query } : {},
9930
+ ...filters.channelId ? { channel_id: filters.channelId } : {},
9931
+ count: matchesOutput.length,
9932
+ matches: matchesOutput
9892
9933
  };
9893
9934
  }
9894
9935
  });
@@ -11294,7 +11335,100 @@ function parseSlackMessageReference(input) {
11294
11335
  };
11295
11336
  }
11296
11337
 
11297
- // src/chat/slack/legacy-attachments.ts
11338
+ // src/chat/slack/message/blocks.ts
11339
+ var MAX_BLOCKS = 50;
11340
+ var MAX_CHILDREN = 50;
11341
+ var MAX_DEPTH = 16;
11342
+ var MAX_NODES = 5e3;
11343
+ var CHILD_KEYS = [
11344
+ "blocks",
11345
+ "elements",
11346
+ "fields",
11347
+ "accessory",
11348
+ "element",
11349
+ "rows",
11350
+ "cells"
11351
+ ];
11352
+ function toText(value) {
11353
+ return typeof value === "string" && value.length > 0 ? value : void 0;
11354
+ }
11355
+ function readText(value) {
11356
+ if (typeof value === "string") return toText(value);
11357
+ if (!value || typeof value !== "object") return void 0;
11358
+ return toText(value.text);
11359
+ }
11360
+ function parseChildren(value, budget, depth) {
11361
+ if (Array.isArray(value)) {
11362
+ return value.slice(0, MAX_CHILDREN).flatMap((child) => parseChildren(child, budget, depth));
11363
+ }
11364
+ return parseElement(value, budget, depth);
11365
+ }
11366
+ function parseElement(value, budget, depth) {
11367
+ if (!value || typeof value !== "object" || depth > MAX_DEPTH || budget.remainingNodes <= 0) {
11368
+ return [];
11369
+ }
11370
+ budget.remainingNodes -= 1;
11371
+ const element = value;
11372
+ const type = toText(element.type);
11373
+ const text = readText(element.text);
11374
+ if (type === "link") {
11375
+ const url = toText(element.url);
11376
+ return [
11377
+ text && url && text !== url ? `${text} (${url})` : text || url
11378
+ ].filter((part) => Boolean(part));
11379
+ }
11380
+ if (type === "button") {
11381
+ const url = toText(element.url);
11382
+ return [text && url ? `${text} (${url})` : text].filter(
11383
+ (part) => Boolean(part)
11384
+ );
11385
+ }
11386
+ if (type === "emoji") {
11387
+ const name = toText(element.name);
11388
+ return name ? [`:${name}:`] : [];
11389
+ }
11390
+ if (type === "user") {
11391
+ const userId = toText(element.user_id);
11392
+ return userId ? [`<@${userId}>`] : [];
11393
+ }
11394
+ if (type === "channel") {
11395
+ const channelId = toText(element.channel_id);
11396
+ return channelId ? [`<#${channelId}>`] : [];
11397
+ }
11398
+ if (type === "usergroup") {
11399
+ const usergroupId = toText(element.usergroup_id);
11400
+ return usergroupId ? [`<!subteam^${usergroupId}>`] : [];
11401
+ }
11402
+ if (type === "broadcast") {
11403
+ const range = toText(element.range);
11404
+ return range ? [`<!${range}>`] : [];
11405
+ }
11406
+ const parts = [
11407
+ text,
11408
+ readText(element.title),
11409
+ readText(element.description),
11410
+ readText(element.label),
11411
+ readText(element.hint),
11412
+ readText(element.placeholder),
11413
+ toText(element.alt_text),
11414
+ toText(element.provider_name),
11415
+ toText(element.fallback)
11416
+ ].filter((part) => Boolean(part));
11417
+ for (const key of CHILD_KEYS) {
11418
+ parts.push(...parseChildren(element[key], budget, depth + 1));
11419
+ }
11420
+ if (type === "checkboxes" || type === "radio_buttons") {
11421
+ parts.push(...parseChildren(element.options, budget, depth + 1));
11422
+ }
11423
+ return parts;
11424
+ }
11425
+ function renderBlockText(value) {
11426
+ if (!Array.isArray(value)) return "";
11427
+ const budget = { remainingNodes: MAX_NODES };
11428
+ return value.slice(0, MAX_BLOCKS).flatMap((block) => parseElement(block, budget, 0)).join("\n");
11429
+ }
11430
+
11431
+ // src/chat/slack/message/attachments.ts
11298
11432
  var MAX_ATTACHMENTS = 10;
11299
11433
  var MAX_FIELDS_PER_ATTACHMENT = 20;
11300
11434
  var MAX_FIELD_CHARS = 1e3;
@@ -11332,6 +11466,7 @@ function renderAttachment(raw) {
11332
11466
  const text = toStr(obj.text);
11333
11467
  const footer = toStr(obj.footer);
11334
11468
  const fields = Array.isArray(obj.fields) ? obj.fields : [];
11469
+ const blockText = renderBlockText(obj.blocks);
11335
11470
  const add = (value) => {
11336
11471
  if (!value) return;
11337
11472
  const normalized = normalizeAttachmentText(value);
@@ -11339,7 +11474,7 @@ function renderAttachment(raw) {
11339
11474
  seen.add(normalized);
11340
11475
  parts.push(normalized);
11341
11476
  };
11342
- const hasRichContent = pretext || title || text;
11477
+ const hasRichContent = pretext || title || text || blockText;
11343
11478
  if (!hasRichContent) {
11344
11479
  add(fallback);
11345
11480
  }
@@ -11355,28 +11490,19 @@ function renderAttachment(raw) {
11355
11490
  for (const field of fields.slice(0, MAX_FIELDS_PER_ATTACHMENT)) {
11356
11491
  add(renderField(field));
11357
11492
  }
11493
+ add(blockText);
11358
11494
  add(footer);
11359
11495
  return parts.join("\n");
11360
11496
  }
11361
- function renderSlackLegacyAttachmentText(input) {
11497
+ function renderAttachmentText(input) {
11362
11498
  const rendered = getAttachmentPayload(input).slice(0, MAX_ATTACHMENTS).map(renderAttachment).filter((line) => line.length > 0).map((line) => `[attachment] ${line}`).join("\n");
11363
11499
  return rendered.slice(0, MAX_ATTACHMENT_TEXT_CHARS);
11364
11500
  }
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
11501
 
11376
11502
  // src/chat/slack/tools/thread-read.ts
11377
11503
  var MAX_THREAD_READ_CHARS = 4e4;
11378
11504
  function sanitizeMessage(msg) {
11379
- const attachmentText = renderSlackLegacyAttachmentText(msg.attachments);
11505
+ const attachmentText = renderAttachmentText(msg.attachments);
11380
11506
  return {
11381
11507
  ts: msg.ts,
11382
11508
  user: msg.user,
@@ -11517,6 +11643,10 @@ function createSlackThreadReadTool(context, deps = {}) {
11517
11643
  });
11518
11644
  }
11519
11645
 
11646
+ // src/chat/slack/tools/user-lookup.ts
11647
+ import { and, eq } from "drizzle-orm";
11648
+ import { z as z50 } from "zod";
11649
+
11520
11650
  // src/chat/slack/users.ts
11521
11651
  function normalizeUser(raw) {
11522
11652
  const rawFields = raw.profile?.fields;
@@ -11657,7 +11787,6 @@ async function searchSlackUsers(options) {
11657
11787
  }
11658
11788
 
11659
11789
  // src/chat/slack/tools/user-lookup.ts
11660
- import { z as z50 } from "zod";
11661
11790
  function explicitUserLookupError(error) {
11662
11791
  if (error.apiError === "user_not_found") {
11663
11792
  return "No Slack user found for the supplied user ID.";
@@ -11676,9 +11805,52 @@ function explicitUserLookupError(error) {
11676
11805
  }
11677
11806
  return void 0;
11678
11807
  }
11679
- function createSlackUserLookupTool() {
11808
+ function slackMention(userId) {
11809
+ return `<@${userId}>`;
11810
+ }
11811
+ async function storeProfile(teamId, profile) {
11812
+ await upsertIdentity(getSqlExecutor(), {
11813
+ kind: profile.is_bot ? "service" : "user",
11814
+ provider: "slack",
11815
+ providerTenantId: teamId,
11816
+ providerSubjectId: profile.id,
11817
+ ...profile.real_name || profile.display_name ? { displayName: profile.real_name || profile.display_name } : {},
11818
+ ...profile.name ? { handle: profile.name } : {},
11819
+ ...profile.email ? { email: profile.email, emailVerified: true } : {}
11820
+ });
11821
+ }
11822
+ async function storedUserByEmail(teamId, email) {
11823
+ const emailNormalized = normalizeIdentityEmail(email);
11824
+ if (!emailNormalized) return void 0;
11825
+ const identities = await getSqlExecutor().db().select().from(juniorIdentities).where(
11826
+ and(
11827
+ eq(juniorIdentities.provider, "slack"),
11828
+ eq(juniorIdentities.providerTenantId, teamId),
11829
+ eq(juniorIdentities.kind, "user"),
11830
+ eq(juniorIdentities.emailVerified, true),
11831
+ eq(juniorIdentities.emailNormalized, emailNormalized)
11832
+ )
11833
+ ).limit(2);
11834
+ if (identities.length > 1) {
11835
+ throw new Error(
11836
+ `Multiple Slack users share verified email ${emailNormalized} in workspace ${teamId}`
11837
+ );
11838
+ }
11839
+ const identity = identities[0];
11840
+ if (!identity) return void 0;
11841
+ return {
11842
+ id: identity.providerSubjectId,
11843
+ ...identity.handle ? { name: identity.handle } : {},
11844
+ ...identity.displayName ? { real_name: identity.displayName } : {},
11845
+ ...identity.displayName ? { display_name: identity.displayName } : {},
11846
+ ...identity.email ? { email: identity.email } : {},
11847
+ is_bot: false,
11848
+ is_deleted: false
11849
+ };
11850
+ }
11851
+ function createSlackUserLookupTool(teamId) {
11680
11852
  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.",
11853
+ description: "Look up Slack user profiles by user ID, email, or name search. Returns Slack `mention` values (`<@U\u2026>`). Use a mention only when one person clearly matches; otherwise ask which person the user means.",
11682
11854
  annotations: {
11683
11855
  destructiveHint: false,
11684
11856
  idempotentHint: true,
@@ -11701,20 +11873,33 @@ function createSlackUserLookupTool() {
11701
11873
  if (!parsedUserId.ok) {
11702
11874
  throw new ToolInputError(parsedUserId.error);
11703
11875
  }
11876
+ const user = await lookupSlackUserProfile(parsedUserId.value);
11877
+ await storeProfile(teamId, user);
11704
11878
  return {
11705
11879
  mode: "user_id",
11706
- user: await lookupSlackUserProfile(parsedUserId.value)
11880
+ mention: slackMention(user.id),
11881
+ user
11707
11882
  };
11708
11883
  }
11709
11884
  if (mode === "email") {
11885
+ const stored = await storedUserByEmail(teamId, value);
11886
+ if (stored) {
11887
+ return {
11888
+ mode: "email",
11889
+ mention: slackMention(stored.id),
11890
+ user: stored
11891
+ };
11892
+ }
11710
11893
  const profile = await lookupSlackUserByEmail(value);
11711
11894
  if (!profile) {
11712
11895
  throw new ToolInputError(
11713
11896
  `No Slack user found with email address ${value}.`
11714
11897
  );
11715
11898
  }
11899
+ await storeProfile(teamId, profile);
11716
11900
  return {
11717
11901
  mode: "email",
11902
+ mention: slackMention(profile.id),
11718
11903
  user: profile
11719
11904
  };
11720
11905
  }
@@ -11724,6 +11909,9 @@ function createSlackUserLookupTool() {
11724
11909
  maxPages: 3,
11725
11910
  includeBots: false
11726
11911
  });
11912
+ if (result.users.length === 1) {
11913
+ await storeProfile(teamId, result.users[0]);
11914
+ }
11727
11915
  return {
11728
11916
  mode: "query",
11729
11917
  query: value,
@@ -11731,7 +11919,10 @@ function createSlackUserLookupTool() {
11731
11919
  searched_pages: result.searched_pages,
11732
11920
  searched_user_count: result.searched_user_count,
11733
11921
  truncated: result.truncated,
11734
- users: result.users
11922
+ users: result.users.map((user) => ({
11923
+ ...user,
11924
+ mention: slackMention(user.id)
11925
+ }))
11735
11926
  };
11736
11927
  } catch (error) {
11737
11928
  if (error instanceof SlackActionError) {
@@ -11837,7 +12028,7 @@ function getTimeZoneOffsetMinutes(timestampMs, timezone) {
11837
12028
  return Math.round((timestampMs - asUtcMs) / 6e4);
11838
12029
  }
11839
12030
 
11840
- // src/chat/tools/query-conversation-events.ts
12031
+ // src/chat/tools/search-conversation-events.ts
11841
12032
  import { z as z52 } from "zod";
11842
12033
  var DEFAULT_LIMIT3 = 25;
11843
12034
  var MAX_LIMIT = 100;
@@ -11845,40 +12036,26 @@ var MAX_EVENT_DATA_BYTES = 4e3;
11845
12036
  var MAX_EVENTS_JSON_BYTES = 2e4;
11846
12037
  var MAX_IDENTITY_CHARS = 256;
11847
12038
  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
12039
  var knownEventTypeSchema = z52.enum(KNOWN_CONVERSATION_EVENT_TYPES);
11853
12040
  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
- ),
12041
+ seq: z52.number().int().nonnegative().describe("Stable event position for pagination."),
12042
+ history_version: z52.number().int().nonnegative().describe("Agent history generation after replacement."),
11858
12043
  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
- )
12044
+ idempotency_key: z52.string().min(1).optional().describe("Retry-stable event identity, when assigned."),
12045
+ data: z52.record(z52.string(), z52.unknown()).describe("Bounded event data.")
11863
12046
  }).strict();
11864
- var queryConversationEventsOutputSchema = juniorToolOutputSchema.extend({
12047
+ var searchConversationEventsOutputSchema = juniorToolOutputSchema.extend({
11865
12048
  conversation_id: z52.string().min(1),
11866
12049
  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
- )
12050
+ has_older: z52.boolean().describe("Whether matching older events exist."),
12051
+ has_newer: z52.boolean().describe("Whether matching newer events exist."),
12052
+ omitted_event_count: z52.number().int().nonnegative().optional().describe("Events omitted by the response byte limit.")
11876
12053
  });
11877
- function createQueryConversationEventsTool(context) {
12054
+ function createSearchConversationEventsTool(context) {
11878
12055
  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.",
12056
+ 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
12057
  exposure: "deferred",
11881
- source: CONVERSATION_EVENTS_TOOL_SOURCE,
12058
+ source: CONVERSATIONS_TOOL_SOURCE,
11882
12059
  annotations: {
11883
12060
  destructiveHint: false,
11884
12061
  idempotentHint: true,
@@ -11886,31 +12063,25 @@ function createQueryConversationEventsTool(context) {
11886
12063
  readOnlyHint: true
11887
12064
  },
11888
12065
  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."
12066
+ conversation_id: z52.string().trim().min(1).nullable().describe(
12067
+ "Conversation ID to search. Omit or null for the current conversation."
11897
12068
  ).optional(),
12069
+ after_seq: z52.number().int().nonnegative().nullable().describe("Exclusive event sequence lower bound; returns ascending.").optional(),
12070
+ before_seq: z52.number().int().nonnegative().nullable().describe("Exclusive event sequence upper bound.").optional(),
11898
12071
  limit: z52.number().int().min(1).max(MAX_LIMIT).nullable().describe(
11899
- `Maximum events to return. Defaults to ${DEFAULT_LIMIT3}; max ${MAX_LIMIT}.`
12072
+ `Maximum events. Default ${DEFAULT_LIMIT3}; max ${MAX_LIMIT}.`
11900
12073
  ).optional(),
11901
- types: z52.array(knownEventTypeSchema).min(1).nullable().describe(
11902
- "Optional event-type filter. Omit to return every durable event type."
11903
- ).optional()
12074
+ types: z52.array(knownEventTypeSchema).min(1).nullable().describe("Event types to include; omit for all types.").optional()
11904
12075
  }).strict(),
11905
- outputSchema: queryConversationEventsOutputSchema,
12076
+ outputSchema: searchConversationEventsOutputSchema,
11906
12077
  execute: async (input) => {
11907
12078
  const currentConversationId = context.conversationId?.trim();
11908
12079
  if (!currentConversationId) {
11909
12080
  throw new ToolInputError(
11910
- "queryConversationEvents requires an active conversation"
12081
+ "searchConversationEvents requires an active conversation"
11911
12082
  );
11912
12083
  }
11913
- const conversationId = input.conversation_id;
12084
+ const conversationId = input.conversation_id?.trim() || currentConversationId;
11914
12085
  const afterSeq = input.after_seq ?? void 0;
11915
12086
  const beforeSeq = input.before_seq ?? void 0;
11916
12087
  const limit = input.limit ?? DEFAULT_LIMIT3;
@@ -11943,7 +12114,7 @@ function createQueryConversationEventsTool(context) {
11943
12114
  const targetRoot = targetRootConversationId === conversationId ? target : await conversationStore.get({
11944
12115
  conversationId: targetRootConversationId
11945
12116
  });
11946
- assertCanQueryConversationEvents({
12117
+ assertCanSearchConversationEvents({
11947
12118
  accessScope,
11948
12119
  targetConversationId: conversationId,
11949
12120
  targetRootConversationId,
@@ -12021,7 +12192,7 @@ async function resolveRootConversationId(conversationStore, conversationId, pare
12021
12192
  }
12022
12193
  return conversationId;
12023
12194
  }
12024
- function assertCanQueryConversationEvents(args) {
12195
+ function assertCanSearchConversationEvents(args) {
12025
12196
  const {
12026
12197
  accessScope,
12027
12198
  targetConversationId,
@@ -12848,7 +13019,7 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
12848
13019
  ...createScheduledTaskTools(context)
12849
13020
  };
12850
13021
  if (context.conversationId) {
12851
- tools.queryConversationEvents = createQueryConversationEventsTool(context);
13022
+ tools.searchConversationEvents = createSearchConversationEventsTool(context);
12852
13023
  }
12853
13024
  if (context.supportsImageInput) {
12854
13025
  tools.viewImage = createViewImageTool(
@@ -12885,7 +13056,7 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
12885
13056
  tools.slackCanvasWrite = createSlackCanvasWriteTool(state);
12886
13057
  tools.slackThreadRead = createSlackThreadReadTool(slackContext);
12887
13058
  if (context.conversationId && slackContext.source.visibility === "public") {
12888
- tools.searchConversationHistory = createSlackConversationSearchTool(
13059
+ tools.searchConversationMessages = createSlackConversationMessageSearchTool(
12889
13060
  {
12890
13061
  kind: "public_provider_tenant",
12891
13062
  provider: "slack",
@@ -12899,7 +13070,7 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
12899
13070
  context.slackActionToken
12900
13071
  );
12901
13072
  }
12902
- tools.slackUserLookup = createSlackUserLookupTool();
13073
+ tools.slackUserLookup = createSlackUserLookupTool(slackContext.teamId);
12903
13074
  tools.slackListCreate = createSlackListCreateTool(state);
12904
13075
  tools.slackListAddItems = createSlackListAddItemsTool(state);
12905
13076
  tools.slackListGetItems = createSlackListGetItemsTool(state);
@@ -13544,6 +13715,46 @@ var SEARCH_TOOLS_NAME = "searchTools";
13544
13715
  var DEFAULT_MAX_RESULTS2 = 5;
13545
13716
  var MAX_RESULTS3 = 20;
13546
13717
  var MODEL_VISIBLE_DESCRIPTION_CAP = 180;
13718
+ var SEARCH_FIELD_WEIGHTS = [8, 4, 1];
13719
+ var BM25_K1 = 1.2;
13720
+ var BM25_B = 0.75;
13721
+ var SEARCH_STOP_WORDS = /* @__PURE__ */ new Set([
13722
+ "a",
13723
+ "an",
13724
+ "and",
13725
+ "are",
13726
+ "as",
13727
+ "at",
13728
+ "be",
13729
+ "by",
13730
+ "do",
13731
+ "for",
13732
+ "from",
13733
+ "how",
13734
+ "i",
13735
+ "in",
13736
+ "is",
13737
+ "it",
13738
+ "me",
13739
+ "my",
13740
+ "of",
13741
+ "on",
13742
+ "or",
13743
+ "please",
13744
+ "that",
13745
+ "the",
13746
+ "this",
13747
+ "to",
13748
+ "use",
13749
+ "we",
13750
+ "what",
13751
+ "when",
13752
+ "where",
13753
+ "which",
13754
+ "with",
13755
+ "you",
13756
+ "your"
13757
+ ]);
13547
13758
  var searchToolsSourceSchema = z58.object({
13548
13759
  id: z58.string(),
13549
13760
  description: z58.string()
@@ -13568,8 +13779,26 @@ var searchToolsOutputSchema = juniorToolOutputSchema.extend({
13568
13779
  execution_tool: z58.literal("executeTool"),
13569
13780
  tools: z58.array(searchToolsToolSchema)
13570
13781
  }).strict();
13571
- function normalize2(value) {
13572
- return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
13782
+ function terms(value) {
13783
+ const chunks = value.match(/[\p{L}\p{N}]+/gu) ?? [];
13784
+ const result = [];
13785
+ for (const chunk of chunks) {
13786
+ result.push(chunk.toLowerCase());
13787
+ 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+/);
13788
+ if (expanded.length > 1) {
13789
+ result.push(...expanded);
13790
+ }
13791
+ }
13792
+ return result;
13793
+ }
13794
+ function queryTerms(query) {
13795
+ return [
13796
+ ...new Set(
13797
+ terms(query).filter(
13798
+ (term) => term.length >= 2 && !SEARCH_STOP_WORDS.has(term)
13799
+ )
13800
+ )
13801
+ ];
13573
13802
  }
13574
13803
  function summarizeModelVisibleDescription(description) {
13575
13804
  const paragraph = description.split(/\n\s*\n/).map((part) => part.trim()).find(Boolean) ?? "";
@@ -13586,36 +13815,114 @@ function schemaText(schema) {
13586
13815
  return "";
13587
13816
  }
13588
13817
  }
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(" ")
13818
+ function searchableToolFields(name, definition) {
13819
+ return [
13820
+ terms(
13821
+ [
13822
+ name,
13823
+ definition.identity?.id,
13824
+ definition.identity?.name,
13825
+ definition.identity?.plugin
13826
+ ].filter(Boolean).join(" ")
13827
+ ),
13828
+ terms(
13829
+ [
13830
+ definition.description,
13831
+ definition.promptSnippet,
13832
+ ...definition.promptGuidelines ?? []
13833
+ ].filter(Boolean).join(" ")
13834
+ ),
13835
+ terms(
13836
+ [
13837
+ definition.source?.id,
13838
+ definition.source?.description,
13839
+ schemaText(definition.inputSchema),
13840
+ schemaText(definition.annotations ?? {})
13841
+ ].filter(Boolean).join(" ")
13842
+ )
13843
+ ];
13844
+ }
13845
+ function prepareSearchDocuments(tools, source) {
13846
+ return Object.entries(tools).filter(
13847
+ ([, definition]) => source ? definition.source?.id === source : true
13848
+ ).map(([name, definition]) => ({
13849
+ name,
13850
+ fields: searchableToolFields(name, definition)
13851
+ }));
13852
+ }
13853
+ function averageFieldLengths(documents) {
13854
+ if (documents.length === 0) {
13855
+ return SEARCH_FIELD_WEIGHTS.map(() => 0);
13856
+ }
13857
+ return SEARCH_FIELD_WEIGHTS.map(
13858
+ (_, fieldIndex) => documents.reduce(
13859
+ (total, document) => total + document.fields[fieldIndex].length,
13860
+ 0
13861
+ ) / documents.length
13604
13862
  );
13605
13863
  }
13864
+ function documentFrequencies(documents) {
13865
+ const frequencies = /* @__PURE__ */ new Map();
13866
+ for (const document of documents) {
13867
+ const uniqueTerms = new Set(document.fields.flat());
13868
+ for (const term of uniqueTerms) {
13869
+ frequencies.set(term, (frequencies.get(term) ?? 0) + 1);
13870
+ }
13871
+ }
13872
+ return frequencies;
13873
+ }
13874
+ function scoreSearchDocument(document, query, frequencies, documentCount, averageLengths) {
13875
+ return query.reduce((score, term) => {
13876
+ const documentFrequency = frequencies.get(term) ?? 0;
13877
+ if (documentFrequency === 0) {
13878
+ return score;
13879
+ }
13880
+ const weightedTermFrequency = document.fields.reduce(
13881
+ (weighted, field, fieldIndex) => {
13882
+ const termFrequency = field.filter(
13883
+ (candidate) => candidate === term
13884
+ ).length;
13885
+ if (termFrequency === 0) {
13886
+ return weighted;
13887
+ }
13888
+ const averageLength = averageLengths[fieldIndex] ?? 0;
13889
+ const lengthRatio = averageLength === 0 ? 1 : field.length / averageLength;
13890
+ return weighted + SEARCH_FIELD_WEIGHTS[fieldIndex] * (termFrequency / (1 - BM25_B + BM25_B * lengthRatio));
13891
+ },
13892
+ 0
13893
+ );
13894
+ if (weightedTermFrequency === 0) {
13895
+ return score;
13896
+ }
13897
+ const inverseDocumentFrequency = Math.log(
13898
+ 1 + (documentCount - documentFrequency + 0.5) / (documentFrequency + 0.5)
13899
+ );
13900
+ return score + inverseDocumentFrequency * weightedTermFrequency * (BM25_K1 + 1) / (weightedTermFrequency + BM25_K1);
13901
+ }, 0);
13902
+ }
13606
13903
  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);
13904
+ const documents = prepareSearchDocuments(tools, source);
13905
+ if (!query.trim()) {
13906
+ return documents.map(({ name }) => name).sort((left, right) => left.localeCompare(right));
13907
+ }
13908
+ const searchTerms = queryTerms(query);
13909
+ if (searchTerms.length === 0) {
13910
+ return [];
13613
13911
  }
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);
13912
+ const averageLengths = averageFieldLengths(documents);
13913
+ const frequencies = documentFrequencies(documents);
13914
+ return documents.map((document) => ({
13915
+ name: document.name,
13916
+ score: scoreSearchDocument(
13917
+ document,
13918
+ searchTerms,
13919
+ frequencies,
13920
+ documents.length,
13921
+ averageLengths
13922
+ )
13923
+ })).filter(({ score }) => score > 0).sort(
13924
+ (left, right) => right.score - left.score || left.name.localeCompare(right.name)
13925
+ ).map(({ name }) => name);
13619
13926
  }
13620
13927
  function callNotes(definition) {
13621
13928
  return [
@@ -15451,7 +15758,6 @@ async function wireAgentTools(args) {
15451
15758
  );
15452
15759
  const effective = resolvedSkill ?? loadedSkill;
15453
15760
  upsertActiveSkill(args.activeSkills, effective);
15454
- args.syncLoadedSkillNamesForResume();
15455
15761
  if (await mcpToolManager.activateForSkill(effective)) {
15456
15762
  await args.recordConnectedMcpProvider(effective.pluginProvider);
15457
15763
  }
@@ -15617,14 +15923,11 @@ function createResumeState(args) {
15617
15923
  const writeBase = () => ({
15618
15924
  conversationId: args.conversationId,
15619
15925
  turnId: args.turnId,
15620
- modelId: args.getModelId(),
15621
15926
  channelName: args.channelName,
15622
15927
  destination: args.destination,
15623
15928
  destinationVisibility: args.destinationVisibility,
15624
15929
  dispatchId: args.dispatchId,
15625
15930
  source: args.runSource,
15626
- loadedSkillNames: args.getLoadedSkillNames(),
15627
- reasoningLevel: args.getReasoningLevel(),
15628
15931
  actor: args.actor,
15629
15932
  surface: args.surface
15630
15933
  });
@@ -16491,10 +16794,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16491
16794
  const skillInvocation = parseSkillInvocation(userInput, availableSkills);
16492
16795
  const invokedSkill = skillInvocation ? findSkillByName(skillInvocation.skillName, availableSkills) : null;
16493
16796
  const activeSkills = [];
16494
- let loadedSkillNamesForResume = [];
16495
- const syncLoadedSkillNamesForResume = () => {
16496
- loadedSkillNamesForResume = activeSkills.map((skill) => skill.name);
16497
- };
16498
16797
  const skillSandbox = new SkillSandbox(availableSkills, activeSkills);
16499
16798
  const checkpoint = await loadTurnCheckpoint({ conversationId, turnId });
16500
16799
  const resumedFromSessionRecord = checkpoint.resumed;
@@ -16529,9 +16828,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16529
16828
  ...routing.destinationVisibility ? { destinationVisibility: routing.destinationVisibility } : {},
16530
16829
  ...routing.dispatch?.id ? { dispatchId: routing.dispatch.id } : {},
16531
16830
  durability,
16532
- getLoadedSkillNames: () => loadedSkillNamesForResume,
16533
- getReasoningLevel: () => turnRoute?.reasoningLevel,
16534
- getModelId: () => activeModelId,
16535
16831
  recordActiveMcpProviders,
16536
16832
  actor,
16537
16833
  runSource,
@@ -16569,8 +16865,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16569
16865
  activeSkills,
16570
16866
  invokedSkill,
16571
16867
  priorPiMessages,
16572
- skillSandbox,
16573
- syncLoadedSkillNamesForResume
16868
+ skillSandbox
16574
16869
  });
16575
16870
  const explicitSkill = invokedSkill ? activeSkills.find((skill) => skill.name === invokedSkill.name) ?? null : null;
16576
16871
  const { contextContentParts, routerBlocks, userContentParts } = buildPromptInput(input);
@@ -16584,10 +16879,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16584
16879
  botConfig,
16585
16880
  activeModelProfile
16586
16881
  );
16587
- const resumedReasoningLevel = existingSessionRecord?.reasoningLevel ? parseTurnReasoningLevel(existingSessionRecord.reasoningLevel) : void 0;
16588
16882
  turnRoute = {
16589
16883
  profile: activeModelProfile,
16590
- reasoningLevel: activeProfileConfig.reasoningLevel ?? resumedReasoningLevel ?? storedTurnRoute.reasoningLevel,
16884
+ reasoningLevel: activeProfileConfig.reasoningLevel ?? storedTurnRoute.reasoningLevel,
16591
16885
  reason: `resumed_handoff:${storedTurnRoute.modelProfile}:${activeModelProfile}`
16592
16886
  };
16593
16887
  } else {
@@ -16797,7 +17091,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
16797
17091
  state,
16798
17092
  supportsImageInput: () => resolveGatewayModel(activeModelId).input.includes("image"),
16799
17093
  surface,
16800
- syncLoadedSkillNamesForResume,
16801
17094
  toolCalls,
16802
17095
  userInput
16803
17096
  });
@@ -17577,8 +17870,8 @@ export {
17577
17870
  deliverResourceEventSubscription,
17578
17871
  sanitizeScheduledTaskPrincipal,
17579
17872
  listThreadReplies,
17580
- renderSlackLegacyAttachmentText,
17581
- appendSlackLegacyAttachmentText,
17873
+ renderBlockText,
17874
+ renderAttachmentText,
17582
17875
  latestReportedProgress,
17583
17876
  executeCredentialedEgressRequest,
17584
17877
  createContextCompactor,