@sentry/junior 0.194.0 → 0.196.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 (97) hide show
  1. package/dist/{agent-hooks-IDX764FD.js → agent-hooks-IQLRR4RC.js} +13 -13
  2. package/dist/api/activity.d.ts +9 -1
  3. package/dist/api/code/overview.d.ts +12 -0
  4. package/dist/api/locations/detail.d.ts +8 -0
  5. package/dist/api/locations/list.d.ts +5 -0
  6. package/dist/api/people/code.d.ts +6 -0
  7. package/dist/api/people/shared.d.ts +9 -1
  8. package/dist/api/reporting-window.d.ts +39 -1
  9. package/dist/api/schema/code.d.ts +12 -0
  10. package/dist/api/schema/conversation.d.ts +25 -0
  11. package/dist/api/schema/location.d.ts +13 -0
  12. package/dist/api/schema/person.d.ts +14 -0
  13. package/dist/api/schema/task.d.ts +12 -0
  14. package/dist/api/schema.js +3 -3
  15. package/dist/api.js +244 -65
  16. package/dist/app.d.ts +8 -2
  17. package/dist/app.js +166 -70
  18. package/dist/{catalog-runtime-MICXEBLK.js → catalog-runtime-EM7V2F4I.js} +4 -4
  19. package/dist/chat/agent/handoff.d.ts +73 -0
  20. package/dist/chat/config.d.ts +3 -2
  21. package/dist/chat/event-tasks/store.d.ts +27 -17
  22. package/dist/chat/model-profile.d.ts +12 -0
  23. package/dist/chat/no-reply.d.ts +4 -3
  24. package/dist/chat/resource-events/notification.d.ts +2 -1
  25. package/dist/chat/services/automated-turn-limit.d.ts +110 -0
  26. package/dist/chat/services/subscribed-decision.d.ts +8 -0
  27. package/dist/chat/slack/automated-turn-limit-notice.d.ts +38 -0
  28. package/dist/chat/tasks/execution-stats.d.ts +2 -1
  29. package/dist/chat/tasks/read.d.ts +5 -2
  30. package/dist/chat/tools/types.d.ts +6 -2
  31. package/dist/{chunk-U76RWMFR.js → chunk-5XSEOJPC.js} +87 -14
  32. package/dist/{chunk-OEQOAONV.js → chunk-6LQNW2CJ.js} +7 -7
  33. package/dist/{chunk-GFBR4S3Q.js → chunk-7NL7T6VU.js} +1 -1
  34. package/dist/{chunk-CFGBKPWQ.js → chunk-7TUDDW3Y.js} +3 -3
  35. package/dist/{chunk-RFE7DCZK.js → chunk-B5WJBVHY.js} +2 -2
  36. package/dist/{chunk-S7GX44BU.js → chunk-BXIVMNLR.js} +1 -1
  37. package/dist/{chunk-QMEF4Z7R.js → chunk-CNI74T7U.js} +6 -6
  38. package/dist/{chunk-X76JVHQ4.js → chunk-CTS72G4B.js} +1 -1
  39. package/dist/{chunk-G35QGPO2.js → chunk-DFWJJOW3.js} +2 -6
  40. package/dist/{chunk-INTBMGNX.js → chunk-EEUFKVCD.js} +22 -22
  41. package/dist/{chunk-H4DCWLTR.js → chunk-EFNUCRB5.js} +8 -8
  42. package/dist/{chunk-V4HXV5MY.js → chunk-EQBHN4JK.js} +1 -1
  43. package/dist/{chunk-JOI3DHML.js → chunk-ES7KCEND.js} +1 -1
  44. package/dist/{chunk-WWXJUURQ.js → chunk-G6YRPYDC.js} +1 -1
  45. package/dist/{chunk-WMJS5DDV.js → chunk-GZ336GZ5.js} +148 -19
  46. package/dist/{chunk-IME5OW4Y.js → chunk-I7GEGEHZ.js} +1 -1
  47. package/dist/{chunk-2NL3Y47F.js → chunk-J357NJQ5.js} +5 -5
  48. package/dist/{chunk-53IEEFFP.js → chunk-KJGH3KWA.js} +3 -3
  49. package/dist/{chunk-ELCYG6UU.js → chunk-KZX7LORG.js} +3 -3
  50. package/dist/{chunk-YSLIB7ER.js → chunk-LBN67OZR.js} +83 -7
  51. package/dist/{chunk-73JEAQRT.js → chunk-LCAM2P7H.js} +4 -4
  52. package/dist/{chunk-VOB2DKO6.js → chunk-LGXI6PWX.js} +24 -13
  53. package/dist/{chunk-P2P6MUQ4.js → chunk-LSPUMNZK.js} +2 -2
  54. package/dist/{chunk-AWZS5SVX.js → chunk-N2MSPOGG.js} +8 -8
  55. package/dist/{chunk-CCTYK5RH.js → chunk-NE2UQMC7.js} +10 -7
  56. package/dist/{chunk-D4YV5TDV.js → chunk-NHJU2ZAL.js} +11 -0
  57. package/dist/{chunk-G4RARFNT.js → chunk-OVWAO5KY.js} +1194 -726
  58. package/dist/{chunk-XRDSML3K.js → chunk-P3LE2CSJ.js} +2 -2
  59. package/dist/{chunk-KNIAWMBU.js → chunk-PI6VXVBK.js} +1 -1
  60. package/dist/{chunk-XLWZRHX5.js → chunk-PIZJBSGZ.js} +23 -29
  61. package/dist/{chunk-GY5SEFVL.js → chunk-QAINJHI4.js} +5 -5
  62. package/dist/{chunk-XND3J6AT.js → chunk-RAWYH7TW.js} +1 -1
  63. package/dist/{chunk-ENWIHU54.js → chunk-RFNMWONZ.js} +6 -6
  64. package/dist/{chunk-E53C73ML.js → chunk-S74KAE77.js} +4 -4
  65. package/dist/{chunk-7ANA7PBB.js → chunk-SR5FS2JP.js} +3 -3
  66. package/dist/{chunk-F2KSURTJ.js → chunk-VKLQ2M7V.js} +9 -9
  67. package/dist/{chunk-NWWDFHXP.js → chunk-VRHZXY5X.js} +1 -1
  68. package/dist/{chunk-6H2MKVV5.js → chunk-VSOO3Y6M.js} +1 -1
  69. package/dist/{chunk-NPO24LAN.js → chunk-VVU7GHIZ.js} +9 -9
  70. package/dist/{chunk-IOGDKPVU.js → chunk-VXAQTJSR.js} +1 -1
  71. package/dist/{chunk-ADEACKAH.js → chunk-XNXKRWWI.js} +11 -4
  72. package/dist/cli/chat.js +35 -35
  73. package/dist/cli/check.js +5 -5
  74. package/dist/cli/plugins.js +14 -14
  75. package/dist/cli/snapshot-create.js +10 -10
  76. package/dist/cli/upgrade.js +7 -7
  77. package/dist/db/schema/event-tasks.d.ts +21 -0
  78. package/dist/db/schema.d.ts +19 -0
  79. package/dist/{db-3IEVINAY.js → db-YTM7ZXPK.js} +8 -8
  80. package/dist/instrumentation.js +3 -3
  81. package/dist/nitro.js +7 -7
  82. package/dist/{oauth-callback-server-N7L2BB4L.js → oauth-callback-server-OXW4KQLQ.js} +31 -31
  83. package/dist/{runner-PTTZV3WU.js → runner-RJY5RNJO.js} +23 -23
  84. package/dist/{skills-POMWS2RR.js → skills-WZV6NLFY.js} +5 -5
  85. package/dist/spawn-J7SQJLYF.js +42 -0
  86. package/dist/task-runner-SMUQ5464.js +36 -0
  87. package/dist/{validation-U6LOMXR7.js → validation-XS5ZHV3W.js} +5 -5
  88. package/dist/version.js +1 -1
  89. package/dist/{work-FHA3BS4L.js → work-LJMSDEY3.js} +23 -23
  90. package/dist/worker-NMFZ7A2N.js +24 -0
  91. package/migrations/0038_event_task_status.sql +5 -0
  92. package/migrations/meta/0038_snapshot.json +3323 -0
  93. package/migrations/meta/_journal.json +8 -1
  94. package/package.json +4 -4
  95. package/dist/spawn-R75MXXKE.js +0 -42
  96. package/dist/task-runner-OQLRHADB.js +0 -36
  97. package/dist/worker-GR4UNVVP.js +0 -24
@@ -7,7 +7,7 @@ import {
7
7
  PluginCredentialFailureError,
8
8
  agentNameSchema,
9
9
  createPluginAuthOrchestration
10
- } from "./chunk-QMEF4Z7R.js";
10
+ } from "./chunk-CNI74T7U.js";
11
11
  import {
12
12
  parseSandboxEgressAuthRequiredSignal,
13
13
  parseSandboxEgressPermissionDeniedSignal,
@@ -38,7 +38,7 @@ import {
38
38
  searchSlackUsers,
39
39
  selectPluginGrant,
40
40
  toMcpProviderError
41
- } from "./chunk-AWZS5SVX.js";
41
+ } from "./chunk-N2MSPOGG.js";
42
42
  import {
43
43
  RetryableDeliveryError,
44
44
  actorFromRun,
@@ -48,24 +48,24 @@ import {
48
48
  formatProviderLabel,
49
49
  getSlackMessagePermalink,
50
50
  isAgentRunFeatureDisabled,
51
+ postSlackMessage,
51
52
  resolveBaseUrl,
52
53
  surfaceFromRun,
53
54
  toolInvocationDestination,
54
55
  uploadFilesToConversation
55
- } from "./chunk-ENWIHU54.js";
56
+ } from "./chunk-RFNMWONZ.js";
56
57
  import {
57
58
  CooperativeTurnYieldError,
58
59
  NO_REPLY_MARKER,
59
60
  TurnInputCommitLostError,
60
61
  abandonReplacedPendingAuth,
61
62
  canReusePendingAuthLink,
62
- containsNoReplyMarker,
63
63
  decideReply,
64
64
  getAssistantReplyText,
65
65
  isNoReplyMarker,
66
66
  isTurnInputCommitLostError,
67
67
  sanitizeAssistantText
68
- } from "./chunk-G35QGPO2.js";
68
+ } from "./chunk-DFWJJOW3.js";
69
69
  import {
70
70
  AGENTS_REMOVAL_NOTICE,
71
71
  AGENTS_REPLACEMENT_NOTICE,
@@ -121,7 +121,7 @@ import {
121
121
  stripRuntimeTurnContext,
122
122
  trimTrailingAssistantMessages,
123
123
  truncateText
124
- } from "./chunk-OEQOAONV.js";
124
+ } from "./chunk-6LQNW2CJ.js";
125
125
  import {
126
126
  SCHEDULED_TASK_SYSTEM_ACTOR,
127
127
  WORKSPACE_SNAPSHOT_FAILED_EVENT,
@@ -162,13 +162,13 @@ import {
162
162
  workspaceSnapshotFinishedEvent,
163
163
  workspaceSnapshotWatch,
164
164
  writableEventTask
165
- } from "./chunk-WMJS5DDV.js";
165
+ } from "./chunk-GZ336GZ5.js";
166
166
  import {
167
167
  parseSlackThreadId
168
- } from "./chunk-IOGDKPVU.js";
168
+ } from "./chunk-VXAQTJSR.js";
169
169
  import {
170
170
  appendAndEnqueueInboundMessage
171
- } from "./chunk-E53C73ML.js";
171
+ } from "./chunk-S74KAE77.js";
172
172
  import {
173
173
  SHORT_TITLE_MAX_LENGTH,
174
174
  ToolInputError,
@@ -176,7 +176,7 @@ import {
176
176
  generateShortTitle,
177
177
  hasAgentTurnUsage,
178
178
  resolveTaskTitle
179
- } from "./chunk-RFE7DCZK.js";
179
+ } from "./chunk-B5WJBVHY.js";
180
180
  import {
181
181
  bindSandboxFileSystem,
182
182
  createSandboxSession,
@@ -187,7 +187,7 @@ import {
187
187
  resolve,
188
188
  setSnapshotSpanAttributes,
189
189
  stopSession
190
- } from "./chunk-ELCYG6UU.js";
190
+ } from "./chunk-KZX7LORG.js";
191
191
  import {
192
192
  privateTraceResultAttributes
193
193
  } from "./chunk-UIE3R5XU.js";
@@ -197,7 +197,7 @@ import {
197
197
  } from "./chunk-X6GDDWQH.js";
198
198
  import {
199
199
  getTurnRequestDeadline
200
- } from "./chunk-NWWDFHXP.js";
200
+ } from "./chunk-VRHZXY5X.js";
201
201
  import {
202
202
  getVercelConversationWorkQueue
203
203
  } from "./chunk-DKIJ2RP5.js";
@@ -244,19 +244,23 @@ import {
244
244
  updateWorkspace,
245
245
  withSlackRetries,
246
246
  workspaceRepoCheckoutPath
247
- } from "./chunk-CCTYK5RH.js";
247
+ } from "./chunk-NE2UQMC7.js";
248
248
  import {
249
+ JUNIOR_THREAD_STATE_TTL_MS
250
+ } from "./chunk-3Y47VMHV.js";
251
+ import {
252
+ destinationKey,
249
253
  getConversationEventStore,
250
254
  getConversationMessageSearchStore,
251
255
  getConversationStore,
252
256
  getDb,
253
257
  getSqlExecutor
254
- } from "./chunk-ADEACKAH.js";
258
+ } from "./chunk-XNXKRWWI.js";
255
259
  import {
256
260
  juniorArtifacts,
257
261
  juniorIdentities,
258
262
  juniorSchedulerRuns
259
- } from "./chunk-XLWZRHX5.js";
263
+ } from "./chunk-PIZJBSGZ.js";
260
264
  import {
261
265
  SANDBOX_DATA_ROOT,
262
266
  SANDBOX_REPOS_ROOT,
@@ -287,19 +291,19 @@ import {
287
291
  throwSandboxOperationError,
288
292
  workspaceSnapshotNotReadyUserMessage,
289
293
  wrapSandboxSetupError
290
- } from "./chunk-7ANA7PBB.js";
294
+ } from "./chunk-SR5FS2JP.js";
291
295
  import {
292
296
  fenceLock,
293
297
  getStateAdapter,
294
298
  withLock
295
- } from "./chunk-V4HXV5MY.js";
299
+ } from "./chunk-EQBHN4JK.js";
296
300
  import {
297
301
  KNOWN_CONVERSATION_EVENT_TYPES,
298
302
  contextProvenance,
299
303
  instructionActors,
300
304
  instructionProvenanceFor,
301
305
  sameActorIdentity
302
- } from "./chunk-GFBR4S3Q.js";
306
+ } from "./chunk-7NL7T6VU.js";
303
307
  import {
304
308
  ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
305
309
  COMPACTION_SUMMARY_PREFIX,
@@ -325,14 +329,16 @@ import {
325
329
  resolveGatewayCredential,
326
330
  resolveGatewayModel,
327
331
  unwrapCurrentInstruction
328
- } from "./chunk-U76RWMFR.js";
332
+ } from "./chunk-5XSEOJPC.js";
329
333
  import {
330
334
  ModelProfileNotConfiguredError,
331
335
  TURN_REASONING_LEVELS,
336
+ formatModelProfile,
337
+ formatModelProfiles,
332
338
  modelIdForProfile,
333
339
  modelProfileSchema,
334
340
  profileConfig
335
- } from "./chunk-D4YV5TDV.js";
341
+ } from "./chunk-NHJU2ZAL.js";
336
342
  import {
337
343
  canExposeConversationPayload,
338
344
  resolveConversationPrivacy,
@@ -342,16 +348,16 @@ import {
342
348
  toGenAiMessagesTraceAttributes,
343
349
  toGenAiPayloadMetadata,
344
350
  toGenAiPayloadTraceAttributes
345
- } from "./chunk-JOI3DHML.js";
351
+ } from "./chunk-ES7KCEND.js";
346
352
  import {
347
353
  discoverSkills,
348
354
  findSkillByName,
349
355
  loadSkillsByName,
350
356
  parseSkillInvocation
351
- } from "./chunk-P2P6MUQ4.js";
357
+ } from "./chunk-LSPUMNZK.js";
352
358
  import {
353
359
  pluginCatalogRuntime
354
- } from "./chunk-WWXJUURQ.js";
360
+ } from "./chunk-G6YRPYDC.js";
355
361
  import {
356
362
  CredentialUnavailableError,
357
363
  OAuthProviderError,
@@ -359,7 +365,7 @@ import {
359
365
  getOAuthProviderErrorAttributes,
360
366
  resolveAuthTokenPlaceholder,
361
367
  resolvePluginCommandEnv
362
- } from "./chunk-S7GX44BU.js";
368
+ } from "./chunk-BXIVMNLR.js";
363
369
  import {
364
370
  credentialContextForActor,
365
371
  credentialUserSubjectId
@@ -395,7 +401,7 @@ import {
395
401
  summarizeMessageText,
396
402
  withLogContext,
397
403
  withSpan
398
- } from "./chunk-X76JVHQ4.js";
404
+ } from "./chunk-CTS72G4B.js";
399
405
  import {
400
406
  startInactiveSpan,
401
407
  withActiveSpan
@@ -919,11 +925,6 @@ function buildTurnResult(input) {
919
925
  if (!isProviderError) {
920
926
  logInfo("ai.no_reply_marker.accepted", markerAttributes);
921
927
  }
922
- } else if (containsNoReplyMarker(rawPrimaryText)) {
923
- logWarn("ai.no_reply_marker.mixed_text", {
924
- "app.ai.no_reply_marker": true,
925
- "app.ai.no_reply_marker_mode": "mixed"
926
- });
927
928
  }
928
929
  if (!primaryText && !completedWithoutTerminalText && !isProviderError) {
929
930
  logWarn("ai.model_response.empty", {
@@ -1141,11 +1142,11 @@ function trimContextForRouter(text) {
1141
1142
  originalCharCount: trimmed.length
1142
1143
  };
1143
1144
  }
1144
- function buildClassifierSystemPrompt(profileNames, defaultProfile) {
1145
+ function buildClassifierSystemPrompt(profiles, profileNames, defaultProfile) {
1146
+ const profileList = formatModelProfiles(profiles, profileNames);
1145
1147
  return [
1146
1148
  "You choose the model profile most likely to produce a complete, source-grounded answer.",
1147
1149
  "Choose exactly one bucket: none, low, medium, high, or xhigh.",
1148
- `Choose profile from the configured profiles: ${profileNames.join(", ")}.`,
1149
1150
  "Choose profile independently from the reasoning bucket.",
1150
1151
  "",
1151
1152
  "Use none only for greetings, acknowledgments, and turns that need no substantive assistant work.",
@@ -1154,9 +1155,11 @@ function buildClassifierSystemPrompt(profileNames, defaultProfile) {
1154
1155
  "Use high for research-heavy work, non-trivial drafting, or explicit requests to be thorough.",
1155
1156
  "Use xhigh for the most complex tasks: code changes, debugging/root-cause analysis, broad refactors, architecture decisions, multi-file implementation, or any task where deep reasoning across multiple systems or files is required.",
1156
1157
  "When unsure between two non-none buckets, choose the higher bucket. Do not use low as the default.",
1157
- `The default profile is ${defaultProfile}.`,
1158
- "Profile names are configured labels. Do not assume that a non-default profile is more capable than the default profile.",
1159
- "Choose a non-default profile only when its label clearly matches the task. Otherwise keep the default profile.",
1158
+ "",
1159
+ `Default profile: "${defaultProfile}". Keep it unless another profile's description is a clearly better fit.`,
1160
+ "Configured profiles (use each description's use and avoid cases; names are labels only; non-default does not mean stronger):",
1161
+ profileList,
1162
+ "Choose a non-default profile only when its description clearly fits the task. If no description clearly fits, keep the default profile.",
1160
1163
  "",
1161
1164
  "Classify based on the substance of the task, not the length of the current message. When the current instruction is a short affirmation (for example: 'go', 'do it', 'yes please', 'proceed') and prior thread context contains a pending task, classify the pending task \u2014 not the affirmation.",
1162
1165
  "",
@@ -1294,6 +1297,7 @@ async function classifyTurn(args) {
1294
1297
  prompt: args.prompt,
1295
1298
  thinkingLevel: "low",
1296
1299
  system: buildClassifierSystemPrompt(
1300
+ args.profiles,
1297
1301
  Object.keys(args.profiles),
1298
1302
  args.defaultProfile
1299
1303
  ),
@@ -1728,7 +1732,7 @@ var TOOL_POLICY_RULES = [
1728
1732
  "- Event tasks make the task creator's connected credentials available by default when the requested work needs user-bound authorization. Do not ask for separate confirmation merely to use credentials needed for the requested work. On creation, omit credentialMode for the creator default and set system only when the creator explicitly requires it. For later changes, creator always means the task's original createdBy actor, never the current requester. If the requester is not that creator, do not attempt to enable creator credential use or suggest that confirmation could authorize it.",
1729
1733
  "- Event tasks list for the current destination, not one thread. Public tasks can also be updated or deleted by task id from another destination in the same workspace. When listing them, use createdBy to explain creator-only credential changes and warn when triggerAvailable is false; an unavailable task remains stored but cannot receive events until its plugin event is enabled again.",
1730
1734
  "- Scheduled tasks make the task creator's connected credentials available by default when the requested work needs user-bound authorization. Do not ask for separate confirmation merely to use credentials needed for the requested work. On creation, omit credential_mode for the creator default and set system only when the creator explicitly requires it. For later changes, creator always means the task's original created_by actor, never the current requester. If the requester is not that creator, do not attempt to enable creator credential use or suggest that confirmation could authorize it.",
1731
- "- For code changes, debugging or root-cause analysis, broad refactors, and software architecture decisions, use `handoff` before substantive analysis only when it offers a profile that better matches the task. Do not switch merely because the task involves code.",
1735
+ "- When another model profile fits the task better, call `handoff` before substantial work. Follow the profile list and selection rules in the tool description.",
1732
1736
  "- Run `jr-rpc config get|set|unset|list` for provider defaults and `jr-rpc plugins list` for installed plugin introspection as standalone bash commands; do not chain them with `cd`, `&&`, pipes, or provider commands.",
1733
1737
  "- If the first result is empty, stale, ambiguous, or incomplete, try a focused alternate query, path, command, or source before concluding the answer cannot be verified."
1734
1738
  ];
@@ -3096,11 +3100,358 @@ async function prepareWorkspaceSnapshot(params) {
3096
3100
  // src/chat/resource-events/ingest.ts
3097
3101
  import { resourceEventSchema } from "@sentry/junior-plugin-api";
3098
3102
 
3103
+ // src/chat/services/automated-turn-limit.ts
3104
+ import { z as z3 } from "zod";
3105
+ var AUTOMATED_TURN_LIMIT_PREFIX = "junior:automated_turn_limit:v1";
3106
+ var AUTOMATED_TURN_LIMIT_LOCK_TTL_MS = 5e3;
3107
+ var AUTOMATED_TURN_LIMIT_LOCK_WAIT_MS = 2e3;
3108
+ var AUTOMATED_TURN_LIMIT_LOCK_RETRY_MS = 25;
3109
+ var automatedTurnLimitStateSchema = z3.object({
3110
+ consecutiveAutomatedTurns: z3.number().int().nonnegative(),
3111
+ noticePostedAtMs: z3.number().finite().nonnegative().optional(),
3112
+ paused: z3.boolean(),
3113
+ updatedAtMs: z3.number().finite().nonnegative()
3114
+ }).strict();
3115
+ function sleep2(ms) {
3116
+ return new Promise((resolve2) => {
3117
+ const timer = setTimeout(resolve2, ms);
3118
+ timer.unref?.();
3119
+ });
3120
+ }
3121
+ function scopeKey(scope) {
3122
+ if (scope.kind === "conversation") {
3123
+ return `${AUTOMATED_TURN_LIMIT_PREFIX}:conversation:${scope.conversationId}`;
3124
+ }
3125
+ return `${AUTOMATED_TURN_LIMIT_PREFIX}:destination:${destinationKey(scope.destination)}`;
3126
+ }
3127
+ function lockKey(key) {
3128
+ return `${key}:lock`;
3129
+ }
3130
+ function parseState(value) {
3131
+ const parsed = automatedTurnLimitStateSchema.safeParse(value);
3132
+ return parsed.success ? parsed.data : void 0;
3133
+ }
3134
+ async function acquireScopeLock(state, key, waitDeadlineMs = Date.now() + AUTOMATED_TURN_LIMIT_LOCK_WAIT_MS) {
3135
+ while (true) {
3136
+ const lock = await state.acquireLock(
3137
+ lockKey(key),
3138
+ AUTOMATED_TURN_LIMIT_LOCK_TTL_MS
3139
+ );
3140
+ if (lock) {
3141
+ return lock;
3142
+ }
3143
+ if (Date.now() >= waitDeadlineMs) {
3144
+ throw new Error(`Could not acquire automated turn limit lock for ${key}`);
3145
+ }
3146
+ await sleep2(AUTOMATED_TURN_LIMIT_LOCK_RETRY_MS);
3147
+ }
3148
+ }
3149
+ async function withScopeLock(state, key, callback) {
3150
+ const lock = await acquireScopeLock(state, key);
3151
+ try {
3152
+ return await callback();
3153
+ } finally {
3154
+ await state.releaseLock(lock);
3155
+ }
3156
+ }
3157
+ function emptyState(nowMs) {
3158
+ return {
3159
+ consecutiveAutomatedTurns: 0,
3160
+ paused: false,
3161
+ updatedAtMs: nowMs
3162
+ };
3163
+ }
3164
+ function resumeInForScope(scope) {
3165
+ return scope.kind === "conversation" ? "thread" : "channel";
3166
+ }
3167
+ function isAutomatedTurnSource(source) {
3168
+ if (!source) {
3169
+ return false;
3170
+ }
3171
+ return source.kind === "resource_event" || source.kind === "event_task" || source.kind === "scheduled_task" || source.kind === "plugin_dispatch" || source.kind === "agent_invocation";
3172
+ }
3173
+ function automatedTurnLimitScopeForSource(args) {
3174
+ if (!isAutomatedTurnSource(args.source)) {
3175
+ return void 0;
3176
+ }
3177
+ if (args.source?.kind === "resource_event") {
3178
+ return {
3179
+ kind: "conversation",
3180
+ conversationId: args.conversationId
3181
+ };
3182
+ }
3183
+ if (args.destination) {
3184
+ return { kind: "destination", destination: args.destination };
3185
+ }
3186
+ return {
3187
+ kind: "conversation",
3188
+ conversationId: args.conversationId
3189
+ };
3190
+ }
3191
+ function buildAutomatedTurnLimitResponse(args) {
3192
+ const place = args.resumeIn === "channel" ? "channel" : "thread";
3193
+ return `I stopped automatic updates after ${args.maxTurns} replies without a new message from you. Send a message or @mention me in this ${place} to continue.`;
3194
+ }
3195
+ async function admitAutomatedTurn(args) {
3196
+ if (args.maxTurns < 1) {
3197
+ throw new Error("Automated turn limit must be at least 1");
3198
+ }
3199
+ const state = args.state ?? getStateAdapter();
3200
+ await state.connect();
3201
+ const nowMs = args.nowMs ?? Date.now();
3202
+ const key = scopeKey(args.scope);
3203
+ return await withScopeLock(state, key, async () => {
3204
+ const current = parseState(await state.get(key)) ?? emptyState(nowMs);
3205
+ if (current.paused || current.consecutiveAutomatedTurns >= args.maxTurns) {
3206
+ const shouldPostNotice = current.noticePostedAtMs === void 0;
3207
+ const next = {
3208
+ consecutiveAutomatedTurns: Math.max(
3209
+ current.consecutiveAutomatedTurns,
3210
+ args.maxTurns
3211
+ ),
3212
+ paused: true,
3213
+ updatedAtMs: nowMs,
3214
+ // Claim the notice slot so concurrent paused wakes do not all post.
3215
+ // Callers must mark success or clear the claim if the post fails.
3216
+ ...shouldPostNotice ? { noticePostedAtMs: nowMs } : current.noticePostedAtMs !== void 0 ? { noticePostedAtMs: current.noticePostedAtMs } : void 0
3217
+ };
3218
+ await state.set(key, next, JUNIOR_THREAD_STATE_TTL_MS);
3219
+ return {
3220
+ status: "paused",
3221
+ consecutiveAutomatedTurns: next.consecutiveAutomatedTurns,
3222
+ shouldPostNotice
3223
+ };
3224
+ }
3225
+ return {
3226
+ status: "allow",
3227
+ consecutiveAutomatedTurns: current.consecutiveAutomatedTurns
3228
+ };
3229
+ });
3230
+ }
3231
+ async function countAutomatedTurn(args) {
3232
+ if (args.maxTurns < 1) {
3233
+ throw new Error("Automated turn limit must be at least 1");
3234
+ }
3235
+ const state = args.state ?? getStateAdapter();
3236
+ await state.connect();
3237
+ const nowMs = args.nowMs ?? Date.now();
3238
+ const key = scopeKey(args.scope);
3239
+ const resumeIn = resumeInForScope(args.scope);
3240
+ return await withScopeLock(state, key, async () => {
3241
+ const current = parseState(await state.get(key)) ?? emptyState(nowMs);
3242
+ const consecutiveAutomatedTurns = current.consecutiveAutomatedTurns + 1;
3243
+ const paused = consecutiveAutomatedTurns >= args.maxTurns;
3244
+ const shouldPostNotice = paused && current.noticePostedAtMs === void 0;
3245
+ const next = {
3246
+ consecutiveAutomatedTurns,
3247
+ paused,
3248
+ updatedAtMs: nowMs,
3249
+ // Claim the notice slot before the destination post. Mark success after
3250
+ // the post lands; clear the claim if the post fails or is skipped.
3251
+ ...shouldPostNotice ? { noticePostedAtMs: nowMs } : current.noticePostedAtMs !== void 0 ? { noticePostedAtMs: current.noticePostedAtMs } : void 0
3252
+ };
3253
+ await state.set(key, next, JUNIOR_THREAD_STATE_TTL_MS);
3254
+ return {
3255
+ consecutiveAutomatedTurns,
3256
+ paused,
3257
+ shouldPostNotice,
3258
+ resumeIn
3259
+ };
3260
+ });
3261
+ }
3262
+ async function clearAutomatedTurnLimitNoticeClaim(args) {
3263
+ const state = args.state ?? getStateAdapter();
3264
+ await state.connect();
3265
+ const nowMs = args.nowMs ?? Date.now();
3266
+ const key = scopeKey(args.scope);
3267
+ await withScopeLock(state, key, async () => {
3268
+ const current = parseState(await state.get(key));
3269
+ if (!current || current.noticePostedAtMs === void 0) {
3270
+ return;
3271
+ }
3272
+ const { noticePostedAtMs: _noticePostedAtMs, ...rest } = current;
3273
+ await state.set(
3274
+ key,
3275
+ {
3276
+ ...rest,
3277
+ updatedAtMs: nowMs
3278
+ },
3279
+ JUNIOR_THREAD_STATE_TTL_MS
3280
+ );
3281
+ });
3282
+ }
3283
+ async function resetAutomatedTurnLimit(args) {
3284
+ const state = args.state ?? getStateAdapter();
3285
+ await state.connect();
3286
+ const key = scopeKey(args.scope);
3287
+ await withScopeLock(state, key, async () => {
3288
+ await state.delete(key);
3289
+ });
3290
+ }
3291
+ async function recordFinishedTurnForAutomatedLimit(args) {
3292
+ const nowMs = args.nowMs ?? Date.now();
3293
+ const automatedScope = automatedTurnLimitScopeForSource({
3294
+ conversationId: args.conversationId,
3295
+ destination: args.destination,
3296
+ source: args.source
3297
+ });
3298
+ if (automatedScope) {
3299
+ return await countAutomatedTurn({
3300
+ maxTurns: args.maxTurns,
3301
+ nowMs,
3302
+ scope: automatedScope,
3303
+ state: args.state
3304
+ });
3305
+ }
3306
+ await resetAutomatedTurnLimit({
3307
+ nowMs,
3308
+ scope: {
3309
+ kind: "conversation",
3310
+ conversationId: args.conversationId
3311
+ },
3312
+ state: args.state
3313
+ });
3314
+ if (args.destination) {
3315
+ await resetAutomatedTurnLimit({
3316
+ nowMs,
3317
+ scope: { kind: "destination", destination: args.destination },
3318
+ state: args.state
3319
+ });
3320
+ }
3321
+ return void 0;
3322
+ }
3323
+
3324
+ // src/chat/slack/automated-turn-limit-notice.ts
3325
+ async function releaseFailedNoticeClaim(args) {
3326
+ try {
3327
+ await clearAutomatedTurnLimitNoticeClaim(args);
3328
+ } catch (error) {
3329
+ logException(error, "automated_turn_limit.notice_claim_clear_failed");
3330
+ }
3331
+ }
3332
+ async function postAutomatedTurnLimitNoticeForConversation(args) {
3333
+ const scope = args.scope ?? {
3334
+ kind: "conversation",
3335
+ conversationId: args.conversationId
3336
+ };
3337
+ try {
3338
+ const conversation = await getConversationStore().get({
3339
+ conversationId: args.conversationId
3340
+ });
3341
+ const location = conversation?.location;
3342
+ if (!location || location.provider !== "slack") {
3343
+ logWarn("automated_turn_limit.notice_skipped", {
3344
+ conversationId: args.conversationId,
3345
+ "app.automated_turn_limit.reason": location ? "unsupported_location" : "missing_location"
3346
+ });
3347
+ await releaseFailedNoticeClaim({
3348
+ nowMs: args.nowMs,
3349
+ scope
3350
+ });
3351
+ return false;
3352
+ }
3353
+ await postSlackMessage({
3354
+ channelId: location.channelId,
3355
+ text: buildAutomatedTurnLimitResponse({
3356
+ maxTurns: args.maxTurns,
3357
+ resumeIn: args.resumeIn ?? "thread"
3358
+ }),
3359
+ ...location.threadTs ? { threadTs: location.threadTs } : void 0
3360
+ });
3361
+ return true;
3362
+ } catch (error) {
3363
+ logException(error, "automated_turn_limit.notice_failed", {
3364
+ conversationId: args.conversationId
3365
+ });
3366
+ await releaseFailedNoticeClaim({
3367
+ nowMs: args.nowMs,
3368
+ scope
3369
+ });
3370
+ return false;
3371
+ }
3372
+ }
3373
+ async function postAutomatedTurnLimitNoticeForDestination(args) {
3374
+ const scope = args.scope ?? {
3375
+ kind: "destination",
3376
+ destination: args.destination
3377
+ };
3378
+ if (args.destination.platform !== "slack") {
3379
+ logWarn("automated_turn_limit.notice_skipped", {
3380
+ "app.automated_turn_limit.reason": "unsupported_destination"
3381
+ });
3382
+ await releaseFailedNoticeClaim({
3383
+ nowMs: args.nowMs,
3384
+ scope
3385
+ });
3386
+ return false;
3387
+ }
3388
+ try {
3389
+ await postSlackMessage({
3390
+ channelId: args.destination.channelId,
3391
+ text: buildAutomatedTurnLimitResponse({
3392
+ maxTurns: args.maxTurns,
3393
+ resumeIn: args.resumeIn ?? "channel"
3394
+ }),
3395
+ ...args.threadTs ? { threadTs: args.threadTs } : void 0
3396
+ });
3397
+ return true;
3398
+ } catch (error) {
3399
+ logException(error, "automated_turn_limit.notice_failed", {
3400
+ "app.slack.channel_id": args.destination.channelId,
3401
+ "app.slack.team_id": args.destination.teamId
3402
+ });
3403
+ await releaseFailedNoticeClaim({
3404
+ nowMs: args.nowMs,
3405
+ scope
3406
+ });
3407
+ return false;
3408
+ }
3409
+ }
3410
+ async function maybePostAutomatedTurnLimitNotice(args) {
3411
+ if (!args.update?.shouldPostNotice) {
3412
+ return;
3413
+ }
3414
+ if (args.update.resumeIn === "thread") {
3415
+ await postAutomatedTurnLimitNoticeForConversation({
3416
+ conversationId: args.conversationId,
3417
+ maxTurns: args.maxTurns,
3418
+ nowMs: args.nowMs,
3419
+ resumeIn: "thread",
3420
+ scope: {
3421
+ kind: "conversation",
3422
+ conversationId: args.conversationId
3423
+ }
3424
+ });
3425
+ return;
3426
+ }
3427
+ if (args.destination) {
3428
+ await postAutomatedTurnLimitNoticeForDestination({
3429
+ destination: args.destination,
3430
+ maxTurns: args.maxTurns,
3431
+ nowMs: args.nowMs,
3432
+ resumeIn: "channel",
3433
+ scope: { kind: "destination", destination: args.destination },
3434
+ threadTs: args.threadTs
3435
+ });
3436
+ return;
3437
+ }
3438
+ await postAutomatedTurnLimitNoticeForConversation({
3439
+ conversationId: args.conversationId,
3440
+ maxTurns: args.maxTurns,
3441
+ nowMs: args.nowMs,
3442
+ resumeIn: args.update.resumeIn,
3443
+ scope: {
3444
+ kind: "conversation",
3445
+ conversationId: args.conversationId
3446
+ }
3447
+ });
3448
+ }
3449
+
3099
3450
  // src/chat/task-input.ts
3100
3451
  function replyContractLines() {
3101
3452
  return [
3102
3453
  "When you reply, follow any reply format in the instructions.",
3103
- `If no visible reply is needed, make the final message exactly ${NO_REPLY_MARKER}.`,
3454
+ `If no visible reply is needed, your final assistant message must be exactly ${NO_REPLY_MARKER} and nothing else.`,
3104
3455
  "Otherwise briefly summarize what you acted on and what you did or need next."
3105
3456
  ];
3106
3457
  }
@@ -3235,6 +3586,38 @@ function createResourceEventInboundMessage(input) {
3235
3586
  };
3236
3587
  }
3237
3588
  async function enqueueResourceEventNotification(args) {
3589
+ const maxTurns = botConfig.maxConsecutiveAutomatedTurns;
3590
+ const decision = await admitAutomatedTurn({
3591
+ maxTurns,
3592
+ nowMs: args.event.occurredAtMs,
3593
+ scope: {
3594
+ kind: "conversation",
3595
+ conversationId: args.subscription.conversationId
3596
+ },
3597
+ state: args.state
3598
+ });
3599
+ if (decision.status === "paused") {
3600
+ logInfo("resource_events.automated_turn_limit.paused", {
3601
+ conversationId: args.subscription.conversationId,
3602
+ "app.automated_turn_limit.consecutive": decision.consecutiveAutomatedTurns,
3603
+ "app.automated_turn_limit.max": maxTurns,
3604
+ "app.resource_event.event_type": args.event.eventType,
3605
+ "app.resource_event.namespace": args.event.namespace
3606
+ });
3607
+ if (decision.shouldPostNotice) {
3608
+ await postAutomatedTurnLimitNoticeForConversation({
3609
+ conversationId: args.subscription.conversationId,
3610
+ maxTurns,
3611
+ nowMs: args.event.occurredAtMs,
3612
+ resumeIn: "thread",
3613
+ scope: {
3614
+ kind: "conversation",
3615
+ conversationId: args.subscription.conversationId
3616
+ }
3617
+ });
3618
+ }
3619
+ return { status: "duplicate" };
3620
+ }
3238
3621
  const text = renderResourceEventNotificationText(
3239
3622
  args.subscription,
3240
3623
  args.event
@@ -5008,10 +5391,10 @@ function validateAndApplyTextEdits(content, edits, targetName) {
5008
5391
  }
5009
5392
 
5010
5393
  // src/chat/tools/sandbox/edit-file.ts
5011
- import { z as z4 } from "zod";
5394
+ import { z as z5 } from "zod";
5012
5395
 
5013
5396
  // src/chat/tool-support/zod-tool.ts
5014
- import { z as z3 } from "zod";
5397
+ import { z as z4 } from "zod";
5015
5398
  function isContentOnlyToolResult(value) {
5016
5399
  return value !== null && typeof value === "object" && Array.isArray(value.content) && !("details" in value);
5017
5400
  }
@@ -5048,7 +5431,7 @@ function zodTool(definition) {
5048
5431
  const { inputSchema: inputSchema2, outputSchema: outputSchema7, prepareArguments, execute, ...toolDef } = definition;
5049
5432
  let modelInputSchema;
5050
5433
  try {
5051
- modelInputSchema = z3.toJSONSchema(inputSchema2);
5434
+ modelInputSchema = z4.toJSONSchema(inputSchema2);
5052
5435
  } catch (error) {
5053
5436
  throw new TypeError(
5054
5437
  "zodTool() inputSchema must be representable as JSON Schema.",
@@ -5058,7 +5441,7 @@ function zodTool(definition) {
5058
5441
  let modelOutputSchema;
5059
5442
  if (outputSchema7) {
5060
5443
  try {
5061
- modelOutputSchema = z3.toJSONSchema(outputSchema7);
5444
+ modelOutputSchema = z4.toJSONSchema(outputSchema7);
5062
5445
  } catch (error) {
5063
5446
  throw new TypeError(
5064
5447
  "zodTool() outputSchema must be representable as JSON Schema.",
@@ -5143,11 +5526,11 @@ async function editFile(params) {
5143
5526
  truncated: diff.truncated
5144
5527
  });
5145
5528
  }
5146
- var editReplacementSchema = z4.object({
5147
- oldText: z4.string().min(1).describe(
5529
+ var editReplacementSchema = z5.object({
5530
+ oldText: z5.string().min(1).describe(
5148
5531
  "Exact text to replace. It must be unique in the original file and must not overlap another edit."
5149
5532
  ),
5150
- newText: z4.string().describe("Replacement text for this edit.")
5533
+ newText: z5.string().describe("Replacement text for this edit.")
5151
5534
  });
5152
5535
  function createEditFileTool() {
5153
5536
  return zodTool({
@@ -5160,9 +5543,9 @@ function createEditFileTool() {
5160
5543
  description: "Edit one sandbox workspace file with exact text replacements. Use for precise changes to existing files; prefer this over writeFile for targeted changes. Each oldText must match exactly, be unique, and not overlap another edit. Returns a diff. Multiple changes to the same file: use one edits[] call.",
5161
5544
  prepareArguments: prepareEditFileArguments,
5162
5545
  executionMode: "sequential",
5163
- inputSchema: z4.object({
5164
- path: z4.string().min(1).describe("Path to edit in the sandbox workspace."),
5165
- edits: z4.array(editReplacementSchema).min(1).describe(
5546
+ inputSchema: z5.object({
5547
+ path: z5.string().min(1).describe("Path to edit in the sandbox workspace."),
5548
+ edits: z5.array(editReplacementSchema).min(1).describe(
5166
5549
  "Exact replacements matched against the original file, not incrementally."
5167
5550
  )
5168
5551
  }),
@@ -5177,7 +5560,7 @@ function createEditFileTool() {
5177
5560
 
5178
5561
  // src/chat/tools/sandbox/find-files.ts
5179
5562
  import path4 from "path";
5180
- import { z as z5 } from "zod";
5563
+ import { z as z6 } from "zod";
5181
5564
  var DEFAULT_FIND_LIMIT = 100;
5182
5565
  async function findFiles(params) {
5183
5566
  if (!params.pattern.trim()) {
@@ -5350,14 +5733,14 @@ function createFindFilesTool() {
5350
5733
  openWorldHint: false,
5351
5734
  readOnlyHint: true
5352
5735
  },
5353
- inputSchema: z5.object({
5354
- pattern: z5.string().min(1).describe(
5736
+ inputSchema: z6.object({
5737
+ pattern: z6.string().min(1).describe(
5355
5738
  "Glob pattern to match, for example '*.ts', '**/*.json', or 'src/**/*.test.ts'."
5356
5739
  ),
5357
- path: z5.string().min(1).describe(
5740
+ path: z6.string().min(1).describe(
5358
5741
  "Directory or file path in the sandbox workspace. Defaults to the workspace root."
5359
5742
  ).optional(),
5360
- limit: z5.coerce.number().int().min(1).describe("Maximum number of file paths to return. Defaults to 100.").optional()
5743
+ limit: z6.coerce.number().int().min(1).describe("Maximum number of file paths to return. Defaults to 100.").optional()
5361
5744
  }),
5362
5745
  outputSchema: juniorToolOutputSchema,
5363
5746
  execute: async () => {
@@ -5370,12 +5753,12 @@ function createFindFilesTool() {
5370
5753
 
5371
5754
  // src/chat/tools/sandbox/grep.ts
5372
5755
  import path5 from "path";
5373
- import { z as z6 } from "zod";
5756
+ import { z as z7 } from "zod";
5374
5757
  var DEFAULT_GREP_LIMIT = 100;
5375
5758
  var MAX_GREP_LINE_CHARS = 500;
5376
- var booleanInput = (description) => z6.preprocess(
5759
+ var booleanInput = (description) => z7.preprocess(
5377
5760
  (value) => value === "true" ? true : value === "false" ? false : value,
5378
- z6.boolean()
5761
+ z7.boolean()
5379
5762
  ).describe(description);
5380
5763
  function truncateGrepLine(value) {
5381
5764
  if (value.length <= MAX_GREP_LINE_CHARS) {
@@ -5729,20 +6112,20 @@ function createGrepTool() {
5729
6112
  openWorldHint: false,
5730
6113
  readOnlyHint: true
5731
6114
  },
5732
- inputSchema: z6.object({
5733
- pattern: z6.string().min(1).describe("Regex pattern or literal text to search for."),
5734
- path: z6.string().min(1).describe(
6115
+ inputSchema: z7.object({
6116
+ pattern: z7.string().min(1).describe("Regex pattern or literal text to search for."),
6117
+ path: z7.string().min(1).describe(
5735
6118
  "Directory or file path in the sandbox workspace. Defaults to the workspace root."
5736
6119
  ).optional(),
5737
- glob: z6.string().min(1).describe("Optional glob filter such as '*.ts' or '**/*.test.ts'.").optional(),
6120
+ glob: z7.string().min(1).describe("Optional glob filter such as '*.ts' or '**/*.test.ts'.").optional(),
5738
6121
  ignoreCase: booleanInput(
5739
6122
  "Whether matching should ignore case."
5740
6123
  ).optional(),
5741
6124
  literal: booleanInput(
5742
6125
  "Treat pattern as literal text instead of regex."
5743
6126
  ).optional(),
5744
- context: z6.coerce.number().int().min(0).describe("Number of surrounding context lines to include.").optional(),
5745
- limit: z6.coerce.number().int().min(1).describe("Maximum matches to return. Defaults to 100.").optional()
6127
+ context: z7.coerce.number().int().min(0).describe("Number of surrounding context lines to include.").optional(),
6128
+ limit: z7.coerce.number().int().min(1).describe("Maximum matches to return. Defaults to 100.").optional()
5746
6129
  }),
5747
6130
  outputSchema: juniorToolOutputSchema,
5748
6131
  execute: async () => {
@@ -5753,7 +6136,7 @@ function createGrepTool() {
5753
6136
 
5754
6137
  // src/chat/tools/sandbox/list-dir.ts
5755
6138
  import path6 from "path";
5756
- import { z as z7 } from "zod";
6139
+ import { z as z8 } from "zod";
5757
6140
  var DEFAULT_LIST_LIMIT = 500;
5758
6141
  async function listDir(params) {
5759
6142
  const dirPath = resolveWorkspacePath(params.path);
@@ -5834,11 +6217,11 @@ function createListDirTool() {
5834
6217
  openWorldHint: false,
5835
6218
  readOnlyHint: true
5836
6219
  },
5837
- inputSchema: z7.object({
5838
- path: z7.string().min(1).describe(
6220
+ inputSchema: z8.object({
6221
+ path: z8.string().min(1).describe(
5839
6222
  "Directory path in the sandbox workspace. Defaults to the workspace root."
5840
6223
  ).optional(),
5841
- limit: z7.coerce.number().int().min(1).describe("Maximum entries to return. Defaults to 500.").optional()
6224
+ limit: z8.coerce.number().int().min(1).describe("Maximum entries to return. Defaults to 500.").optional()
5842
6225
  }),
5843
6226
  outputSchema: juniorToolOutputSchema,
5844
6227
  execute: async () => {
@@ -5850,7 +6233,7 @@ function createListDirTool() {
5850
6233
  }
5851
6234
 
5852
6235
  // src/chat/tools/sandbox/read-file.ts
5853
- import { z as z8 } from "zod";
6236
+ import { z as z9 } from "zod";
5854
6237
 
5855
6238
  // src/chat/tool-support/text-range-result.ts
5856
6239
  var DEFAULT_READ_LIMIT = 1e3;
@@ -5944,10 +6327,10 @@ function createReadFileTool() {
5944
6327
  openWorldHint: false,
5945
6328
  readOnlyHint: true
5946
6329
  },
5947
- inputSchema: z8.object({
5948
- path: z8.string().min(1).describe("Path to the file in the sandbox workspace."),
5949
- offset: z8.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
5950
- limit: z8.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
6330
+ inputSchema: z9.object({
6331
+ path: z9.string().min(1).describe("Path to the file in the sandbox workspace."),
6332
+ offset: z9.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
6333
+ limit: z9.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
5951
6334
  }),
5952
6335
  outputSchema: juniorToolOutputSchema,
5953
6336
  execute: async () => {
@@ -6547,25 +6930,25 @@ function createSandbox(options) {
6547
6930
 
6548
6931
  // src/chat/tools/sandbox/file-uploads.ts
6549
6932
  import path7 from "path";
6550
- import { z as z9 } from "zod";
6933
+ import { z as z10 } from "zod";
6551
6934
  var MAX_SANDBOX_FILE_UPLOAD_BYTES = 10 * 1024 * 1024;
6552
6935
  var SANDBOX_ARTIFACTS_DIR = "/tmp/junior/artifacts";
6553
- var sandboxFileReferenceSchema = z9.object({
6554
- path: z9.string().min(1).describe(
6936
+ var sandboxFileReferenceSchema = z10.object({
6937
+ path: z10.string().min(1).describe(
6555
6938
  "Exact source path of an existing sandbox file. Preserve paths returned by other tools unchanged; do not move or rewrite them before sending."
6556
6939
  ),
6557
- filename: z9.string().min(1).nullable().optional().describe(
6940
+ filename: z10.string().min(1).nullable().optional().describe(
6558
6941
  "Optional filename override shown to the recipient. Null is treated as omitted."
6559
6942
  ),
6560
- mimeType: z9.string().min(1).nullable().optional().describe("Optional MIME type override. Null is treated as omitted."),
6561
- bytes: z9.number().int().nonnegative().nullable().optional().describe(
6943
+ mimeType: z10.string().min(1).nullable().optional().describe("Optional MIME type override. Null is treated as omitted."),
6944
+ bytes: z10.number().int().nonnegative().nullable().optional().describe(
6562
6945
  "Optional known file size returned by a producing tool. Null is treated as omitted; sending tools validate the file contents directly."
6563
6946
  )
6564
6947
  });
6565
6948
  var generatedArtifactFileRefSchema = sandboxFileReferenceSchema.extend({
6566
- filename: z9.string().min(1),
6567
- mimeType: z9.string().min(1).optional(),
6568
- bytes: z9.number().int().nonnegative()
6949
+ filename: z10.string().min(1),
6950
+ mimeType: z10.string().min(1).optional(),
6951
+ bytes: z10.number().int().nonnegative()
6569
6952
  }).strict();
6570
6953
  var MIME_BY_EXTENSION = {
6571
6954
  ".png": "image/png",
@@ -7816,7 +8199,7 @@ function serializeMcpPayload(payload, privacy, options = {}) {
7816
8199
  }
7817
8200
 
7818
8201
  // src/chat/tools/sandbox/bash.ts
7819
- import { z as z10 } from "zod";
8202
+ import { z as z11 } from "zod";
7820
8203
  function createBashTool() {
7821
8204
  return zodTool({
7822
8205
  annotations: {
@@ -7826,10 +8209,10 @@ function createBashTool() {
7826
8209
  readOnlyHint: false
7827
8210
  },
7828
8211
  description: "Run a bash command inside the isolated sandbox workspace. Use this for repository inspection/execution tasks that need shell access. Do not use for network-sensitive or destructive actions unless explicitly required.",
7829
- inputSchema: z10.object({
7830
- command: z10.string().min(1).describe("Bash command to run inside the sandbox."),
7831
- cwd: z10.string().min(1).describe("Optional working directory for this command only.").optional(),
7832
- timeoutMs: z10.coerce.number().int().min(1e3).describe(
8212
+ inputSchema: z11.object({
8213
+ command: z11.string().min(1).describe("Bash command to run inside the sandbox."),
8214
+ cwd: z11.string().min(1).describe("Optional working directory for this command only.").optional(),
8215
+ timeoutMs: z11.coerce.number().int().min(1e3).describe(
7833
8216
  "Optional command timeout in milliseconds. Use for commands that may hang."
7834
8217
  ).optional()
7835
8218
  }),
@@ -7843,14 +8226,14 @@ function createBashTool() {
7843
8226
  }
7844
8227
 
7845
8228
  // src/chat/tools/web/image-generate.ts
7846
- import { z as z11 } from "zod";
8229
+ import { z as z12 } from "zod";
7847
8230
  var imageGenerateOutputSchema = juniorToolOutputSchema.extend({
7848
- model: z11.string(),
7849
- prompt: z11.string(),
7850
- enrichedPrompt: z11.string(),
7851
- image_count: z11.number().int().nonnegative(),
7852
- images: z11.array(generatedArtifactFileRefSchema),
7853
- delivery: z11.string()
8231
+ model: z12.string(),
8232
+ prompt: z12.string(),
8233
+ enrichedPrompt: z12.string(),
8234
+ image_count: z12.number().int().nonnegative(),
8235
+ images: z12.array(generatedArtifactFileRefSchema),
8236
+ delivery: z12.string()
7854
8237
  }).strict();
7855
8238
  var ENRICHMENT_SYSTEM_PROMPT = `You are an image prompt enrichment agent. Your job is to rewrite image generation requests to reflect a specific visual identity and mood.
7856
8239
 
@@ -7912,8 +8295,8 @@ function createImageGenerateTool(hooks, options, deps = {}) {
7912
8295
  readOnlyHint: false
7913
8296
  },
7914
8297
  description: "Generate images from a prompt. Use when the user wants to visually show or represent something \u2014 feelings, concepts, art, humor, or any visual idea. Also use for explicit image creation requests.",
7915
- inputSchema: z11.object({
7916
- prompt: z11.string().min(1).max(4e3).describe("Image generation prompt.")
8298
+ inputSchema: z12.object({
8299
+ prompt: z12.string().min(1).max(4e3).describe("Image generation prompt.")
7917
8300
  }),
7918
8301
  outputSchema: imageGenerateOutputSchema,
7919
8302
  execute: async ({ prompt }) => {
@@ -8003,7 +8386,7 @@ function parseMcpProviderFromToolName(toolName) {
8003
8386
  }
8004
8387
 
8005
8388
  // src/chat/tools/skill/call-mcp-tool.ts
8006
- import { z as z12 } from "zod";
8389
+ import { z as z13 } from "zod";
8007
8390
  function resolveMcpArguments(input) {
8008
8391
  const extraKeys = Object.keys(input).filter(
8009
8392
  (key) => key !== "tool_name" && key !== "arguments"
@@ -8046,9 +8429,9 @@ function createCallMcpToolTool(mcpToolManager) {
8046
8429
  readOnlyHint: false
8047
8430
  },
8048
8431
  description: "Call an active MCP tool by exact tool_name. Use searchMcpTools to discover tool names and schemas; copy required provider fields into arguments. Do not call with only tool_name unless the discovered tool has no arguments. Authorization is handled by the runtime when required.",
8049
- inputSchema: z12.object({
8050
- tool_name: z12.string().min(1).describe("Exact MCP tool_name from searchMcpTools."),
8051
- arguments: z12.record(z12.string(), z12.unknown()).describe(
8432
+ inputSchema: z13.object({
8433
+ tool_name: z13.string().min(1).describe("Exact MCP tool_name from searchMcpTools."),
8434
+ arguments: z13.record(z13.string(), z13.unknown()).describe(
8052
8435
  'Arguments matching the disclosed MCP tool schema, for example { "query": "..." } when searchMcpTools shows query is required.'
8053
8436
  ).optional()
8054
8437
  }).passthrough(),
@@ -8101,7 +8484,7 @@ function createCallMcpToolTool(mcpToolManager) {
8101
8484
  }
8102
8485
 
8103
8486
  // src/chat/tools/skill/load-skill.ts
8104
- import { z as z13 } from "zod";
8487
+ import { z as z14 } from "zod";
8105
8488
  function toLoadedSkill(result, availableSkills) {
8106
8489
  if (typeof result.skill_name !== "string" || typeof result.description !== "string" || typeof result.skill_dir !== "string" || typeof result.instructions !== "string") {
8107
8490
  return null;
@@ -8151,8 +8534,8 @@ function createLoadSkillTool(availableSkills, options) {
8151
8534
  readOnlyHint: false
8152
8535
  },
8153
8536
  description: "Load a skill by name for this turn. The result includes working_directory; resolve skill paths there and run skill-owned bash commands from there or with absolute paths. When the skill instructions name an MCP provider, use searchMcpTools before callMcpTool. Use when a request clearly matches a known skill.",
8154
- inputSchema: z13.object({
8155
- skill_name: z13.string().min(1).describe("Skill name to load, without the leading slash.")
8537
+ inputSchema: z14.object({
8538
+ skill_name: z14.string().min(1).describe("Skill name to load, without the leading slash.")
8156
8539
  }),
8157
8540
  outputSchema: juniorToolOutputSchema,
8158
8541
  execute: async ({ skill_name }) => {
@@ -8167,7 +8550,7 @@ function createLoadSkillTool(availableSkills, options) {
8167
8550
  }
8168
8551
 
8169
8552
  // src/chat/tools/skill/search-mcp-tools.ts
8170
- import { z as z14 } from "zod";
8553
+ import { z as z15 } from "zod";
8171
8554
 
8172
8555
  // src/chat/tool-support/skill/mcp-tool-summary.ts
8173
8556
  function toExposedToolSummary(toolDef) {
@@ -8199,29 +8582,29 @@ function toActiveMcpCatalogSummaries(toolDefs) {
8199
8582
  // src/chat/tools/skill/search-mcp-tools.ts
8200
8583
  var DEFAULT_MAX_RESULTS = 5;
8201
8584
  var MAX_RESULTS = 20;
8202
- var providerSummarySchema = z14.object({
8203
- provider: z14.string(),
8204
- description: z14.string(),
8205
- active: z14.boolean()
8585
+ var providerSummarySchema = z15.object({
8586
+ provider: z15.string(),
8587
+ description: z15.string(),
8588
+ active: z15.boolean()
8206
8589
  }).strict();
8207
- var exposedToolSummarySchema = z14.object({
8208
- tool_name: z14.string(),
8209
- mcp_tool_name: z14.string(),
8210
- provider: z14.string(),
8211
- title: z14.string().optional(),
8212
- description: z14.string(),
8213
- input_schema: z14.record(z14.string(), z14.unknown()),
8214
- output_schema: z14.record(z14.string(), z14.unknown()).optional(),
8215
- annotations: z14.record(z14.string(), z14.unknown()).optional()
8590
+ var exposedToolSummarySchema = z15.object({
8591
+ tool_name: z15.string(),
8592
+ mcp_tool_name: z15.string(),
8593
+ provider: z15.string(),
8594
+ title: z15.string().optional(),
8595
+ description: z15.string(),
8596
+ input_schema: z15.record(z15.string(), z15.unknown()),
8597
+ output_schema: z15.record(z15.string(), z15.unknown()).optional(),
8598
+ annotations: z15.record(z15.string(), z15.unknown()).optional()
8216
8599
  }).strict();
8217
8600
  var searchMcpToolsOutputSchema = juniorToolOutputSchema.extend({
8218
- query: z14.string().nullable(),
8219
- provider: z14.string().nullable(),
8220
- total_active_tools: z14.number().int().nonnegative(),
8221
- returned_tools: z14.number().int().nonnegative(),
8222
- execution_tool: z14.literal("callMcpTool"),
8223
- available_providers: z14.array(providerSummarySchema),
8224
- tools: z14.array(exposedToolSummarySchema)
8601
+ query: z15.string().nullable(),
8602
+ provider: z15.string().nullable(),
8603
+ total_active_tools: z15.number().int().nonnegative(),
8604
+ returned_tools: z15.number().int().nonnegative(),
8605
+ execution_tool: z15.literal("callMcpTool"),
8606
+ available_providers: z15.array(providerSummarySchema),
8607
+ tools: z15.array(exposedToolSummarySchema)
8225
8608
  }).strict();
8226
8609
  function normalize(value) {
8227
8610
  return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
@@ -8347,14 +8730,14 @@ function createSearchMcpToolsTool(mcpToolManager) {
8347
8730
  readOnlyHint: true
8348
8731
  },
8349
8732
  description: "List or search MCP providers and active MCP tools. When provider is supplied and not yet active, Junior connects to it on demand and returns tool descriptors including schemas. Without provider, returns active tools plus matching configured providers without connecting. Use when choosing a provider tool or when callMcpTool arguments are unclear.",
8350
- inputSchema: z14.object({
8351
- query: z14.string().min(1).describe(
8733
+ inputSchema: z15.object({
8734
+ query: z15.string().min(1).describe(
8352
8735
  "Optional search terms describing the MCP tool or arguments needed."
8353
8736
  ).optional(),
8354
- provider: z14.string().min(1).describe(
8737
+ provider: z15.string().min(1).describe(
8355
8738
  "Optional provider name to list or search within. If configured but not yet connected, Junior activates it on demand."
8356
8739
  ).optional(),
8357
- max_results: z14.number().int().min(1).max(MAX_RESULTS).describe("Maximum matching tool descriptors to return.").optional()
8740
+ max_results: z15.number().int().min(1).max(MAX_RESULTS).describe("Maximum matching tool descriptors to return.").optional()
8358
8741
  }).strict(),
8359
8742
  outputSchema: searchMcpToolsOutputSchema,
8360
8743
  privateTraceResult: (result) => ({
@@ -8394,10 +8777,10 @@ function createSearchMcpToolsTool(mcpToolManager) {
8394
8777
  }
8395
8778
 
8396
8779
  // src/chat/tools/sandbox/view-image.ts
8397
- import { z as z15 } from "zod";
8780
+ import { z as z16 } from "zod";
8398
8781
  var MAX_VIEW_IMAGE_BYTES = 5 * 1024 * 1024;
8399
- var viewImageInputSchema = z15.object({
8400
- path: z15.string().min(1).describe("Path to an image file in the sandbox workspace.")
8782
+ var viewImageInputSchema = z16.object({
8783
+ path: z16.string().min(1).describe("Path to an image file in the sandbox workspace.")
8401
8784
  }).strict();
8402
8785
  function detectImageMimeType(data) {
8403
8786
  if (data.length >= 8 && data.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
@@ -8464,7 +8847,7 @@ function createViewImageTool(sandbox, supportsImageInput, deps = {}) {
8464
8847
  }
8465
8848
 
8466
8849
  // src/chat/tools/runtime/report-progress.ts
8467
- import { z as z16 } from "zod";
8850
+ import { z as z17 } from "zod";
8468
8851
  function createReportProgressTool() {
8469
8852
  return zodTool({
8470
8853
  annotations: {
@@ -8474,8 +8857,8 @@ function createReportProgressTool() {
8474
8857
  readOnlyHint: false
8475
8858
  },
8476
8859
  description: "Update the user-visible assistant loading message with a short progress phase. Use this only for work with multiple substantive phases or a materially long wait. Skip short lookups, routine commands, generic filler, and minor substeps. After an initial update, call it again only when the major phase meaningfully changes. Messages must be written in sentence case with a present-participle verb (e.g. 'Searching docs', 'Reviewing results', 'Running checks').",
8477
- inputSchema: z16.object({
8478
- message: z16.string().min(1).describe("Short user-facing progress message.")
8860
+ inputSchema: z17.object({
8861
+ message: z17.string().min(1).describe("Short user-facing progress message.")
8479
8862
  }),
8480
8863
  outputSchema: juniorToolOutputSchema,
8481
8864
  execute: async () => ({})
@@ -8483,9 +8866,9 @@ function createReportProgressTool() {
8483
8866
  }
8484
8867
 
8485
8868
  // src/chat/tools/runtime/spawn-agent.ts
8486
- import { z as z17 } from "zod";
8869
+ import { z as z18 } from "zod";
8487
8870
  var spawnAgentOutputSchema = juniorToolOutputSchema.extend({
8488
- invocation_id: z17.string().min(1)
8871
+ invocation_id: z18.string().min(1)
8489
8872
  });
8490
8873
  function createSpawnAgentTool(spawnAgent) {
8491
8874
  return zodTool({
@@ -8496,10 +8879,10 @@ function createSpawnAgentTool(spawnAgent) {
8496
8879
  openWorldHint: false,
8497
8880
  readOnlyHint: false
8498
8881
  },
8499
- inputSchema: z17.object({
8500
- task: z17.string().trim().min(1).describe("Task for the child agent"),
8882
+ inputSchema: z18.object({
8883
+ task: z18.string().trim().min(1).describe("Task for the child agent"),
8501
8884
  name: agentNameSchema.nullable().optional().describe("Stable child-agent name, or omit for a one-off agent"),
8502
- reasoning_level: z17.enum(TURN_REASONING_LEVELS).nullable().optional().describe(
8885
+ reasoning_level: z18.enum(TURN_REASONING_LEVELS).nullable().optional().describe(
8503
8886
  "Optional reasoning level for this delegated task only"
8504
8887
  )
8505
8888
  }).strict(),
@@ -8544,19 +8927,19 @@ function createSpawnAgentTool(spawnAgent) {
8544
8927
  }
8545
8928
 
8546
8929
  // src/chat/tools/list-resource-event-subscriptions.ts
8547
- import { z as z18 } from "zod";
8548
- var listedResourceWatchSchema = z18.object({
8549
- id: z18.string().min(1),
8550
- label: z18.string().min(1),
8551
- identifier: z18.string().min(1),
8552
- namespace: z18.string().min(1),
8553
- resourceType: z18.string().min(1),
8554
- events: z18.array(z18.string().min(1)).min(1),
8555
- match: z18.record(z18.string(), z18.unknown()).optional(),
8556
- intent: z18.string().min(1),
8557
- expiresAtMs: z18.number().finite()
8930
+ import { z as z19 } from "zod";
8931
+ var listedResourceWatchSchema = z19.object({
8932
+ id: z19.string().min(1),
8933
+ label: z19.string().min(1),
8934
+ identifier: z19.string().min(1),
8935
+ namespace: z19.string().min(1),
8936
+ resourceType: z19.string().min(1),
8937
+ events: z19.array(z19.string().min(1)).min(1),
8938
+ match: z19.record(z19.string(), z19.unknown()).optional(),
8939
+ intent: z19.string().min(1),
8940
+ expiresAtMs: z19.number().finite()
8558
8941
  }).strict();
8559
- var resultDataSchema = z18.object({ subscriptions: z18.array(listedResourceWatchSchema) }).strict();
8942
+ var resultDataSchema = z19.object({ subscriptions: z19.array(listedResourceWatchSchema) }).strict();
8560
8943
  var outputSchema = juniorToolOutputSchema.merge(resultDataSchema);
8561
8944
  function createListResourceEventSubscriptionsTool(context) {
8562
8945
  return zodTool({
@@ -8569,7 +8952,7 @@ function createListResourceEventSubscriptionsTool(context) {
8569
8952
  description: "List active resource event subscriptions for the current conversation.",
8570
8953
  exposure: "deferred",
8571
8954
  source: RESOURCE_WATCH_TOOL_SOURCE,
8572
- inputSchema: z18.object({}).strict(),
8955
+ inputSchema: z19.object({}).strict(),
8573
8956
  outputSchema,
8574
8957
  async execute() {
8575
8958
  const subscriptions = await listResourceEventSubscriptions({
@@ -8596,28 +8979,28 @@ function createListResourceEventSubscriptionsTool(context) {
8596
8979
  }
8597
8980
 
8598
8981
  // src/chat/tools/search-resource-event-types.ts
8599
- import { z as z19 } from "zod";
8982
+ import { z as z20 } from "zod";
8600
8983
  var DEFAULT_SEARCH_RESULTS = 10;
8601
8984
  var MAX_SEARCH_RESULTS = 20;
8602
- var searchedResourceTypeSchema = z19.object({
8603
- namespace: z19.string(),
8604
- type: z19.string(),
8605
- supportedEvents: z19.array(z19.string()),
8606
- suggestedEvents: z19.array(z19.string()).optional(),
8607
- matchFields: z19.record(
8608
- z19.string(),
8609
- z19.object({
8610
- kind: z19.enum(["boolean", "string", "number"]),
8611
- description: z19.string(),
8612
- enum: z19.array(z19.string()).optional()
8985
+ var searchedResourceTypeSchema = z20.object({
8986
+ namespace: z20.string(),
8987
+ type: z20.string(),
8988
+ supportedEvents: z20.array(z20.string()),
8989
+ suggestedEvents: z20.array(z20.string()).optional(),
8990
+ matchFields: z20.record(
8991
+ z20.string(),
8992
+ z20.object({
8993
+ kind: z20.enum(["boolean", "string", "number"]),
8994
+ description: z20.string(),
8995
+ enum: z20.array(z20.string()).optional()
8613
8996
  }).strict()
8614
8997
  ).optional()
8615
8998
  }).strict();
8616
8999
  var outputSchema2 = juniorToolOutputSchema.extend({
8617
- query: z19.string().nullable(),
8618
- namespace: z19.string().nullable(),
8619
- totalMatches: z19.number().int().nonnegative(),
8620
- resourceTypes: z19.array(searchedResourceTypeSchema)
9000
+ query: z20.string().nullable(),
9001
+ namespace: z20.string().nullable(),
9002
+ totalMatches: z20.number().int().nonnegative(),
9003
+ resourceTypes: z20.array(searchedResourceTypeSchema)
8621
9004
  }).strict();
8622
9005
  function normalizeSearchText(value) {
8623
9006
  return value.toLowerCase().replace(/[^a-z0-9_.-]+/g, " ").trim();
@@ -8644,12 +9027,12 @@ function createSearchResourceEventTypesTool(catalog) {
8644
9027
  readOnlyHint: true
8645
9028
  },
8646
9029
  description: "Search the resource event types currently enabled without creating anything. Includes plugin resources and core Workspace snapshot events. Use watchResourceEvents for temporary updates in the current conversation; use createEventTask for durable automation. This tool does not watch a resource, create a task, or list concrete resources.",
8647
- inputSchema: z19.object({
8648
- query: z19.string().nullable().describe(
9030
+ inputSchema: z20.object({
9031
+ query: z20.string().nullable().describe(
8649
9032
  "Optional terms matching a namespace, resource type, or event name. Empty lists all enabled resource event types."
8650
9033
  ).optional(),
8651
9034
  namespace: eventNamespaceSchema(catalog).nullable().describe("Optional enabled plugin namespace to search within.").optional(),
8652
- maxResults: z19.number().int().min(1).max(MAX_SEARCH_RESULTS).nullable().describe("Maximum matching resource types to return.").optional()
9035
+ maxResults: z20.number().int().min(1).max(MAX_SEARCH_RESULTS).nullable().describe("Maximum matching resource types to return.").optional()
8653
9036
  }).strict(),
8654
9037
  outputSchema: outputSchema2,
8655
9038
  async execute({ query, namespace, maxResults }) {
@@ -8688,10 +9071,10 @@ function createSearchResourceEventTypesTool(catalog) {
8688
9071
  }
8689
9072
 
8690
9073
  // src/chat/tools/stop-watching-resources.ts
8691
- import { z as z20 } from "zod";
8692
- var resultDataSchema2 = z20.object({
8693
- watching_status: z20.literal("stopped"),
8694
- stoppedIds: z20.array(z20.string().min(1))
9074
+ import { z as z21 } from "zod";
9075
+ var resultDataSchema2 = z21.object({
9076
+ watching_status: z21.literal("stopped"),
9077
+ stoppedIds: z21.array(z21.string().min(1))
8695
9078
  }).strict();
8696
9079
  var outputSchema3 = juniorToolOutputSchema.merge(resultDataSchema2);
8697
9080
  function createStopWatchingResourcesTool(context) {
@@ -8705,7 +9088,7 @@ function createStopWatchingResourcesTool(context) {
8705
9088
  description: "Stop one resource watch in the current conversation by id. Omit id only when the user explicitly asks to stop every watch in this conversation. Infer terse stop requests from context, inspect active watches when the target is unclear, and call this tool before confirming that watching stopped.",
8706
9089
  exposure: "deferred",
8707
9090
  source: RESOURCE_WATCH_TOOL_SOURCE,
8708
- inputSchema: z20.object({ id: z20.string().min(1).nullable().optional() }).strict(),
9091
+ inputSchema: z21.object({ id: z21.string().min(1).nullable().optional() }).strict(),
8709
9092
  outputSchema: outputSchema3,
8710
9093
  async execute({ id }) {
8711
9094
  let stoppedIds;
@@ -8739,25 +9122,25 @@ function createStopWatchingResourcesTool(context) {
8739
9122
  }
8740
9123
 
8741
9124
  // src/chat/tools/watch-resource-events.ts
8742
- import { z as z21 } from "zod";
9125
+ import { z as z22 } from "zod";
8743
9126
  function inputSchema(catalog) {
8744
- return z21.object({
8745
- identifier: z21.string().trim().min(1).describe("Plugin-defined resource identifier."),
9127
+ return z22.object({
9128
+ identifier: z22.string().trim().min(1).describe("Plugin-defined resource identifier."),
8746
9129
  namespace: eventNamespaceSchema(catalog).describe(
8747
9130
  "Enabled plugin namespace for this resource."
8748
9131
  ),
8749
9132
  resourceType: registeredResourceTypeSchema(catalog).describe(
8750
9133
  "Plugin-defined resource type."
8751
9134
  ),
8752
- label: z21.string().trim().min(1).max(500).describe("Human-readable resource label."),
8753
- events: z21.array(registeredEventTypeSchema(catalog)).min(1).describe(
9135
+ label: z22.string().trim().min(1).max(500).describe("Human-readable resource label."),
9136
+ events: z22.array(registeredEventTypeSchema(catalog)).min(1).describe(
8754
9137
  "High-signal event names to deliver to this conversation when they occur."
8755
9138
  ),
8756
9139
  match: registeredResourceEventMatchSchema(),
8757
- intent: z21.string().trim().min(1).max(4e3).describe(
9140
+ intent: z22.string().trim().min(1).max(4e3).describe(
8758
9141
  "Concise reason this conversation wants these events, used when an event arrives."
8759
9142
  ),
8760
- ttlMs: z21.coerce.number().describe(
9143
+ ttlMs: z22.coerce.number().describe(
8761
9144
  "How long to keep the subscription active. Defaults to 14 days and must not exceed 30 days."
8762
9145
  ).optional()
8763
9146
  }).strict().superRefine((subscription, context) => {
@@ -8777,20 +9160,20 @@ function inputSchema(catalog) {
8777
9160
  });
8778
9161
  });
8779
9162
  }
8780
- var stopWatchingActionSchema = z21.object({
8781
- execution_tool: z21.literal("executeTool"),
8782
- execution_example: z21.object({
8783
- tool_name: z21.literal(STOP_WATCHING_TOOL_NAME),
8784
- arguments: z21.object({ id: z21.string().min(1) }).strict()
9163
+ var stopWatchingActionSchema = z22.object({
9164
+ execution_tool: z22.literal("executeTool"),
9165
+ execution_example: z22.object({
9166
+ tool_name: z22.literal(STOP_WATCHING_TOOL_NAME),
9167
+ arguments: z22.object({ id: z22.string().min(1) }).strict()
8785
9168
  }).strict()
8786
9169
  }).strict();
8787
- var resultDataSchema3 = z21.object({
8788
- id: z21.string().min(1),
8789
- subscription_status: z21.enum(["active", "cancelled", "completed"]),
8790
- identifier: z21.string().min(1),
8791
- events: z21.array(z21.string().min(1)).min(1),
8792
- match: z21.record(z21.string(), z21.unknown()).optional(),
8793
- expiresAtMs: z21.number().finite(),
9170
+ var resultDataSchema3 = z22.object({
9171
+ id: z22.string().min(1),
9172
+ subscription_status: z22.enum(["active", "cancelled", "completed"]),
9173
+ identifier: z22.string().min(1),
9174
+ events: z22.array(z22.string().min(1)).min(1),
9175
+ match: z22.record(z22.string(), z22.unknown()).optional(),
9176
+ expiresAtMs: z22.number().finite(),
8794
9177
  stop_watching: stopWatchingActionSchema
8795
9178
  }).strict();
8796
9179
  var outputSchema4 = juniorToolOutputSchema.merge(resultDataSchema3);
@@ -8892,7 +9275,7 @@ function createResourceEventTools(context, catalog) {
8892
9275
 
8893
9276
  // src/chat/tools/create-event-task.ts
8894
9277
  import { createHash } from "crypto";
8895
- import { z as z22 } from "zod";
9278
+ import { z as z23 } from "zod";
8896
9279
  function buildEventTaskId(args) {
8897
9280
  const toolCallId = args.toolCallId?.trim();
8898
9281
  if (!toolCallId) {
@@ -8920,13 +9303,13 @@ function createEventTaskTool(context, catalog) {
8920
9303
  },
8921
9304
  executionMode: "sequential",
8922
9305
  description: "Create a durable event task that executes the supplied instruction for every matching resource event. Use for whenever-this-happens-do-X automation; ordinary watch, notify, or tell-me-when requests use watchResourceEvents instead. The task may use the creator's connected credentials. Prefer a subscribable tool result when available.",
8923
- inputSchema: z22.object({
8924
- task: z22.string().trim().min(1).max(4e3),
8925
- title: z22.string().trim().min(1).max(SHORT_TITLE_MAX_LENGTH).nullable().describe(
9306
+ inputSchema: z23.object({
9307
+ task: z23.string().trim().min(1).max(4e3),
9308
+ title: z23.string().trim().min(1).max(SHORT_TITLE_MAX_LENGTH).nullable().describe(
8926
9309
  "Optional short display title. Omit or use null to generate one from the task instruction."
8927
9310
  ).optional(),
8928
9311
  trigger,
8929
- credentialMode: z22.enum(["creator", "system"]).nullable().describe(
9312
+ credentialMode: z23.enum(["creator", "system"]).nullable().describe(
8930
9313
  "Use creator to make the task creator's connected credentials available, or system when the creator says not to use them. Omit or use null for the creator default."
8931
9314
  ).optional()
8932
9315
  }).strict(),
@@ -8957,7 +9340,9 @@ function createEventTaskTool(context, catalog) {
8957
9340
  if (!eventTaskMatchesDestination(existing, destination) || existing.createdBy.slackUserId !== actor.userId) {
8958
9341
  throw new ToolInputError("Event task operation identity is invalid.");
8959
9342
  }
8960
- return eventTaskSuccess(existing, catalog);
9343
+ if (existing.status !== "deleted") {
9344
+ return eventTaskSuccess(existing, catalog);
9345
+ }
8961
9346
  }
8962
9347
  const title = await resolveTaskTitle({
8963
9348
  completeText,
@@ -8996,7 +9381,7 @@ function createEventTaskTool(context, catalog) {
8996
9381
  }
8997
9382
 
8998
9383
  // src/chat/tools/delete-event-task.ts
8999
- import { z as z23 } from "zod";
9384
+ import { z as z24 } from "zod";
9000
9385
  function createDeleteEventTaskTool(context, catalog) {
9001
9386
  return zodTool({
9002
9387
  approvalMode: "review",
@@ -9008,7 +9393,7 @@ function createDeleteEventTaskTool(context, catalog) {
9008
9393
  },
9009
9394
  executionMode: "sequential",
9010
9395
  description: "Delete an event task.",
9011
- inputSchema: z23.object({ taskId: z23.string().min(1) }).strict(),
9396
+ inputSchema: z24.object({ taskId: z24.string().min(1) }).strict(),
9012
9397
  outputSchema: eventTaskToolResultSchema,
9013
9398
  async execute({ taskId }) {
9014
9399
  const current = await writableEventTask(context, taskId);
@@ -9022,7 +9407,7 @@ function createDeleteEventTaskTool(context, catalog) {
9022
9407
  }
9023
9408
 
9024
9409
  // src/chat/tools/list-event-tasks.ts
9025
- import { z as z24 } from "zod";
9410
+ import { z as z25 } from "zod";
9026
9411
  var MAX_LISTED_EVENT_TASKS = 50;
9027
9412
  function createListEventTasksTool(context, catalog) {
9028
9413
  return zodTool({
@@ -9033,7 +9418,7 @@ function createListEventTasksTool(context, catalog) {
9033
9418
  readOnlyHint: true
9034
9419
  },
9035
9420
  description: "List event tasks for the current destination. A false triggerAvailable value means the task remains stored but its plugin event is not currently enabled.",
9036
- inputSchema: z24.object({}).strict(),
9421
+ inputSchema: z25.object({}).strict(),
9037
9422
  outputSchema: eventTaskListToolResultSchema,
9038
9423
  async execute() {
9039
9424
  const { destination } = requireEventTaskSlackContext(context);
@@ -9049,7 +9434,7 @@ function createListEventTasksTool(context, catalog) {
9049
9434
 
9050
9435
  // src/chat/tools/update-event-task.ts
9051
9436
  import { stableResourceEventMatchKey } from "@sentry/junior-plugin-api";
9052
- import { z as z25 } from "zod";
9437
+ import { z as z26 } from "zod";
9053
9438
  function changesEventTaskTrigger(current, next) {
9054
9439
  const currentEvents = [...current.events].sort();
9055
9440
  const nextEvents = [...next.events].sort();
@@ -9066,11 +9451,11 @@ function createUpdateEventTaskTool(context, catalog) {
9066
9451
  },
9067
9452
  executionMode: "sequential",
9068
9453
  description: "Update the instruction, registered trigger, or credential use for an event task.",
9069
- inputSchema: z25.object({
9070
- taskId: z25.string().min(1),
9071
- task: z25.string().trim().min(1).max(4e3).nullable().optional(),
9454
+ inputSchema: z26.object({
9455
+ taskId: z26.string().min(1),
9456
+ task: z26.string().trim().min(1).max(4e3).nullable().optional(),
9072
9457
  trigger: registeredEventTaskTriggerSchema(catalog).nullable().optional(),
9073
- credentialMode: z25.enum(["system", "creator"]).nullable().describe(
9458
+ credentialMode: z26.enum(["system", "creator"]).nullable().describe(
9074
9459
  "Set creator to make the task's original creator credentials available, or system to disable them. Creator always means the task's createdBy actor, never the current requester. Only that original creator may enable creator mode. Omit or use null to leave unchanged."
9075
9460
  ).optional()
9076
9461
  }).strict(),
@@ -9152,10 +9537,10 @@ function createEventTaskTools(context, catalog) {
9152
9537
  }
9153
9538
 
9154
9539
  // src/chat/scheduled-tasks/tools/create.ts
9155
- import { z as z28 } from "zod";
9540
+ import { z as z29 } from "zod";
9156
9541
 
9157
9542
  // src/chat/scheduled-tasks/schedule-intent.ts
9158
- import { z as z26 } from "zod";
9543
+ import { z as z27 } from "zod";
9159
9544
 
9160
9545
  // src/chat/scheduled-tasks/cadence.ts
9161
9546
  var FORMATTERS = /* @__PURE__ */ new Map();
@@ -9446,12 +9831,12 @@ function getNextRunAtMs(task, scheduledForMs, afterMs = scheduledForMs) {
9446
9831
  }
9447
9832
 
9448
9833
  // src/chat/scheduled-tasks/schedule-intent.ts
9449
- var localDateSchema = z26.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Use a local date in YYYY-MM-DD format.");
9450
- var localTimeSchema = z26.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "Use local time in HH:MM format.");
9451
- var timezoneSchema = z26.string().min(1).max(80).describe(
9834
+ var localDateSchema = z27.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Use a local date in YYYY-MM-DD format.");
9835
+ var localTimeSchema = z27.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "Use local time in HH:MM format.");
9836
+ var timezoneSchema = z27.string().min(1).max(80).describe(
9452
9837
  "IANA timezone, for example America/Los_Angeles. Omit or use null for the scheduler default."
9453
9838
  ).nullable().optional();
9454
- var weekdaySchema = z26.enum([
9839
+ var weekdaySchema = z27.enum([
9455
9840
  "sunday",
9456
9841
  "monday",
9457
9842
  "tuesday",
@@ -9460,17 +9845,17 @@ var weekdaySchema = z26.enum([
9460
9845
  "friday",
9461
9846
  "saturday"
9462
9847
  ]);
9463
- var oneOffScheduleIntentSchema = z26.object({
9464
- kind: z26.literal("one_off").describe("A schedule that runs once."),
9848
+ var oneOffScheduleIntentSchema = z27.object({
9849
+ kind: z27.literal("one_off").describe("A schedule that runs once."),
9465
9850
  timezone: timezoneSchema,
9466
- timing: z26.discriminatedUnion("type", [
9467
- z26.object({
9468
- type: z26.literal("after").describe("Run after a relative delay from the server clock."),
9469
- value: z26.number().int().positive().max(1e5),
9470
- unit: z26.enum(["second", "minute", "hour", "day", "week"])
9851
+ timing: z27.discriminatedUnion("type", [
9852
+ z27.object({
9853
+ type: z27.literal("after").describe("Run after a relative delay from the server clock."),
9854
+ value: z27.number().int().positive().max(1e5),
9855
+ unit: z27.enum(["second", "minute", "hour", "day", "week"])
9471
9856
  }).strict(),
9472
- z26.object({
9473
- type: z26.literal("at").describe("Run at an explicit local calendar date and time."),
9857
+ z27.object({
9858
+ type: z27.literal("at").describe("Run at an explicit local calendar date and time."),
9474
9859
  date: localDateSchema.describe(
9475
9860
  "Requested local calendar date in YYYY-MM-DD format."
9476
9861
  ),
@@ -9480,16 +9865,16 @@ var oneOffScheduleIntentSchema = z26.object({
9480
9865
  }).strict()
9481
9866
  ]).describe("Relative delay or explicit local time for the one-off run.")
9482
9867
  }).strict();
9483
- var recurringScheduleIntentSchema = z26.object({
9484
- kind: z26.literal("recurring").describe("A repeating calendar schedule."),
9485
- frequency: z26.enum(["daily", "weekly", "monthly", "yearly"]).describe("Recurring tasks can run at most once per day."),
9486
- interval: z26.number().int().positive().max(365).describe("Repeat every N frequency units. Defaults to 1.").nullable().optional(),
9868
+ var recurringScheduleIntentSchema = z27.object({
9869
+ kind: z27.literal("recurring").describe("A repeating calendar schedule."),
9870
+ frequency: z27.enum(["daily", "weekly", "monthly", "yearly"]).describe("Recurring tasks can run at most once per day."),
9871
+ interval: z27.number().int().positive().max(365).describe("Repeat every N frequency units. Defaults to 1.").nullable().optional(),
9487
9872
  time: localTimeSchema.describe(
9488
9873
  "Local wall-clock time for each occurrence in HH:MM format."
9489
9874
  ),
9490
- weekdays: z26.array(weekdaySchema).min(1).max(7).describe("Required for weekly schedules.").nullable().optional(),
9491
- day_of_month: z26.number().int().min(1).max(31).describe("Required for monthly and yearly schedules.").nullable().optional(),
9492
- month: z26.number().int().min(1).max(12).describe("Required for yearly schedules, where January is 1.").nullable().optional(),
9875
+ weekdays: z27.array(weekdaySchema).min(1).max(7).describe("Required for weekly schedules.").nullable().optional(),
9876
+ day_of_month: z27.number().int().min(1).max(31).describe("Required for monthly and yearly schedules.").nullable().optional(),
9877
+ month: z27.number().int().min(1).max(12).describe("Required for yearly schedules, where January is 1.").nullable().optional(),
9493
9878
  start_date: localDateSchema.describe(
9494
9879
  "Optional local calendar date that anchors the recurrence. Omit to start with the next matching occurrence."
9495
9880
  ).nullable().optional(),
@@ -9538,7 +9923,7 @@ var recurringScheduleIntentSchema = z26.object({
9538
9923
  });
9539
9924
  }
9540
9925
  });
9541
- var scheduleIntentSchema = z26.union([
9926
+ var scheduleIntentSchema = z27.union([
9542
9927
  oneOffScheduleIntentSchema,
9543
9928
  recurringScheduleIntentSchema
9544
9929
  ]);
@@ -9733,7 +10118,7 @@ import { createHash as createHash2 } from "crypto";
9733
10118
  import {
9734
10119
  sourceSchema
9735
10120
  } from "@sentry/junior-plugin-api";
9736
- import { z as z27 } from "zod";
10121
+ import { z as z28 } from "zod";
9737
10122
 
9738
10123
  // src/chat/scheduled-tasks/identity.ts
9739
10124
  var SLACK_USER_ID_PATTERN = /^[UW][A-Z0-9]{5,}$/;
@@ -9770,36 +10155,36 @@ function sanitizeScheduledTaskPrincipal(principal) {
9770
10155
  var TASK_ID_PREFIX = "sched";
9771
10156
  var MAX_LISTED_TASKS = 50;
9772
10157
  var DEFAULT_SCHEDULE_TIMEZONE = "America/Los_Angeles";
9773
- var compactTaskResultSchema = z27.object({
9774
- id: z27.string(),
9775
- status: z27.enum(["active", "blocked", "completed", "deleted"]),
9776
- task: z27.string(),
9777
- schedule: z27.string(),
9778
- timezone: z27.string(),
9779
- recurrence: z27.unknown().nullable(),
9780
- next_run_at: z27.string().nullable(),
9781
- destination: z27.object({
9782
- platform: z27.literal("slack"),
9783
- team_id: z27.string().min(1),
9784
- channel_id: z27.string().min(1)
10158
+ var compactTaskResultSchema = z28.object({
10159
+ id: z28.string(),
10160
+ status: z28.enum(["active", "blocked", "completed", "deleted"]),
10161
+ task: z28.string(),
10162
+ schedule: z28.string(),
10163
+ timezone: z28.string(),
10164
+ recurrence: z28.unknown().nullable(),
10165
+ next_run_at: z28.string().nullable(),
10166
+ destination: z28.object({
10167
+ platform: z28.literal("slack"),
10168
+ team_id: z28.string().min(1),
10169
+ channel_id: z28.string().min(1)
9785
10170
  }).strict(),
9786
- conversation_access: z27.object({
9787
- audience: z27.enum(["direct", "group", "channel"]),
9788
- visibility: z27.enum(["private", "public"])
10171
+ conversation_access: z28.object({
10172
+ audience: z28.enum(["direct", "group", "channel"]),
10173
+ visibility: z28.enum(["private", "public"])
9789
10174
  }).strict(),
9790
- credential_mode: z27.enum(["system", "creator"]),
9791
- dashboard_url: z27.string().url().nullable(),
9792
- last_run_at: z27.string().nullable(),
9793
- run_now_at: z27.string().nullable()
10175
+ credential_mode: z28.enum(["system", "creator"]),
10176
+ dashboard_url: z28.string().url().nullable(),
10177
+ last_run_at: z28.string().nullable(),
10178
+ run_now_at: z28.string().nullable()
9794
10179
  }).strict();
9795
10180
  var scheduleTaskToolResultSchema = juniorToolOutputSchema.extend({
9796
- target: z27.string(),
10181
+ target: z28.string(),
9797
10182
  task: compactTaskResultSchema
9798
10183
  }).strict();
9799
10184
  var scheduleListToolResultSchema = juniorToolOutputSchema.extend({
9800
- target: z27.string(),
9801
- tasks: z27.array(compactTaskResultSchema),
9802
- truncated: z27.boolean()
10185
+ target: z28.string(),
10186
+ tasks: z28.array(compactTaskResultSchema),
10187
+ truncated: z28.boolean()
9803
10188
  }).strict();
9804
10189
  function throwToolInputError(error) {
9805
10190
  throw new ToolInputError(error);
@@ -9962,15 +10347,15 @@ function createSlackScheduleCreateTaskTool(context) {
9962
10347
  },
9963
10348
  description: "Create a one-time or recurring Junior task in the active Slack conversation when the user asks Junior to do work later or repeatedly.",
9964
10349
  executionMode: "sequential",
9965
- inputSchema: z28.object({
9966
- task: z28.string().min(1).max(4e3),
9967
- title: z28.string().trim().min(1).max(SHORT_TITLE_MAX_LENGTH).nullable().describe(
10350
+ inputSchema: z29.object({
10351
+ task: z29.string().min(1).max(4e3),
10352
+ title: z29.string().trim().min(1).max(SHORT_TITLE_MAX_LENGTH).nullable().describe(
9968
10353
  "Optional short display title. Omit or use null to generate one from the task instruction."
9969
10354
  ).optional(),
9970
10355
  schedule: scheduleIntentSchema.describe(
9971
10356
  "When the task runs. The scheduler computes the exact next run from this intent and the server clock."
9972
10357
  ),
9973
- credential_mode: z28.enum(["creator", "system"]).nullable().describe(
10358
+ credential_mode: z29.enum(["creator", "system"]).nullable().describe(
9974
10359
  "Use creator to make the task creator's connected credentials available, or system when the creator says not to use them. Omit or use null for the creator default."
9975
10360
  ).optional()
9976
10361
  }).strict(),
@@ -10069,7 +10454,7 @@ function createSlackScheduleCreateTaskTool(context) {
10069
10454
  }
10070
10455
 
10071
10456
  // src/chat/scheduled-tasks/tools/delete.ts
10072
- import { z as z29 } from "zod";
10457
+ import { z as z30 } from "zod";
10073
10458
  function createSlackScheduleDeleteTaskTool(context) {
10074
10459
  return zodTool({
10075
10460
  approvalMode: "review",
@@ -10081,8 +10466,8 @@ function createSlackScheduleDeleteTaskTool(context) {
10081
10466
  },
10082
10467
  description: "Delete one scheduled Junior task from the active Slack conversation. Use only task IDs returned for this conversation. Do not delete schedules from threads, other channels, or another user's DM.",
10083
10468
  executionMode: "sequential",
10084
- inputSchema: z29.object({
10085
- task_id: z29.string().min(1).describe(
10469
+ inputSchema: z30.object({
10470
+ task_id: z30.string().min(1).describe(
10086
10471
  "ID of the task to delete. Must be from this active Slack conversation."
10087
10472
  )
10088
10473
  }),
@@ -10106,12 +10491,12 @@ function createSlackScheduleDeleteTaskTool(context) {
10106
10491
  }
10107
10492
 
10108
10493
  // src/chat/slack/id-param.ts
10109
- import { z as z30 } from "zod";
10494
+ import { z as z31 } from "zod";
10110
10495
  function slackChannelIdParam(description) {
10111
- return z30.string().min(1).describe(description);
10496
+ return z31.string().min(1).describe(description);
10112
10497
  }
10113
10498
  function slackUserIdParam(description) {
10114
- return z30.string().min(1).describe(description);
10499
+ return z31.string().min(1).describe(description);
10115
10500
  }
10116
10501
  function parseRequiredSlackChannelIdParam(field, value) {
10117
10502
  const channelId = parseSlackChannelId(value);
@@ -10135,7 +10520,7 @@ function parseRequiredSlackUserIdParam(field, value) {
10135
10520
  }
10136
10521
 
10137
10522
  // src/chat/scheduled-tasks/tools/list.ts
10138
- import { z as z31 } from "zod";
10523
+ import { z as z32 } from "zod";
10139
10524
  function taskMatchesQuery(task, query) {
10140
10525
  const normalized = query.toLowerCase();
10141
10526
  return [
@@ -10155,11 +10540,11 @@ function createSlackScheduleListTasksTool(context) {
10155
10540
  openWorldHint: false,
10156
10541
  readOnlyHint: true
10157
10542
  },
10158
- inputSchema: z31.object({
10543
+ inputSchema: z32.object({
10159
10544
  channel_id: slackChannelIdParam(
10160
10545
  "Current destination channel ID to filter by. Use the ID from a channel mention; do not guess."
10161
10546
  ).nullable().optional(),
10162
- query: z31.string().trim().min(1).max(200).nullable().describe("Text to match in the requester's scheduled tasks.").optional()
10547
+ query: z32.string().trim().min(1).max(200).nullable().describe("Text to match in the requester's scheduled tasks.").optional()
10163
10548
  }).strict(),
10164
10549
  outputSchema: scheduleListToolResultSchema,
10165
10550
  execute: async (input) => {
@@ -10207,7 +10592,7 @@ function createSlackScheduleListTasksTool(context) {
10207
10592
  }
10208
10593
 
10209
10594
  // src/chat/scheduled-tasks/tools/run-now.ts
10210
- import { z as z32 } from "zod";
10595
+ import { z as z33 } from "zod";
10211
10596
  function createSlackScheduleRunTaskNowTool(context) {
10212
10597
  return zodTool({
10213
10598
  approvalMode: "review",
@@ -10219,8 +10604,8 @@ function createSlackScheduleRunTaskNowTool(context) {
10219
10604
  },
10220
10605
  description: "Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled task now. Use only task IDs returned for this conversation.",
10221
10606
  executionMode: "sequential",
10222
- inputSchema: z32.object({
10223
- task_id: z32.string().min(1).describe(
10607
+ inputSchema: z33.object({
10608
+ task_id: z33.string().min(1).describe(
10224
10609
  "ID of the active task to run now. Must be from this active Slack conversation."
10225
10610
  )
10226
10611
  }),
@@ -10248,7 +10633,7 @@ function createSlackScheduleRunTaskNowTool(context) {
10248
10633
  }
10249
10634
 
10250
10635
  // src/chat/scheduled-tasks/tools/update.ts
10251
- import { z as z33 } from "zod";
10636
+ import { z as z34 } from "zod";
10252
10637
  import { and, eq, inArray } from "drizzle-orm";
10253
10638
  function createSlackScheduleUpdateTaskTool(context) {
10254
10639
  return zodTool({
@@ -10261,17 +10646,17 @@ function createSlackScheduleUpdateTaskTool(context) {
10261
10646
  },
10262
10647
  description: `Update a scheduled task. To move the requester's task into this Slack conversation, set destination to "here".`,
10263
10648
  executionMode: "sequential",
10264
- inputSchema: z33.object({
10265
- task_id: z33.string().min(1).describe("Scheduled task ID returned by slackScheduleListTasks."),
10266
- task: z33.string().min(1).max(4e3).optional(),
10649
+ inputSchema: z34.object({
10650
+ task_id: z34.string().min(1).describe("Scheduled task ID returned by slackScheduleListTasks."),
10651
+ task: z34.string().min(1).max(4e3).optional(),
10267
10652
  schedule: scheduleIntentSchema.describe("Complete replacement schedule. Omit to keep it unchanged.").nullable().optional(),
10268
- status: z33.enum(["active", "blocked"]).describe(
10653
+ status: z34.enum(["active", "blocked"]).describe(
10269
10654
  "Set active to resume a blocked task, or blocked to stop dispatch."
10270
10655
  ).optional(),
10271
- destination: z33.literal("here").nullable().describe(
10656
+ destination: z34.literal("here").nullable().describe(
10272
10657
  `Set to "here" to move the creator's task into this Slack conversation. Omit to keep its destination.`
10273
10658
  ).optional(),
10274
- credential_mode: z33.enum(["system", "creator"]).nullable().describe(
10659
+ credential_mode: z34.enum(["system", "creator"]).nullable().describe(
10275
10660
  "Use creator credentials or system credentials. Only the task creator may enable creator mode. Omit to keep unchanged."
10276
10661
  ).optional()
10277
10662
  }).strict(),
@@ -10630,9 +11015,9 @@ async function joinPublicChannelForRead(args) {
10630
11015
  }
10631
11016
 
10632
11017
  // src/chat/slack/tool-support/channel-target.ts
10633
- import { z as z34 } from "zod";
11018
+ import { z as z35 } from "zod";
10634
11019
  var SLACK_CHANNEL_REF_MAX_LENGTH = 160;
10635
- var slackChannelRefParam = z34.string().trim().min(1).max(SLACK_CHANNEL_REF_MAX_LENGTH).describe(
11020
+ var slackChannelRefParam = z35.string().trim().min(1).max(SLACK_CHANNEL_REF_MAX_LENGTH).describe(
10636
11021
  "Slack channel id (`C123`), mention (`<#C123>` / `<#C123|name>`), Junior slack reference (`slack:C123`), or a channel name Junior already knows in this workspace."
10637
11022
  );
10638
11023
  async function resolveSlackChannelRef(input) {
@@ -10680,7 +11065,7 @@ async function resolveOptionalSlackChannelRef(input) {
10680
11065
  }
10681
11066
 
10682
11067
  // src/chat/slack/tools/channel-join.ts
10683
- import { z as z35 } from "zod";
11068
+ import { z as z36 } from "zod";
10684
11069
  function createSlackChannelJoinTool(context) {
10685
11070
  return zodTool({
10686
11071
  description: "Join a public Slack channel.",
@@ -10690,7 +11075,7 @@ function createSlackChannelJoinTool(context) {
10690
11075
  openWorldHint: true,
10691
11076
  readOnlyHint: false
10692
11077
  },
10693
- inputSchema: z35.object({
11078
+ inputSchema: z36.object({
10694
11079
  channel_id: slackChannelRefParam
10695
11080
  }),
10696
11081
  outputSchema: juniorToolOutputSchema,
@@ -10747,11 +11132,11 @@ function createSlackChannelJoinTool(context) {
10747
11132
  }
10748
11133
 
10749
11134
  // src/chat/slack/timestamp-param.ts
10750
- import { z as z36 } from "zod";
11135
+ import { z as z37 } from "zod";
10751
11136
  function slackTimestampParam(description) {
10752
- return z36.preprocess(
11137
+ return z37.preprocess(
10753
11138
  (value) => typeof value === "number" && Number.isFinite(value) ? String(value) : value,
10754
- z36.string().min(1)
11139
+ z37.string().min(1)
10755
11140
  ).describe(description);
10756
11141
  }
10757
11142
  function parseSlackTimestampParam(field, value) {
@@ -10779,10 +11164,10 @@ function parseRequiredSlackTimestampParam(field, value) {
10779
11164
  }
10780
11165
 
10781
11166
  // src/chat/slack/tools/channel-list-messages.ts
10782
- import { z as z37 } from "zod";
10783
- var booleanInput2 = (description) => z37.preprocess(
11167
+ import { z as z38 } from "zod";
11168
+ var booleanInput2 = (description) => z38.preprocess(
10784
11169
  (value) => value === "true" ? true : value === "false" ? false : value,
10785
- z37.boolean()
11170
+ z38.boolean()
10786
11171
  ).describe(description);
10787
11172
  function normalizeRangeTimestamp(field, value, targetChannelId) {
10788
11173
  if (value === void 0) {
@@ -10814,10 +11199,10 @@ function createSlackChannelListMessagesTool(context) {
10814
11199
  openWorldHint: true,
10815
11200
  readOnlyHint: true
10816
11201
  },
10817
- inputSchema: z37.object({
11202
+ inputSchema: z38.object({
10818
11203
  channel_id: slackChannelRefParam.optional(),
10819
- limit: z37.coerce.number().int().min(1).max(1e3).describe("Maximum number of messages to return across pages.").optional(),
10820
- cursor: z37.string().min(1).describe("Optional cursor to continue from a prior call.").optional(),
11204
+ limit: z38.coerce.number().int().min(1).max(1e3).describe("Maximum number of messages to return across pages.").optional(),
11205
+ cursor: z38.string().min(1).describe("Optional cursor to continue from a prior call.").optional(),
10821
11206
  oldest: slackTimestampParam(
10822
11207
  "Oldest message timestamp (Slack ts) for range filtering."
10823
11208
  ).optional(),
@@ -10827,7 +11212,7 @@ function createSlackChannelListMessagesTool(context) {
10827
11212
  inclusive: booleanInput2(
10828
11213
  "Whether oldest/latest bounds should be inclusive."
10829
11214
  ).optional(),
10830
- max_pages: z37.coerce.number().int().min(1).max(10).describe("Maximum number of API pages to traverse in a single call.").optional()
11215
+ max_pages: z38.coerce.number().int().min(1).max(10).describe("Maximum number of API pages to traverse in a single call.").optional()
10831
11216
  }),
10832
11217
  outputSchema: juniorToolOutputSchema,
10833
11218
  execute: async ({
@@ -10950,7 +11335,7 @@ function createSlackChannelListMessagesTool(context) {
10950
11335
  }
10951
11336
 
10952
11337
  // src/chat/slack/tools/conversation-message-search.ts
10953
- import { z as z38 } from "zod";
11338
+ import { z as z39 } from "zod";
10954
11339
 
10955
11340
  // src/chat/conversations/tool-source.ts
10956
11341
  var CONVERSATIONS_TOOL_SOURCE = {
@@ -10962,23 +11347,23 @@ var CONVERSATIONS_TOOL_SOURCE = {
10962
11347
  var DEFAULT_LIMIT = 20;
10963
11348
  var MAX_LIMIT = 50;
10964
11349
  var conversationMessageSearchOutputSchema = juniorToolOutputSchema.extend({
10965
- after: z38.string().datetime().optional(),
10966
- annotation: z38.string().min(1).optional(),
10967
- before: z38.string().datetime().optional(),
10968
- channel_id: z38.string().min(1).optional(),
10969
- count: z38.number().int().nonnegative(),
10970
- query: z38.string().optional(),
10971
- matches: z38.array(
10972
- z38.object({
10973
- channel_id: z38.string().min(1),
10974
- channel_name: z38.string().min(1).optional(),
10975
- conversation_id: z38.string().min(1),
10976
- excerpt: z38.string(),
10977
- message_id: z38.string().min(1),
10978
- message_role: z38.enum(["assistant", "user"]),
10979
- message_timestamp: z38.string().datetime(),
10980
- permalink: z38.string().url().optional(),
10981
- thread_ts: z38.string().min(1)
11350
+ after: z39.string().datetime().optional(),
11351
+ annotation: z39.string().min(1).optional(),
11352
+ before: z39.string().datetime().optional(),
11353
+ channel_id: z39.string().min(1).optional(),
11354
+ count: z39.number().int().nonnegative(),
11355
+ query: z39.string().optional(),
11356
+ matches: z39.array(
11357
+ z39.object({
11358
+ channel_id: z39.string().min(1),
11359
+ channel_name: z39.string().min(1).optional(),
11360
+ conversation_id: z39.string().min(1),
11361
+ excerpt: z39.string(),
11362
+ message_id: z39.string().min(1),
11363
+ message_role: z39.enum(["assistant", "user"]),
11364
+ message_timestamp: z39.string().datetime(),
11365
+ permalink: z39.string().url().optional(),
11366
+ thread_ts: z39.string().min(1)
10982
11367
  }).strict()
10983
11368
  )
10984
11369
  });
@@ -11033,15 +11418,15 @@ function createSlackConversationMessageSearchTool(scope, currentConversationId)
11033
11418
  openWorldHint: false,
11034
11419
  readOnlyHint: true
11035
11420
  },
11036
- inputSchema: z38.object({
11037
- after: z38.string().datetime().nullable().describe("Include conversations active at or after this timestamp.").optional(),
11038
- annotation: z38.string().trim().min(1).max(256).nullable().describe(
11421
+ inputSchema: z39.object({
11422
+ after: z39.string().datetime().nullable().describe("Include conversations active at or after this timestamp.").optional(),
11423
+ annotation: z39.string().trim().min(1).max(256).nullable().describe(
11039
11424
  "Linked resource key. Matches that key, or nested children that continue with #."
11040
11425
  ).optional(),
11041
- before: z38.string().datetime().nullable().describe("Include conversations active before this timestamp.").optional(),
11426
+ before: z39.string().datetime().nullable().describe("Include conversations active before this timestamp.").optional(),
11042
11427
  channel_id: slackChannelRefParam.nullable().optional(),
11043
- query: z38.string().trim().min(1).max(200).nullable().describe("Words or phrase to match in message text.").optional(),
11044
- limit: z38.number().int().min(1).max(MAX_LIMIT).describe(
11428
+ query: z39.string().trim().min(1).max(200).nullable().describe("Words or phrase to match in message text.").optional(),
11429
+ limit: z39.number().int().min(1).max(MAX_LIMIT).describe(
11045
11430
  `Maximum conversations. Default ${DEFAULT_LIMIT}; max ${MAX_LIMIT}.`
11046
11431
  ).nullable().optional()
11047
11432
  }).strict(),
@@ -11100,13 +11485,13 @@ function createSlackConversationMessageSearchTool(scope, currentConversationId)
11100
11485
  }
11101
11486
 
11102
11487
  // src/chat/slack/tools/public-search.ts
11103
- import { z as z39 } from "zod";
11488
+ import { z as z40 } from "zod";
11104
11489
  var DEFAULT_LIMIT2 = 10;
11105
11490
  var DEFAULT_CONTENT_TYPES = ["messages"];
11106
11491
  var CONTENT_TYPES = ["messages", "files", "channels", "users"];
11107
- var unixTimestampParam = z39.coerce.number().int().nonnegative();
11492
+ var unixTimestampParam = z40.coerce.number().int().nonnegative();
11108
11493
  function optionalUnixTimestampParam(description) {
11109
- return z39.preprocess(
11494
+ return z40.preprocess(
11110
11495
  (value) => typeof value === "string" && value.trim() === "" ? void 0 : value,
11111
11496
  unixTimestampParam.optional()
11112
11497
  ).describe(description);
@@ -11120,64 +11505,64 @@ function normalizeOptionalUnixTimestamp(value) {
11120
11505
  }
11121
11506
  return unixTimestampParam.parse(value);
11122
11507
  }
11123
- var searchMessageSchema = z39.object({
11124
- author_name: z39.string().min(1).optional().describe("Author display name."),
11125
- author_user_id: z39.string().min(1).optional().describe("Author user ID."),
11126
- channel_id: z39.string().min(1).describe("Channel ID."),
11127
- channel_name: z39.string().min(1).optional().describe("Channel name."),
11128
- message_ts: z39.string().min(1).describe("Message timestamp."),
11129
- content: z39.string().describe("Message text."),
11130
- is_author_bot: z39.boolean().optional().describe("Whether the author is a bot."),
11131
- permalink: z39.string().url().describe("Message permalink.")
11508
+ var searchMessageSchema = z40.object({
11509
+ author_name: z40.string().min(1).optional().describe("Author display name."),
11510
+ author_user_id: z40.string().min(1).optional().describe("Author user ID."),
11511
+ channel_id: z40.string().min(1).describe("Channel ID."),
11512
+ channel_name: z40.string().min(1).optional().describe("Channel name."),
11513
+ message_ts: z40.string().min(1).describe("Message timestamp."),
11514
+ content: z40.string().describe("Message text."),
11515
+ is_author_bot: z40.boolean().optional().describe("Whether the author is a bot."),
11516
+ permalink: z40.string().url().describe("Message permalink.")
11132
11517
  });
11133
- var searchFileSchema = z39.object({
11134
- file_id: z39.string().min(1).describe("File ID."),
11135
- title: z39.string().min(1).optional().describe("File title."),
11136
- name: z39.string().min(1).optional().describe("File name."),
11137
- filetype: z39.string().min(1).optional().describe("File type."),
11138
- user_id: z39.string().min(1).optional().describe("Uploader user ID."),
11139
- user_name: z39.string().min(1).optional().describe("Uploader user name."),
11140
- channel_id: z39.string().min(1).optional().describe("Channel ID."),
11141
- channel_name: z39.string().min(1).optional().describe("Channel name."),
11142
- permalink: z39.string().url().optional().describe("File permalink."),
11143
- content: z39.string().min(1).optional().describe("File preview or content snippet.")
11518
+ var searchFileSchema = z40.object({
11519
+ file_id: z40.string().min(1).describe("File ID."),
11520
+ title: z40.string().min(1).optional().describe("File title."),
11521
+ name: z40.string().min(1).optional().describe("File name."),
11522
+ filetype: z40.string().min(1).optional().describe("File type."),
11523
+ user_id: z40.string().min(1).optional().describe("Uploader user ID."),
11524
+ user_name: z40.string().min(1).optional().describe("Uploader user name."),
11525
+ channel_id: z40.string().min(1).optional().describe("Channel ID."),
11526
+ channel_name: z40.string().min(1).optional().describe("Channel name."),
11527
+ permalink: z40.string().url().optional().describe("File permalink."),
11528
+ content: z40.string().min(1).optional().describe("File preview or content snippet.")
11144
11529
  });
11145
- var searchChannelSchema = z39.object({
11146
- channel_id: z39.string().min(1).describe("Channel ID."),
11147
- channel_name: z39.string().min(1).optional().describe("Channel name."),
11148
- is_private: z39.boolean().optional().describe("Whether the channel is private."),
11149
- is_member: z39.boolean().optional().describe("Whether the bot is a member."),
11150
- topic: z39.string().min(1).optional().describe("Channel topic."),
11151
- purpose: z39.string().min(1).optional().describe("Channel purpose."),
11152
- permalink: z39.string().url().optional().describe("Channel permalink.")
11530
+ var searchChannelSchema = z40.object({
11531
+ channel_id: z40.string().min(1).describe("Channel ID."),
11532
+ channel_name: z40.string().min(1).optional().describe("Channel name."),
11533
+ is_private: z40.boolean().optional().describe("Whether the channel is private."),
11534
+ is_member: z40.boolean().optional().describe("Whether the bot is a member."),
11535
+ topic: z40.string().min(1).optional().describe("Channel topic."),
11536
+ purpose: z40.string().min(1).optional().describe("Channel purpose."),
11537
+ permalink: z40.string().url().optional().describe("Channel permalink.")
11153
11538
  });
11154
- var searchUserSchema = z39.object({
11155
- user_id: z39.string().min(1).describe("User ID."),
11156
- user_name: z39.string().min(1).optional().describe("Username."),
11157
- real_name: z39.string().min(1).optional().describe("Real name."),
11158
- display_name: z39.string().min(1).optional().describe("Display name."),
11159
- title: z39.string().min(1).optional().describe("Profile title."),
11160
- permalink: z39.string().url().optional().describe("Profile permalink.")
11539
+ var searchUserSchema = z40.object({
11540
+ user_id: z40.string().min(1).describe("User ID."),
11541
+ user_name: z40.string().min(1).optional().describe("Username."),
11542
+ real_name: z40.string().min(1).optional().describe("Real name."),
11543
+ display_name: z40.string().min(1).optional().describe("Display name."),
11544
+ title: z40.string().min(1).optional().describe("Profile title."),
11545
+ permalink: z40.string().url().optional().describe("Profile permalink.")
11161
11546
  });
11162
11547
  var publicSearchOutputSchema = juniorToolOutputSchema.extend({
11163
- query: z39.string().describe("Search query."),
11164
- content_types: z39.array(z39.enum(CONTENT_TYPES)).describe("Content types included in the search."),
11165
- count: z39.number().int().nonnegative().describe("Total matched results."),
11166
- messages: z39.array(searchMessageSchema).describe("Matched messages."),
11167
- files: z39.array(searchFileSchema).describe("Matched files."),
11168
- channels: z39.array(searchChannelSchema).describe("Matched channels."),
11169
- users: z39.array(searchUserSchema).describe("Matched users."),
11170
- next_cursor: z39.string().min(1).optional().describe("Cursor for the next result page.")
11548
+ query: z40.string().describe("Search query."),
11549
+ content_types: z40.array(z40.enum(CONTENT_TYPES)).describe("Content types included in the search."),
11550
+ count: z40.number().int().nonnegative().describe("Total matched results."),
11551
+ messages: z40.array(searchMessageSchema).describe("Matched messages."),
11552
+ files: z40.array(searchFileSchema).describe("Matched files."),
11553
+ channels: z40.array(searchChannelSchema).describe("Matched channels."),
11554
+ users: z40.array(searchUserSchema).describe("Matched users."),
11555
+ next_cursor: z40.string().min(1).optional().describe("Cursor for the next result page.")
11171
11556
  });
11172
- var nonEmptyString = z39.string().trim().min(1);
11173
- var optionalWireString = z39.preprocess((value) => {
11557
+ var nonEmptyString = z40.string().trim().min(1);
11558
+ var optionalWireString = z40.preprocess((value) => {
11174
11559
  if (typeof value !== "string") {
11175
11560
  return void 0;
11176
11561
  }
11177
11562
  const trimmed = value.trim();
11178
11563
  return trimmed === "" ? void 0 : trimmed;
11179
11564
  }, nonEmptyString.optional());
11180
- var optionalWireUrl = z39.preprocess((value) => {
11565
+ var optionalWireUrl = z40.preprocess((value) => {
11181
11566
  if (typeof value !== "string") {
11182
11567
  return void 0;
11183
11568
  }
@@ -11191,20 +11576,20 @@ var optionalWireUrl = z39.preprocess((value) => {
11191
11576
  } catch {
11192
11577
  return void 0;
11193
11578
  }
11194
- }, z39.string().url().optional());
11195
- var optionalWireBoolean = z39.preprocess(
11579
+ }, z40.string().url().optional());
11580
+ var optionalWireBoolean = z40.preprocess(
11196
11581
  (value) => typeof value === "boolean" ? value : void 0,
11197
- z39.boolean().optional()
11582
+ z40.boolean().optional()
11198
11583
  );
11199
- var slackSearchMessageWireSchema = z39.object({
11584
+ var slackSearchMessageWireSchema = z40.object({
11200
11585
  author_name: optionalWireString,
11201
11586
  author_user_id: optionalWireString,
11202
11587
  channel_id: nonEmptyString,
11203
11588
  channel_name: optionalWireString,
11204
11589
  message_ts: nonEmptyString,
11205
- content: z39.string(),
11590
+ content: z40.string(),
11206
11591
  is_author_bot: optionalWireBoolean,
11207
- permalink: z39.string().url()
11592
+ permalink: z40.string().url()
11208
11593
  }).transform(
11209
11594
  (value) => ({
11210
11595
  channel_id: value.channel_id,
@@ -11217,7 +11602,7 @@ var slackSearchMessageWireSchema = z39.object({
11217
11602
  ...value.is_author_bot !== void 0 ? { is_author_bot: value.is_author_bot } : void 0
11218
11603
  })
11219
11604
  );
11220
- var slackSearchFileWireSchema = z39.object({
11605
+ var slackSearchFileWireSchema = z40.object({
11221
11606
  id: optionalWireString,
11222
11607
  file_id: optionalWireString,
11223
11608
  title: optionalWireString,
@@ -11251,7 +11636,7 @@ var slackSearchFileWireSchema = z39.object({
11251
11636
  ...value.content ?? value.preview ? { content: value.content ?? value.preview } : void 0
11252
11637
  };
11253
11638
  });
11254
- var slackSearchChannelWireSchema = z39.object({
11639
+ var slackSearchChannelWireSchema = z40.object({
11255
11640
  id: optionalWireString,
11256
11641
  channel_id: optionalWireString,
11257
11642
  name: optionalWireString,
@@ -11276,7 +11661,7 @@ var slackSearchChannelWireSchema = z39.object({
11276
11661
  ...value.permalink ? { permalink: value.permalink } : void 0
11277
11662
  };
11278
11663
  });
11279
- var slackSearchUserWireSchema = z39.object({
11664
+ var slackSearchUserWireSchema = z40.object({
11280
11665
  id: optionalWireString,
11281
11666
  user_id: optionalWireString,
11282
11667
  name: optionalWireString,
@@ -11300,12 +11685,12 @@ var slackSearchUserWireSchema = z39.object({
11300
11685
  ...value.permalink ? { permalink: value.permalink } : void 0
11301
11686
  };
11302
11687
  });
11303
- var slackSearchResponseSchema = z39.object({
11304
- results: z39.object({
11305
- messages: z39.array(z39.unknown()).default([]),
11306
- files: z39.array(z39.unknown()).default([]),
11307
- channels: z39.array(z39.unknown()).default([]),
11308
- users: z39.array(z39.unknown()).default([]),
11688
+ var slackSearchResponseSchema = z40.object({
11689
+ results: z40.object({
11690
+ messages: z40.array(z40.unknown()).default([]),
11691
+ files: z40.array(z40.unknown()).default([]),
11692
+ channels: z40.array(z40.unknown()).default([]),
11693
+ users: z40.array(z40.unknown()).default([]),
11309
11694
  // Slack often returns "" on the final page; omit rather than fail the parse.
11310
11695
  next_cursor: optionalWireString
11311
11696
  }).default({
@@ -11354,15 +11739,15 @@ function createSlackPublicSearchTool(actionToken) {
11354
11739
  openWorldHint: true,
11355
11740
  readOnlyHint: true
11356
11741
  },
11357
- inputSchema: z39.object({
11358
- query: z39.string().trim().min(1).max(500).describe("Slack search query."),
11359
- content_types: z39.array(z39.enum(CONTENT_TYPES)).min(1).max(4).describe("Content types to include. Defaults to messages.").optional(),
11742
+ inputSchema: z40.object({
11743
+ query: z40.string().trim().min(1).max(500).describe("Slack search query."),
11744
+ content_types: z40.array(z40.enum(CONTENT_TYPES)).min(1).max(4).describe("Content types to include. Defaults to messages.").optional(),
11360
11745
  after: optionalUnixTimestampParam("Unix timestamp lower bound."),
11361
11746
  before: optionalUnixTimestampParam("Unix timestamp upper bound."),
11362
- cursor: z39.string().min(1).describe("Cursor for the next result page.").optional(),
11363
- limit: z39.coerce.number().int().min(1).max(20).describe("Maximum results to return; Slack allows at most 20.").optional(),
11364
- sort: z39.enum(["score", "timestamp"]).describe("Rank by relevance or timestamp.").optional(),
11365
- sort_dir: z39.enum(["asc", "desc"]).describe("Sort direction.").optional()
11747
+ cursor: z40.string().min(1).describe("Cursor for the next result page.").optional(),
11748
+ limit: z40.coerce.number().int().min(1).max(20).describe("Maximum results to return; Slack allows at most 20.").optional(),
11749
+ sort: z40.enum(["score", "timestamp"]).describe("Rank by relevance or timestamp.").optional(),
11750
+ sort_dir: z40.enum(["asc", "desc"]).describe("Sort direction.").optional()
11366
11751
  }),
11367
11752
  outputSchema: publicSearchOutputSchema,
11368
11753
  execute: async ({
@@ -11447,7 +11832,7 @@ function createSlackPublicSearchTool(actionToken) {
11447
11832
  }
11448
11833
 
11449
11834
  // src/chat/slack/tools/message-add-reaction.ts
11450
- import { z as z40 } from "zod";
11835
+ import { z as z41 } from "zod";
11451
11836
 
11452
11837
  // src/chat/tools/idempotency.ts
11453
11838
  function stableSerialize(value) {
@@ -11478,8 +11863,8 @@ function createSlackMessageAddReactionTool(context, state) {
11478
11863
  readOnlyHint: false
11479
11864
  },
11480
11865
  description: "Add an emoji reaction to the current inbound Slack message.",
11481
- inputSchema: z40.object({
11482
- emoji: z40.string().min(1).max(64).describe(
11866
+ inputSchema: z41.object({
11867
+ emoji: z41.string().min(1).max(64).describe(
11483
11868
  "Slack emoji alias name to react with (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`). Optional surrounding colons are allowed."
11484
11869
  )
11485
11870
  }),
@@ -11528,14 +11913,14 @@ function createSlackMessageAddReactionTool(context, state) {
11528
11913
 
11529
11914
  // src/chat/slack/tools/send-files.ts
11530
11915
  import { createHash as createHash3 } from "crypto";
11531
- import { z as z41 } from "zod";
11916
+ import { z as z42 } from "zod";
11532
11917
  var sendFilesResultSchema = juniorToolOutputSchema.extend({
11533
- deduplicated: z41.boolean().optional(),
11534
- attachment_refs: z41.array(
11535
- z41.object({
11536
- id: z41.string().min(1),
11918
+ deduplicated: z42.boolean().optional(),
11919
+ attachment_refs: z42.array(
11920
+ z42.object({
11921
+ id: z42.string().min(1),
11537
11922
  // Same noun as storage, delivery events, and the report API.
11538
- filename: z41.string().min(1)
11923
+ filename: z42.string().min(1)
11539
11924
  })
11540
11925
  )
11541
11926
  });
@@ -11567,8 +11952,8 @@ function createSendFilesTool(context, state, materializeFile, attachments) {
11567
11952
  readOnlyHint: false
11568
11953
  },
11569
11954
  description: "Send one or more sandbox files into the active Slack conversation.",
11570
- inputSchema: z41.object({
11571
- files: z41.array(sandboxFileReferenceSchema).min(1).describe(
11955
+ inputSchema: z42.object({
11956
+ files: z42.array(sandboxFileReferenceSchema).min(1).describe(
11572
11957
  "One or more existing sandbox files. Objects returned by imageGenerate or webFetch can be passed unchanged."
11573
11958
  )
11574
11959
  }),
@@ -11987,7 +12372,7 @@ async function readCanvas(canvasIdOrUrl) {
11987
12372
  }
11988
12373
 
11989
12374
  // src/chat/slack/tools/canvas/create.ts
11990
- import { z as z42 } from "zod";
12375
+ import { z as z43 } from "zod";
11991
12376
  function createSlackCanvasCreateTool(context, state) {
11992
12377
  return zodTool({
11993
12378
  annotations: {
@@ -11997,9 +12382,9 @@ function createSlackCanvasCreateTool(context, state) {
11997
12382
  readOnlyHint: false
11998
12383
  },
11999
12384
  description: "Create a Slack canvas in the active channel.",
12000
- inputSchema: z42.object({
12001
- title: z42.string().min(1).max(160).describe("Canvas title."),
12002
- markdown: z42.string().min(1).describe("Canvas markdown body content.")
12385
+ inputSchema: z43.object({
12386
+ title: z43.string().min(1).max(160).describe("Canvas title."),
12387
+ markdown: z43.string().min(1).describe("Canvas markdown body content.")
12003
12388
  }),
12004
12389
  outputSchema: juniorToolOutputSchema,
12005
12390
  execute: async ({ title, markdown }) => {
@@ -12043,8 +12428,8 @@ function createSlackCanvasCreateTool(context, state) {
12043
12428
  }
12044
12429
 
12045
12430
  // src/chat/slack/tool-support/canvas/context.ts
12046
- import { z as z43 } from "zod";
12047
- var slackCanvasRefParam = z43.string().min(1).describe("Slack canvas/file ID or canvas/docs URL.");
12431
+ import { z as z44 } from "zod";
12432
+ var slackCanvasRefParam = z44.string().min(1).describe("Slack canvas/file ID or canvas/docs URL.");
12048
12433
  function resolveCanvasTarget(canvas) {
12049
12434
  const canvasId = extractCanvasId(canvas);
12050
12435
  if (!canvasId) {
@@ -12057,26 +12442,26 @@ function resolveCanvasTarget(canvas) {
12057
12442
  }
12058
12443
 
12059
12444
  // src/chat/slack/tools/canvas/edit.ts
12060
- import { z as z44 } from "zod";
12445
+ import { z as z45 } from "zod";
12061
12446
  function prepareCanvasEditArguments(input) {
12062
12447
  return prepareTextReplacementArguments(input);
12063
12448
  }
12064
- var editReplacementSchema2 = z44.object({
12065
- oldText: z44.string().min(1).describe(
12449
+ var editReplacementSchema2 = z45.object({
12450
+ oldText: z45.string().min(1).describe(
12066
12451
  "Exact Canvas markdown to replace. It must be unique in the current Canvas body and must not overlap another edit."
12067
12452
  ),
12068
- newText: z44.string().describe("Replacement Canvas markdown for this edit.")
12453
+ newText: z45.string().describe("Replacement Canvas markdown for this edit.")
12069
12454
  });
12070
12455
  var slackCanvasEditOutputSchema = juniorToolOutputSchema.extend({
12071
- canvas_id: z44.string().optional(),
12072
- title: z44.string().optional(),
12073
- permalink: z44.string().optional(),
12074
- diff: z44.string().optional(),
12075
- first_changed_line: z44.number().int().positive().optional(),
12076
- replacements: z44.number().int().nonnegative().optional(),
12077
- normalized_heading_count: z44.number().int().nonnegative().optional(),
12078
- summary: z44.string().optional(),
12079
- deduplicated: z44.boolean().optional()
12456
+ canvas_id: z45.string().optional(),
12457
+ title: z45.string().optional(),
12458
+ permalink: z45.string().optional(),
12459
+ diff: z45.string().optional(),
12460
+ first_changed_line: z45.number().int().positive().optional(),
12461
+ replacements: z45.number().int().nonnegative().optional(),
12462
+ normalized_heading_count: z45.number().int().nonnegative().optional(),
12463
+ summary: z45.string().optional(),
12464
+ deduplicated: z45.boolean().optional()
12080
12465
  }).strict();
12081
12466
  function createSlackCanvasEditTool(state) {
12082
12467
  return zodTool({
@@ -12089,9 +12474,9 @@ function createSlackCanvasEditTool(state) {
12089
12474
  description: "Edit a Slack canvas with exact markdown replacements. Returns a diff.",
12090
12475
  prepareArguments: prepareCanvasEditArguments,
12091
12476
  executionMode: "sequential",
12092
- inputSchema: z44.object({
12477
+ inputSchema: z45.object({
12093
12478
  canvas: slackCanvasRefParam,
12094
- edits: z44.array(editReplacementSchema2).min(1).describe(
12479
+ edits: z45.array(editReplacementSchema2).min(1).describe(
12095
12480
  "Exact replacements matched against the current Canvas body, not incrementally."
12096
12481
  )
12097
12482
  }),
@@ -12144,18 +12529,18 @@ function createSlackCanvasEditTool(state) {
12144
12529
  }
12145
12530
 
12146
12531
  // src/chat/slack/tools/canvas/read.ts
12147
- import { z as z45 } from "zod";
12532
+ import { z as z46 } from "zod";
12148
12533
  var slackCanvasReadOutputSchema = juniorToolOutputSchema.extend({
12149
- canvas_id: z45.string().optional(),
12150
- title: z45.string().optional(),
12151
- permalink: z45.string().optional(),
12152
- mimetype: z45.string().optional(),
12153
- filetype: z45.string().optional(),
12154
- original_byte_length: z45.number().int().nonnegative().optional(),
12155
- content: z45.string().optional(),
12156
- start_line: z45.number().int().positive().optional(),
12157
- end_line: z45.number().int().nonnegative().optional(),
12158
- total_lines: z45.number().int().nonnegative().optional()
12534
+ canvas_id: z46.string().optional(),
12535
+ title: z46.string().optional(),
12536
+ permalink: z46.string().optional(),
12537
+ mimetype: z46.string().optional(),
12538
+ filetype: z46.string().optional(),
12539
+ original_byte_length: z46.number().int().nonnegative().optional(),
12540
+ content: z46.string().optional(),
12541
+ start_line: z46.number().int().positive().optional(),
12542
+ end_line: z46.number().int().nonnegative().optional(),
12543
+ total_lines: z46.number().int().nonnegative().optional()
12159
12544
  }).strict();
12160
12545
  function createSlackCanvasReadTool() {
12161
12546
  return zodTool({
@@ -12166,10 +12551,10 @@ function createSlackCanvasReadTool() {
12166
12551
  openWorldHint: true,
12167
12552
  readOnlyHint: true
12168
12553
  },
12169
- inputSchema: z45.object({
12554
+ inputSchema: z46.object({
12170
12555
  canvas: slackCanvasRefParam,
12171
- offset: z45.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
12172
- limit: z45.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
12556
+ offset: z46.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
12557
+ limit: z46.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
12173
12558
  }),
12174
12559
  outputSchema: slackCanvasReadOutputSchema,
12175
12560
  execute: async ({ canvas, offset, limit }) => {
@@ -12205,7 +12590,7 @@ function createSlackCanvasReadTool() {
12205
12590
  }
12206
12591
 
12207
12592
  // src/chat/slack/tools/canvas/write.ts
12208
- import { z as z46 } from "zod";
12593
+ import { z as z47 } from "zod";
12209
12594
  function createSlackCanvasWriteTool(state) {
12210
12595
  return zodTool({
12211
12596
  annotations: {
@@ -12216,9 +12601,9 @@ function createSlackCanvasWriteTool(state) {
12216
12601
  },
12217
12602
  description: "Replace the full markdown body of a Slack canvas.",
12218
12603
  executionMode: "sequential",
12219
- inputSchema: z46.object({
12604
+ inputSchema: z47.object({
12220
12605
  canvas: slackCanvasRefParam,
12221
- content: z46.string().describe("UTF-8 markdown content to write.")
12606
+ content: z47.string().describe("UTF-8 markdown content to write.")
12222
12607
  }),
12223
12608
  outputSchema: juniorToolOutputSchema,
12224
12609
  execute: async ({ canvas, content }) => {
@@ -12440,12 +12825,12 @@ async function updateListItem(input) {
12440
12825
  }
12441
12826
 
12442
12827
  // src/chat/slack/tool-support/list/params.ts
12443
- import { z as z47 } from "zod";
12444
- var slackListIdParam = z47.string().min(1).describe("Slack list ID.");
12445
- var slackListItemIdParam = z47.string().min(1).describe("Slack list item ID.");
12828
+ import { z as z48 } from "zod";
12829
+ var slackListIdParam = z48.string().min(1).describe("Slack list ID.");
12830
+ var slackListItemIdParam = z48.string().min(1).describe("Slack list item ID.");
12446
12831
 
12447
12832
  // src/chat/slack/tools/list/add-items.ts
12448
- import { z as z48 } from "zod";
12833
+ import { z as z49 } from "zod";
12449
12834
  function createSlackListAddItemsTool(state) {
12450
12835
  return zodTool({
12451
12836
  annotations: {
@@ -12455,13 +12840,13 @@ function createSlackListAddItemsTool(state) {
12455
12840
  readOnlyHint: false
12456
12841
  },
12457
12842
  description: "Add tasks to a Slack list.",
12458
- inputSchema: z48.object({
12843
+ inputSchema: z49.object({
12459
12844
  list_id: slackListIdParam,
12460
- items: z48.array(z48.string().min(1)).min(1).max(25).describe("List item titles to create."),
12845
+ items: z49.array(z49.string().min(1)).min(1).max(25).describe("List item titles to create."),
12461
12846
  assignee_user_id: slackUserIdParam(
12462
12847
  "Optional Slack user ID assigned to all created items."
12463
12848
  ).optional(),
12464
- due_date: z48.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Optional due date in YYYY-MM-DD format.").optional()
12849
+ due_date: z49.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Optional due date in YYYY-MM-DD format.").optional()
12465
12850
  }),
12466
12851
  outputSchema: juniorToolOutputSchema,
12467
12852
  execute: async ({ list_id, items, assignee_user_id, due_date }) => {
@@ -12500,7 +12885,7 @@ function createSlackListAddItemsTool(state) {
12500
12885
  }
12501
12886
 
12502
12887
  // src/chat/slack/tools/list/create.ts
12503
- import { z as z49 } from "zod";
12888
+ import { z as z50 } from "zod";
12504
12889
  function createSlackListCreateTool(state) {
12505
12890
  return zodTool({
12506
12891
  annotations: {
@@ -12510,8 +12895,8 @@ function createSlackListCreateTool(state) {
12510
12895
  readOnlyHint: false
12511
12896
  },
12512
12897
  description: "Create a Slack todo list.",
12513
- inputSchema: z49.object({
12514
- name: z49.string().min(1).max(160).describe("Name for the new Slack list.")
12898
+ inputSchema: z50.object({
12899
+ name: z50.string().min(1).max(160).describe("Name for the new Slack list.")
12515
12900
  }),
12516
12901
  outputSchema: juniorToolOutputSchema,
12517
12902
  execute: async ({ name }) => {
@@ -12536,7 +12921,7 @@ function createSlackListCreateTool(state) {
12536
12921
  }
12537
12922
 
12538
12923
  // src/chat/slack/tools/list/get-items.ts
12539
- import { z as z50 } from "zod";
12924
+ import { z as z51 } from "zod";
12540
12925
  function createSlackListGetItemsTool() {
12541
12926
  return zodTool({
12542
12927
  description: "Read items from a Slack list.",
@@ -12546,9 +12931,9 @@ function createSlackListGetItemsTool() {
12546
12931
  openWorldHint: true,
12547
12932
  readOnlyHint: true
12548
12933
  },
12549
- inputSchema: z50.object({
12934
+ inputSchema: z51.object({
12550
12935
  list_id: slackListIdParam,
12551
- limit: z50.coerce.number().int().min(1).max(200).describe("Maximum number of list items to return.").optional()
12936
+ limit: z51.coerce.number().int().min(1).max(200).describe("Maximum number of list items to return.").optional()
12552
12937
  }),
12553
12938
  outputSchema: juniorToolOutputSchema,
12554
12939
  execute: async ({ list_id, limit }) => {
@@ -12563,23 +12948,23 @@ function createSlackListGetItemsTool() {
12563
12948
  }
12564
12949
 
12565
12950
  // src/chat/slack/tools/list/update-item.ts
12566
- import { z as z51 } from "zod";
12567
- var booleanInput3 = (description) => z51.preprocess(
12951
+ import { z as z52 } from "zod";
12952
+ var booleanInput3 = (description) => z52.preprocess(
12568
12953
  (value) => value === "true" ? true : value === "false" ? false : value,
12569
- z51.boolean()
12954
+ z52.boolean()
12570
12955
  ).describe(description);
12571
- var updateListItemInputSchema = z51.union([
12572
- z51.object({
12956
+ var updateListItemInputSchema = z52.union([
12957
+ z52.object({
12573
12958
  list_id: slackListIdParam,
12574
12959
  item_id: slackListItemIdParam,
12575
12960
  completed: booleanInput3("Optional completion status update."),
12576
- title: z51.string().min(1).describe("Optional new item title.").optional()
12961
+ title: z52.string().min(1).describe("Optional new item title.").optional()
12577
12962
  }),
12578
- z51.object({
12963
+ z52.object({
12579
12964
  list_id: slackListIdParam,
12580
12965
  item_id: slackListItemIdParam,
12581
12966
  completed: booleanInput3("Optional completion status update.").optional(),
12582
- title: z51.string().min(1).describe("Optional new item title.")
12967
+ title: z52.string().min(1).describe("Optional new item title.")
12583
12968
  })
12584
12969
  ]);
12585
12970
  function createSlackListUpdateItemTool(state) {
@@ -12627,7 +13012,7 @@ function createSlackListUpdateItemTool(state) {
12627
13012
  }
12628
13013
 
12629
13014
  // src/chat/slack/tools/thread-read.ts
12630
- import { z as z52 } from "zod";
13015
+ import { z as z53 } from "zod";
12631
13016
 
12632
13017
  // src/chat/slack/tool-support/slack-message-url.ts
12633
13018
  var SLACK_HOST_PATTERN = /^[a-z0-9-]+\.slack(?:-gov)?\.com$/;
@@ -12893,14 +13278,14 @@ function createSlackThreadReadTool(context) {
12893
13278
  openWorldHint: true,
12894
13279
  readOnlyHint: true
12895
13280
  },
12896
- inputSchema: z52.object({
12897
- url: z52.string().min(1).describe("Slack message archive URL.").optional(),
13281
+ inputSchema: z53.object({
13282
+ url: z53.string().min(1).describe("Slack message archive URL.").optional(),
12898
13283
  channel_id: slackChannelRefParam.optional(),
12899
13284
  ts: slackTimestampParam(
12900
13285
  "Slack message timestamp. May be the thread root or any message in the thread."
12901
13286
  ).optional(),
12902
- limit: z52.coerce.number().int().min(1).max(1e3).describe("Maximum number of thread messages to fetch.").optional(),
12903
- max_pages: z52.coerce.number().int().min(1).max(10).describe("Maximum number of Slack API pages to traverse.").optional()
13287
+ limit: z53.coerce.number().int().min(1).max(1e3).describe("Maximum number of thread messages to fetch.").optional(),
13288
+ max_pages: z53.coerce.number().int().min(1).max(10).describe("Maximum number of Slack API pages to traverse.").optional()
12904
13289
  }),
12905
13290
  outputSchema: juniorToolOutputSchema,
12906
13291
  execute: async ({ url, channel_id, ts, limit, max_pages }) => {
@@ -13027,7 +13412,7 @@ function createSlackThreadReadTool(context) {
13027
13412
  // src/chat/tools/user-lookup.ts
13028
13413
  import { and as and2, eq as eq2, or, sql } from "drizzle-orm";
13029
13414
  import { alias } from "drizzle-orm/pg-core";
13030
- import { z as z53 } from "zod";
13415
+ import { z as z54 } from "zod";
13031
13416
  var linkedSlackIdentity = alias(juniorIdentities, "user_lookup_slack_identity");
13032
13417
  function explicitUserLookupError(error) {
13033
13418
  if (error.apiError === "user_not_found" || error.code === "not_found") {
@@ -13176,9 +13561,9 @@ function createUserLookupTool(teamId, providers) {
13176
13561
  openWorldHint: true,
13177
13562
  readOnlyHint: true
13178
13563
  },
13179
- inputSchema: z53.object({
13180
- provider: z53.enum(providers).describe("Enabled identity provider to query."),
13181
- query: z53.string().trim().min(1).describe("Provider subject ID, handle, Slack email, or Slack name.")
13564
+ inputSchema: z54.object({
13565
+ provider: z54.enum(providers).describe("Enabled identity provider to query."),
13566
+ query: z54.string().trim().min(1).describe("Provider subject ID, handle, Slack email, or Slack name.")
13182
13567
  }).strict(),
13183
13568
  outputSchema: juniorToolOutputSchema,
13184
13569
  execute: async ({ provider, query }) => {
@@ -13198,18 +13583,18 @@ function createUserLookupTool(teamId, providers) {
13198
13583
  }
13199
13584
 
13200
13585
  // src/chat/tools/system-time.ts
13201
- import { z as z54 } from "zod";
13202
- var systemTimeInputSchema = z54.object({
13203
- timezone: z54.string().trim().min(1).optional().describe(
13586
+ import { z as z55 } from "zod";
13587
+ var systemTimeInputSchema = z55.object({
13588
+ timezone: z55.string().trim().min(1).optional().describe(
13204
13589
  "Optional IANA timezone, for example America/Los_Angeles. When set, iso_local and timezone_offset_minutes are for that zone."
13205
13590
  )
13206
13591
  });
13207
13592
  var systemTimeOutputSchema = juniorToolOutputSchema.extend({
13208
- unix_ms: z54.number(),
13209
- iso_utc: z54.string(),
13210
- iso_local: z54.string(),
13211
- timezone: z54.string().nullable(),
13212
- timezone_offset_minutes: z54.number()
13593
+ unix_ms: z55.number(),
13594
+ iso_utc: z55.string(),
13595
+ iso_local: z55.string(),
13596
+ timezone: z55.string().nullable(),
13597
+ timezone_offset_minutes: z55.number()
13213
13598
  });
13214
13599
  function createSystemTimeTool() {
13215
13600
  return zodTool({
@@ -13289,7 +13674,7 @@ function getTimeZoneOffsetMinutes(timestampMs, timezone) {
13289
13674
  }
13290
13675
 
13291
13676
  // src/chat/tools/publish-image.ts
13292
- import { z as z55 } from "zod";
13677
+ import { z as z56 } from "zod";
13293
13678
 
13294
13679
  // src/chat/artifacts/store.ts
13295
13680
  import { createHash as createHash4, randomUUID as randomUUID4 } from "crypto";
@@ -13490,10 +13875,10 @@ function unpublishedArtifactHeaders() {
13490
13875
 
13491
13876
  // src/chat/tools/publish-image.ts
13492
13877
  var outputSchema5 = juniorToolOutputSchema.extend({
13493
- bytes: z55.number().int().positive(),
13494
- content_type: z55.string().min(1),
13495
- public: z55.literal(true),
13496
- url: z55.string().url()
13878
+ bytes: z56.number().int().positive(),
13879
+ content_type: z56.string().min(1),
13880
+ public: z56.literal(true),
13881
+ url: z56.string().url()
13497
13882
  });
13498
13883
  function createPublishImageTool(args) {
13499
13884
  return zodTool({
@@ -13507,8 +13892,8 @@ function createPublishImageTool(args) {
13507
13892
  description: "Publish one sandbox image to a durable public HTTPS URL. Anyone on the internet with the URL can view the image. Use only when an external destination needs a public image URL. Do not use for private file sharing or private conversation storage. Supports PNG, JPEG, GIF, and WebP up to 10 MB.",
13508
13893
  describeProposal: ({ path: path8 }) => `Publish sandbox image ${path8} to a public internet URL.`,
13509
13894
  executionMode: "sequential",
13510
- inputSchema: z55.object({
13511
- path: z55.string().min(1).describe("Exact sandbox path of an existing image file.")
13895
+ inputSchema: z56.object({
13896
+ path: z56.string().min(1).describe("Exact sandbox path of an existing image file.")
13512
13897
  }).strict(),
13513
13898
  outputSchema: outputSchema5,
13514
13899
  async execute({ path: path8 }) {
@@ -13541,10 +13926,10 @@ function createPublishImageTool(args) {
13541
13926
  }
13542
13927
 
13543
13928
  // src/chat/tools/unpublish-image.ts
13544
- import { z as z56 } from "zod";
13929
+ import { z as z57 } from "zod";
13545
13930
  var outputSchema6 = juniorToolOutputSchema.extend({
13546
- filename: z56.string().min(1),
13547
- unpublished: z56.literal(true)
13931
+ filename: z57.string().min(1),
13932
+ unpublished: z57.literal(true)
13548
13933
  });
13549
13934
  function createUnpublishImageTool(args) {
13550
13935
  return zodTool({
@@ -13558,8 +13943,8 @@ function createUnpublishImageTool(args) {
13558
13943
  description: "Unpublish one public image previously published in this conversation so its public URL stops serving. Pass the public artifact URL or `<id>.<ext>` filename. Only images owned by this conversation can be unpublished. Republishing the same image bytes later in this conversation restores a live URL for this conversation. Does not remove copies already fetched by browsers or GitHub.",
13559
13944
  describeProposal: ({ ref }) => `Unpublish public image ${ref}.`,
13560
13945
  executionMode: "sequential",
13561
- inputSchema: z56.object({
13562
- ref: z56.string().min(1).describe(
13946
+ inputSchema: z57.object({
13947
+ ref: z57.string().min(1).describe(
13563
13948
  "Public artifact URL or artifact filename (`<id>.<ext>`)."
13564
13949
  )
13565
13950
  }).strict(),
@@ -13579,27 +13964,27 @@ function createUnpublishImageTool(args) {
13579
13964
  }
13580
13965
 
13581
13966
  // src/chat/tools/search-conversation-events.ts
13582
- import { z as z57 } from "zod";
13967
+ import { z as z58 } from "zod";
13583
13968
  var DEFAULT_LIMIT3 = 25;
13584
13969
  var MAX_LIMIT2 = 100;
13585
13970
  var MAX_EVENT_DATA_BYTES = 4e3;
13586
13971
  var MAX_EVENTS_JSON_BYTES = 2e4;
13587
13972
  var MAX_IDENTITY_CHARS = 256;
13588
13973
  var textEncoder = new TextEncoder();
13589
- var knownEventTypeSchema = z57.enum(KNOWN_CONVERSATION_EVENT_TYPES);
13590
- var projectedEventSchema = z57.object({
13591
- seq: z57.number().int().nonnegative().describe("Stable event position for pagination."),
13592
- history_version: z57.number().int().nonnegative().describe("Agent history generation after replacement."),
13593
- created_at: z57.iso.datetime().describe("When the event was recorded."),
13594
- idempotency_key: z57.string().min(1).optional().describe("Retry-stable event identity, when assigned."),
13595
- data: z57.record(z57.string(), z57.unknown()).describe("Bounded event data.")
13974
+ var knownEventTypeSchema = z58.enum(KNOWN_CONVERSATION_EVENT_TYPES);
13975
+ var projectedEventSchema = z58.object({
13976
+ seq: z58.number().int().nonnegative().describe("Stable event position for pagination."),
13977
+ history_version: z58.number().int().nonnegative().describe("Agent history generation after replacement."),
13978
+ created_at: z58.iso.datetime().describe("When the event was recorded."),
13979
+ idempotency_key: z58.string().min(1).optional().describe("Retry-stable event identity, when assigned."),
13980
+ data: z58.record(z58.string(), z58.unknown()).describe("Bounded event data.")
13596
13981
  }).strict();
13597
13982
  var searchConversationEventsOutputSchema = juniorToolOutputSchema.extend({
13598
- conversation_id: z57.string().min(1),
13599
- events: z57.array(projectedEventSchema),
13600
- has_older: z57.boolean().describe("Whether matching older events exist."),
13601
- has_newer: z57.boolean().describe("Whether matching newer events exist."),
13602
- omitted_event_count: z57.number().int().nonnegative().optional().describe("Events omitted by the response byte limit.")
13983
+ conversation_id: z58.string().min(1),
13984
+ events: z58.array(projectedEventSchema),
13985
+ has_older: z58.boolean().describe("Whether matching older events exist."),
13986
+ has_newer: z58.boolean().describe("Whether matching newer events exist."),
13987
+ omitted_event_count: z58.number().int().nonnegative().optional().describe("Events omitted by the response byte limit.")
13603
13988
  });
13604
13989
  function createSearchConversationEventsTool(context) {
13605
13990
  return zodTool({
@@ -13612,16 +13997,16 @@ function createSearchConversationEventsTool(context) {
13612
13997
  openWorldHint: false,
13613
13998
  readOnlyHint: true
13614
13999
  },
13615
- inputSchema: z57.object({
13616
- conversation_id: z57.string().trim().min(1).nullable().describe(
14000
+ inputSchema: z58.object({
14001
+ conversation_id: z58.string().trim().min(1).nullable().describe(
13617
14002
  "Conversation ID to search. Omit or null for the current conversation."
13618
14003
  ).optional(),
13619
- after_seq: z57.number().int().nonnegative().nullable().describe("Exclusive event sequence lower bound; returns ascending.").optional(),
13620
- before_seq: z57.number().int().nonnegative().nullable().describe("Exclusive event sequence upper bound.").optional(),
13621
- limit: z57.number().int().min(1).max(MAX_LIMIT2).nullable().describe(
14004
+ after_seq: z58.number().int().nonnegative().nullable().describe("Exclusive event sequence lower bound; returns ascending.").optional(),
14005
+ before_seq: z58.number().int().nonnegative().nullable().describe("Exclusive event sequence upper bound.").optional(),
14006
+ limit: z58.number().int().min(1).max(MAX_LIMIT2).nullable().describe(
13622
14007
  `Maximum events. Default ${DEFAULT_LIMIT3}; max ${MAX_LIMIT2}.`
13623
14008
  ).optional(),
13624
- types: z57.array(knownEventTypeSchema).min(1).nullable().describe("Event types to include; omit for all types.").optional()
14009
+ types: z58.array(knownEventTypeSchema).min(1).nullable().describe("Event types to include; omit for all types.").optional()
13625
14010
  }).strict(),
13626
14011
  outputSchema: searchConversationEventsOutputSchema,
13627
14012
  execute: async (input) => {
@@ -13870,14 +14255,21 @@ function stripReplacementHistoryField(value) {
13870
14255
  }
13871
14256
 
13872
14257
  // src/chat/tools/handoff/tool.ts
13873
- import { z as z58 } from "zod";
14258
+ import { z as z59 } from "zod";
13874
14259
  var HANDOFF_TOOL_NAME = "handoff";
14260
+ function formatHandoffProfiles(handoff) {
14261
+ return handoff.profiles.map(
14262
+ (profile) => `- ${formatModelProfile(profile.name, profile.description)}`
14263
+ ).join("\n");
14264
+ }
13875
14265
  function createHandoffTool(handoff) {
13876
- const profileSchema = z58.enum(handoff.profiles);
14266
+ const profileSchema = z59.enum(
14267
+ handoff.profiles.map((profile) => profile.name)
14268
+ );
13877
14269
  const handoffResultSchema = juniorToolOutputSchema.extend({
13878
14270
  model_profile: modelProfileSchema
13879
14271
  });
13880
- const profileNames = handoff.profiles.map((profile) => `\`${profile}\``).join(", ");
14272
+ const profileList = formatHandoffProfiles(handoff);
13881
14273
  return zodTool({
13882
14274
  annotations: {
13883
14275
  destructiveHint: false,
@@ -13885,10 +14277,21 @@ function createHandoffTool(handoff) {
13885
14277
  openWorldHint: false,
13886
14278
  readOnlyHint: false
13887
14279
  },
13888
- description: `Switch to another model profile and continue the same task. Profiles: ${profileNames}. Call this as the only tool.`,
14280
+ description: [
14281
+ "Switch this conversation to another configured model profile and continue the same task.",
14282
+ "Call this as the only tool in the assistant turn, before substantial analysis or implementation, when a listed profile's description fits the task better than the current profile.",
14283
+ "Use each description's use and avoid cases. Do not select by the profile name or assume that a non-default profile is stronger.",
14284
+ "Do not call this for ordinary lookups, short answers, light investigation, or only because the task mentions code.",
14285
+ "Do not call this after you have done the difficult work on the current profile. Do not combine it with other tools in the same assistant message.",
14286
+ "A successful handoff becomes the active profile for later turns. Another handoff can change it again.",
14287
+ `Available profiles:
14288
+ ${profileList}`
14289
+ ].join(" "),
13889
14290
  executionMode: "sequential",
13890
- inputSchema: z58.object({
13891
- profile: profileSchema.describe("Target model profile")
14291
+ inputSchema: z59.object({
14292
+ profile: profileSchema.describe(
14293
+ "Exact configured profile name. Choose the profile whose description best fits the remaining task. If none clearly fits better, do not call handoff."
14294
+ )
13892
14295
  }).strict(),
13893
14296
  outputSchema: handoffResultSchema,
13894
14297
  execute: async (input, options) => {
@@ -13908,7 +14311,7 @@ function createHandoffTool(handoff) {
13908
14311
  }
13909
14312
 
13910
14313
  // src/chat/tools/web/fetch-tool.ts
13911
- import { z as z59 } from "zod";
14314
+ import { z as z60 } from "zod";
13912
14315
 
13913
14316
  // src/chat/tools/web/constants.ts
13914
14317
  var USER_AGENT = "junior-bot/0.1";
@@ -14357,9 +14760,9 @@ function createWebFetchTool(hooks, options = {}) {
14357
14760
  openWorldHint: true,
14358
14761
  readOnlyHint: true
14359
14762
  },
14360
- inputSchema: z59.object({
14361
- url: z59.string().min(1).describe("HTTP(S) URL to fetch."),
14362
- max_chars: z59.coerce.number().int().min(500).max(MAX_FETCH_CHARS).describe("Optional maximum number of extracted characters to return.").optional()
14763
+ inputSchema: z60.object({
14764
+ url: z60.string().min(1).describe("HTTP(S) URL to fetch."),
14765
+ max_chars: z60.coerce.number().int().min(500).max(MAX_FETCH_CHARS).describe("Optional maximum number of extracted characters to return.").optional()
14363
14766
  }),
14364
14767
  outputSchema: juniorToolOutputSchema,
14365
14768
  execute: async ({ url, max_chars }) => {
@@ -14404,7 +14807,7 @@ function createWebFetchTool(hooks, options = {}) {
14404
14807
  }
14405
14808
 
14406
14809
  // src/chat/tools/web/search.ts
14407
- import { z as z60 } from "zod";
14810
+ import { z as z61 } from "zod";
14408
14811
  import { generateText } from "ai";
14409
14812
  import { createGatewayProvider } from "@ai-sdk/gateway";
14410
14813
  var SEARCH_TIMEOUT_MS = 6e4;
@@ -14446,9 +14849,9 @@ function createWebSearchTool(modelId, override) {
14446
14849
  openWorldHint: true,
14447
14850
  readOnlyHint: true
14448
14851
  },
14449
- inputSchema: z60.object({
14450
- query: z60.string().min(1).max(500).describe("Search query."),
14451
- max_results: z60.coerce.number().int().min(1).max(MAX_RESULTS2).describe("Max results to return.").optional()
14852
+ inputSchema: z61.object({
14853
+ query: z61.string().min(1).max(500).describe("Search query."),
14854
+ max_results: z61.coerce.number().int().min(1).max(MAX_RESULTS2).describe("Max results to return.").optional()
14452
14855
  }),
14453
14856
  outputSchema: juniorToolOutputSchema,
14454
14857
  execute: async ({ query, max_results }) => {
@@ -14490,7 +14893,7 @@ function createWebSearchTool(modelId, override) {
14490
14893
  }
14491
14894
 
14492
14895
  // src/chat/tools/sandbox/write-file.ts
14493
- import { z as z61 } from "zod";
14896
+ import { z as z62 } from "zod";
14494
14897
  function createWriteFileTool() {
14495
14898
  return zodTool({
14496
14899
  annotations: {
@@ -14501,9 +14904,9 @@ function createWriteFileTool() {
14501
14904
  },
14502
14905
  description: "Write UTF-8 content to a file in the sandbox workspace. Use for intentional file creation or deliberate full-file replacement after validation; use editFile instead for targeted changes to existing files. Do not use for exploratory analysis-only turns.",
14503
14906
  executionMode: "sequential",
14504
- inputSchema: z61.object({
14505
- path: z61.string().min(1).describe("Path to write in the sandbox workspace."),
14506
- content: z61.string().describe("UTF-8 file content to write.")
14907
+ inputSchema: z62.object({
14908
+ path: z62.string().min(1).describe("Path to write in the sandbox workspace."),
14909
+ content: z62.string().describe("UTF-8 file content to write.")
14507
14910
  }),
14508
14911
  outputSchema: juniorToolOutputSchema,
14509
14912
  execute: async () => {
@@ -14515,7 +14918,7 @@ function createWriteFileTool() {
14515
14918
  }
14516
14919
 
14517
14920
  // src/chat/workspaces/tools.ts
14518
- import { z as z62 } from "zod";
14921
+ import { z as z63 } from "zod";
14519
14922
  import {
14520
14923
  resourceEventSubscriptionResultSchema
14521
14924
  } from "@sentry/junior-plugin-api";
@@ -14547,16 +14950,16 @@ async function stopWorkspaceSnapshotWatch(input) {
14547
14950
  });
14548
14951
  }
14549
14952
  }
14550
- var repoSchema = z62.object({
14551
- provider: z62.string(),
14552
- repo: z62.string(),
14553
- checkout_path: z62.string()
14953
+ var repoSchema = z63.object({
14954
+ provider: z63.string(),
14955
+ repo: z63.string(),
14956
+ checkout_path: z63.string()
14554
14957
  });
14555
- var workspaceSchema = z62.object({
14556
- id: z62.string(),
14557
- name: z62.string(),
14558
- setup_script: z62.string(),
14559
- repos: z62.array(repoSchema)
14958
+ var workspaceSchema = z63.object({
14959
+ id: z63.string(),
14960
+ name: z63.string(),
14961
+ setup_script: z63.string(),
14962
+ repos: z63.array(repoSchema)
14560
14963
  });
14561
14964
  function view(workspace) {
14562
14965
  return {
@@ -14589,18 +14992,18 @@ function workspaceProviderNames() {
14589
14992
  }
14590
14993
  function workspaceWriteSchemas(providers) {
14591
14994
  const providerNames = providers.map((provider) => `\`${provider}\``).join(", ");
14592
- const repoInputSchema = z62.object({
14593
- provider: z62.enum(providers).describe(`Repository provider. Supported: ${providerNames}.`),
14594
- repo: z62.string().trim().min(1).describe("Repository in owner/name format.")
14995
+ const repoInputSchema = z63.object({
14996
+ provider: z63.enum(providers).describe(`Repository provider. Supported: ${providerNames}.`),
14997
+ repo: z63.string().trim().min(1).describe("Repository in owner/name format.")
14595
14998
  }).strict();
14596
- const workspaceInputSchema = z62.object({
14597
- name: z62.string().trim().min(1).describe(
14999
+ const workspaceInputSchema = z63.object({
15000
+ name: z63.string().trim().min(1).describe(
14598
15001
  "Workspace name. Use lowercase letters, digits, underscores, or hyphens."
14599
15002
  ),
14600
- setup_script: z62.string().nullable().describe(
15003
+ setup_script: z63.string().nullable().describe(
14601
15004
  "Optional shell script to run after repository checkout whenever this Workspace starts. Omit or use null for no setup script."
14602
15005
  ).optional(),
14603
- repos: z62.array(repoInputSchema).max(32).describe("Complete repository list.")
15006
+ repos: z63.array(repoInputSchema).max(32).describe("Complete repository list.")
14604
15007
  }).strict();
14605
15008
  return { providerNames, workspaceInputSchema };
14606
15009
  }
@@ -14675,7 +15078,7 @@ function createWorkspaceWriteTools(providers) {
14675
15078
  },
14676
15079
  description: `Replace an install-wide Workspace recipe. Repository providers: ${providerNames}. Use the Workspace ID returned by listWorkspaces.`,
14677
15080
  inputSchema: workspaceInputSchema.extend({
14678
- id: z62.string().uuid().describe("Workspace ID from listWorkspaces.")
15081
+ id: z63.string().uuid().describe("Workspace ID from listWorkspaces.")
14679
15082
  }).strict(),
14680
15083
  prepareArguments(args) {
14681
15084
  const input = args;
@@ -14708,11 +15111,11 @@ function createWorkspaceWriteTools(providers) {
14708
15111
  readOnlyHint: false
14709
15112
  },
14710
15113
  description: "Delete one install-wide Workspace recipe. Use the Workspace ID returned by listWorkspaces.",
14711
- inputSchema: z62.object({
14712
- id: z62.string().uuid().describe("Workspace ID from listWorkspaces.")
15114
+ inputSchema: z63.object({
15115
+ id: z63.string().uuid().describe("Workspace ID from listWorkspaces.")
14713
15116
  }).strict(),
14714
15117
  outputSchema: juniorToolOutputSchema.extend({
14715
- deleted: z62.literal(true)
15118
+ deleted: z63.literal(true)
14716
15119
  }),
14717
15120
  async execute({ id }) {
14718
15121
  const deleted = await workspaceWrite(() => deleteWorkspace(id));
@@ -14737,10 +15140,10 @@ function createWorkspaceTools(context) {
14737
15140
  readOnlyHint: true
14738
15141
  },
14739
15142
  description: "List named repository workspaces that can replace the current sandbox.",
14740
- inputSchema: z62.object({}).strict(),
15143
+ inputSchema: z63.object({}).strict(),
14741
15144
  outputSchema: juniorToolOutputSchema.extend({
14742
- active_workspace_id: z62.string().nullable(),
14743
- workspaces: z62.array(workspaceSchema)
15145
+ active_workspace_id: z63.string().nullable(),
15146
+ workspaces: z63.array(workspaceSchema)
14744
15147
  }),
14745
15148
  async execute() {
14746
15149
  return {
@@ -14758,12 +15161,12 @@ function createWorkspaceTools(context) {
14758
15161
  readOnlyHint: false
14759
15162
  },
14760
15163
  description: "Replace the current sandbox with a named repository Workspace. Files in the old sandbox do not carry over. Returns ready after the switch, or building with a temporary subscription when the snapshot is still being prepared. When building, wait for the ready event and call switchWorkspace again with the same name.",
14761
- inputSchema: z62.object({
14762
- name: z62.string().trim().min(1).describe("Exact workspace name.")
15164
+ inputSchema: z63.object({
15165
+ name: z63.string().trim().min(1).describe("Exact workspace name.")
14763
15166
  }).strict(),
14764
15167
  outputSchema: juniorToolOutputSchema.extend({
14765
15168
  workspace: workspaceSchema,
14766
- status: z62.enum(["ready", "building"]),
15169
+ status: z63.enum(["ready", "building"]),
14767
15170
  subscription: resourceEventSubscriptionResultSchema.optional().describe(
14768
15171
  "Present when the snapshot ready and failed events are already watched for this conversation."
14769
15172
  )
@@ -15549,7 +15952,7 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, conv
15549
15952
  }
15550
15953
 
15551
15954
  // src/chat/tools/execute-tool.ts
15552
- import { z as z63 } from "zod";
15955
+ import { z as z64 } from "zod";
15553
15956
  var EXECUTE_TOOL_NAME = "executeTool";
15554
15957
  function createExecuteToolTool() {
15555
15958
  return zodTool({
@@ -15561,11 +15964,11 @@ function createExecuteToolTool() {
15561
15964
  },
15562
15965
  description: "Execute any catalog tool by exact tool_name from searchTools or a tool-result execution hint. Put tool-specific parameters inside arguments.",
15563
15966
  executionMode: "sequential",
15564
- inputSchema: z63.object({
15565
- tool_name: z63.string().min(1).describe(
15967
+ inputSchema: z64.object({
15968
+ tool_name: z64.string().min(1).describe(
15566
15969
  "Exact catalog tool_name returned by searchTools or a tool-result execution hint."
15567
15970
  ),
15568
- arguments: z63.record(z63.string(), z63.unknown()).describe(
15971
+ arguments: z64.record(z64.string(), z64.unknown()).describe(
15569
15972
  'Arguments matching the selected catalog tool schema, for example { "query": "..." }.'
15570
15973
  ).optional()
15571
15974
  }).strict(),
@@ -15605,7 +16008,7 @@ function planToolExposure(tools) {
15605
16008
  }
15606
16009
 
15607
16010
  // src/chat/tools/search-tools.ts
15608
- import { z as z64 } from "zod";
16011
+ import { z as z65 } from "zod";
15609
16012
  var SEARCH_TOOLS_NAME = "searchTools";
15610
16013
  var DEFAULT_MAX_RESULTS2 = 5;
15611
16014
  var MAX_RESULTS3 = 20;
@@ -15650,29 +16053,29 @@ var SEARCH_STOP_WORDS = /* @__PURE__ */ new Set([
15650
16053
  "you",
15651
16054
  "your"
15652
16055
  ]);
15653
- var searchToolsSourceSchema = z64.object({
15654
- id: z64.string(),
15655
- description: z64.string()
16056
+ var searchToolsSourceSchema = z65.object({
16057
+ id: z65.string(),
16058
+ description: z65.string()
15656
16059
  }).strict();
15657
- var searchToolsToolSchema = z64.object({
15658
- tool_name: z64.string(),
15659
- description: z64.string(),
15660
- exposure: z64.enum(["direct", "deferred", "modelOnly", "hidden"]),
15661
- source: z64.string().optional(),
15662
- input_schema: z64.unknown(),
15663
- call_notes: z64.array(z64.string()),
15664
- annotations: z64.record(z64.string(), z64.unknown())
16060
+ var searchToolsToolSchema = z65.object({
16061
+ tool_name: z65.string(),
16062
+ description: z65.string(),
16063
+ exposure: z65.enum(["direct", "deferred", "modelOnly", "hidden"]),
16064
+ source: z65.string().optional(),
16065
+ input_schema: z65.unknown(),
16066
+ call_notes: z65.array(z65.string()),
16067
+ annotations: z65.record(z65.string(), z65.unknown())
15665
16068
  }).strict();
15666
16069
  var searchToolsOutputSchema = juniorToolOutputSchema.extend({
15667
- query: z64.string().nullable(),
15668
- source: z64.string().nullable(),
15669
- sources: z64.array(searchToolsSourceSchema),
15670
- total_catalog_tools: z64.number().int().nonnegative(),
15671
- total_eligible_tools: z64.number().int().nonnegative(),
15672
- total_matches: z64.number().int().nonnegative(),
15673
- returned_tools: z64.number().int().nonnegative(),
15674
- execution_tool: z64.literal("executeTool"),
15675
- tools: z64.array(searchToolsToolSchema)
16070
+ query: z65.string().nullable(),
16071
+ source: z65.string().nullable(),
16072
+ sources: z65.array(searchToolsSourceSchema),
16073
+ total_catalog_tools: z65.number().int().nonnegative(),
16074
+ total_eligible_tools: z65.number().int().nonnegative(),
16075
+ total_matches: z65.number().int().nonnegative(),
16076
+ returned_tools: z65.number().int().nonnegative(),
16077
+ execution_tool: z65.literal("executeTool"),
16078
+ tools: z65.array(searchToolsToolSchema)
15676
16079
  }).strict();
15677
16080
  function terms(value) {
15678
16081
  const chunks = value.match(/[\p{L}\p{N}]+/gu) ?? [];
@@ -15883,14 +16286,14 @@ function createSearchToolsTool(catalogTools) {
15883
16286
  openWorldHint: false,
15884
16287
  readOnlyHint: true
15885
16288
  },
15886
- inputSchema: z64.object({
15887
- query: z64.string().nullable().describe(
16289
+ inputSchema: z65.object({
16290
+ query: z65.string().nullable().describe(
15888
16291
  "Optional search terms describing the tool, owner, action, or arguments needed. Empty string lists catalog tools."
15889
16292
  ).optional(),
15890
- source: z64.string().nullable().describe(
16293
+ source: z65.string().nullable().describe(
15891
16294
  "Optional source id to search within, such as a plugin source returned in sources."
15892
16295
  ).optional(),
15893
- max_results: z64.number().int().min(1).max(MAX_RESULTS3).nullable().describe("Maximum matching catalog tool descriptors to return.").optional()
16296
+ max_results: z65.number().int().min(1).max(MAX_RESULTS3).nullable().describe("Maximum matching catalog tool descriptors to return.").optional()
15894
16297
  }).strict(),
15895
16298
  outputSchema: searchToolsOutputSchema,
15896
16299
  privateTraceResult: (result) => ({
@@ -17188,7 +17591,7 @@ function createPluginEgress(deps) {
17188
17591
  }
17189
17592
 
17190
17593
  // src/chat/services/guardian-action-review.ts
17191
- import { z as z65 } from "zod";
17594
+ import { z as z66 } from "zod";
17192
17595
 
17193
17596
  // src/chat/services/guardian-action-policy.ts
17194
17597
  var GUARDIAN_ACTION_POLICY = `You are judging one planned Junior agent action.
@@ -17262,17 +17665,17 @@ Assess the exact action's intrinsic risk and whether the user's intent authorize
17262
17665
  - Keep the reason to one concise, specific sentence grounded in the main risk or authorization fact. For ask, name the exact action, target, and material side effects the user must confirm.`;
17263
17666
 
17264
17667
  // src/chat/services/guardian-action-review.ts
17265
- var guardianDecisionSchema = z65.object({
17266
- decision: z65.enum(["allow", "ask", "deny"]),
17267
- reason: z65.string().trim().min(1).max(500),
17268
- riskLevel: z65.enum(["low", "medium", "high", "critical"]),
17269
- userAuthorization: z65.enum(["high", "medium", "low", "unknown"])
17668
+ var guardianDecisionSchema = z66.object({
17669
+ decision: z66.enum(["allow", "ask", "deny"]),
17670
+ reason: z66.string().trim().min(1).max(500),
17671
+ riskLevel: z66.enum(["low", "medium", "high", "critical"]),
17672
+ userAuthorization: z66.enum(["high", "medium", "low", "unknown"])
17270
17673
  }).strict();
17271
17674
  var GUARDIAN_REVIEW_TIMEOUT_MS = 6e4;
17272
17675
  var GUARDIAN_REVIEW_MAX_TOKENS = 2e3;
17273
17676
  var MAX_PROPOSAL_CHARS = 192e3;
17274
17677
  function guardianPrompt(proposal) {
17275
- const proposalJson = JSON.stringify(z65.json().parse(proposal), null, 2);
17678
+ const proposalJson = JSON.stringify(z66.json().parse(proposal), null, 2);
17276
17679
  if (proposalJson.length > MAX_PROPOSAL_CHARS) {
17277
17680
  throw new Error(
17278
17681
  `Guardian action proposal exceeds ${MAX_PROPOSAL_CHARS} characters.`
@@ -18601,6 +19004,145 @@ ${summary}`
18601
19004
  return { compacted: true, piMessages: messages };
18602
19005
  }
18603
19006
 
19007
+ // src/chat/agent/handoff.ts
19008
+ var EXCLUSIVE_TOOL_NAMES = [HANDOFF_TOOL_NAME, "switchWorkspace"];
19009
+ function exclusiveToolName(toolCalls) {
19010
+ for (const name of EXCLUSIVE_TOOL_NAMES) {
19011
+ if (toolCalls.some((call) => call.name === name)) {
19012
+ return name;
19013
+ }
19014
+ }
19015
+ return void 0;
19016
+ }
19017
+ function handoffControl(args) {
19018
+ if (!args.enabled) {
19019
+ return void 0;
19020
+ }
19021
+ const profileNames = [
19022
+ botConfig.defaultProfile,
19023
+ ...Object.keys(botConfig.profiles).filter((profile) => profile !== botConfig.defaultProfile).sort()
19024
+ ].filter((profile) => profile !== args.activeProfile);
19025
+ const [firstProfileName, ...otherProfileNames] = profileNames;
19026
+ if (!firstProfileName) {
19027
+ return void 0;
19028
+ }
19029
+ const toHandoffProfile = (name) => ({
19030
+ name,
19031
+ description: profileConfig(botConfig, name).description
19032
+ });
19033
+ return {
19034
+ profiles: [
19035
+ toHandoffProfile(firstProfileName),
19036
+ ...otherProfileNames.map(toHandoffProfile)
19037
+ ],
19038
+ execute: args.execute
19039
+ };
19040
+ }
19041
+ function toolsForHandoffProfile(args) {
19042
+ const control = handoffControl({
19043
+ activeProfile: args.activeProfile,
19044
+ enabled: args.enabled,
19045
+ execute: args.execute
19046
+ });
19047
+ if (!control) {
19048
+ return args.agentTools.filter((tool) => tool.name !== HANDOFF_TOOL_NAME);
19049
+ }
19050
+ const handoffAgentTool = args.agentTools.find(
19051
+ (tool) => tool.name === HANDOFF_TOOL_NAME
19052
+ );
19053
+ if (!handoffAgentTool) {
19054
+ throw new Error("Handoff control is missing its Pi tool");
19055
+ }
19056
+ const definition = createHandoffTool(control);
19057
+ return args.agentTools.map(
19058
+ (tool) => tool.name === HANDOFF_TOOL_NAME ? {
19059
+ ...handoffAgentTool,
19060
+ description: definition.description,
19061
+ parameters: definition.inputSchema,
19062
+ prepareArguments: definition.prepareArguments
19063
+ } : tool
19064
+ );
19065
+ }
19066
+ async function commitHandoff(args) {
19067
+ if (args.profile === args.activeModelProfile) {
19068
+ return void 0;
19069
+ }
19070
+ const runtimeContext = retainRuntimeTurnContext(
19071
+ args.runtimeContextSourceMessages ?? args.sourceMessages
19072
+ );
19073
+ const phaseUsageSummary = extractGenAiUsageSummary(
19074
+ ...args.sourceMessages.slice(args.beforeMessageCount).filter(isAssistantMessage)
19075
+ );
19076
+ const phaseUsage = hasAgentTurnUsage(phaseUsageSummary) ? phaseUsageSummary : void 0;
19077
+ const selectedProfile = profileConfig(botConfig, args.profile);
19078
+ const handoffReasoningLevel = selectedProfile.reasoningLevel ?? args.turnRoute.reasoningLevel;
19079
+ const target = {
19080
+ modelId: selectedProfile.modelId,
19081
+ modelProfile: args.profile,
19082
+ reasoningLevel: handoffReasoningLevel
19083
+ };
19084
+ void (async () => {
19085
+ await args.onStatus?.({ text: "Switching models" });
19086
+ })().catch((error) => {
19087
+ logWarn("assistant.status.observer.failed", {
19088
+ "exception.message": error instanceof Error ? error.message : String(error)
19089
+ });
19090
+ });
19091
+ const handoffMessages = await compactContextForHandoff(
19092
+ {
19093
+ conversationContext: args.conversationContext,
19094
+ conversationId: args.conversationId,
19095
+ piMessages: args.sourceMessages,
19096
+ runtimeContext,
19097
+ signal: args.signal,
19098
+ triggeringToolCallId: args.triggeringToolCallId,
19099
+ target,
19100
+ metadata: args.metadata
19101
+ },
19102
+ {
19103
+ completeText: (completeArgs) => completeText(completeArgs)
19104
+ }
19105
+ );
19106
+ const turnRoute = handoffReasoningLevel === args.turnRoute.reasoningLevel ? args.turnRoute : {
19107
+ ...args.turnRoute,
19108
+ reasoningLevel: handoffReasoningLevel,
19109
+ reason: `profile_reasoning_override:${args.profile}:${args.turnRoute.reason}`
19110
+ };
19111
+ return {
19112
+ messages: handoffMessages,
19113
+ model: resolveGatewayModel(target.modelId),
19114
+ modelId: target.modelId,
19115
+ modelProfile: args.profile,
19116
+ phaseUsage,
19117
+ thinkingLevel: toPiReasoningLevel(handoffReasoningLevel),
19118
+ turnRoute
19119
+ };
19120
+ }
19121
+ function applyHandoff(args) {
19122
+ const replacement = [...args.pending.messages];
19123
+ args.agent.state.messages = replacement;
19124
+ args.agent.state.model = args.pending.model;
19125
+ args.agent.state.thinkingLevel = args.pending.thinkingLevel;
19126
+ args.agent.state.tools = args.tools;
19127
+ args.resume.setBeforeMessageCount(replacement.length);
19128
+ args.resume.setTurnStartMessageIndex(0);
19129
+ args.resume.adoptCommittedBoundary(replacement);
19130
+ setSpanAttributes({
19131
+ "gen_ai.agent.model": args.pending.modelId,
19132
+ "gen_ai.agent.model_profile": args.pending.modelProfile,
19133
+ "gen_ai.agent.reasoning.level": args.pending.turnRoute.reasoningLevel
19134
+ });
19135
+ return {
19136
+ context: {
19137
+ systemPrompt: args.baseInstructions,
19138
+ messages: replacement,
19139
+ tools: args.tools
19140
+ },
19141
+ model: args.pending.model,
19142
+ thinkingLevel: args.pending.thinkingLevel
19143
+ };
19144
+ }
19145
+
18604
19146
  // src/chat/agent/index.ts
18605
19147
  var AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
18606
19148
  async function readRunConversationVisibility(conversationId) {
@@ -18996,93 +19538,56 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
18996
19538
  activeModelProfile = routedModelProfile;
18997
19539
  activeModelId = routedModelId;
18998
19540
  let pendingPiHookError;
18999
- let pendingHandoff;
19000
19541
  const currentAgentMessages = () => agent ? [...agent.state.messages] : [];
19001
- const handoffProfiles = [
19002
- botConfig.defaultProfile,
19003
- ...Object.keys(botConfig.profiles).filter((profile) => profile !== botConfig.defaultProfile).sort()
19004
- ];
19005
19542
  const usageSinceCurrentBoundary = (messages) => {
19006
19543
  const usage = extractGenAiUsageSummary(
19007
19544
  ...messages.slice(runResume.beforeMessageCount).filter(isAssistantMessage)
19008
19545
  );
19009
19546
  return hasAgentTurnUsage(usage) ? usage : void 0;
19010
19547
  };
19548
+ let baseInstructions = "";
19549
+ let pendingHandoff;
19550
+ const handoffMetadata = {
19551
+ threadId: conversationId,
19552
+ channelId: slackChannelId,
19553
+ actorId: slackActor?.userId,
19554
+ runId
19555
+ };
19011
19556
  const scheduleHandoff = async (args) => {
19012
- if (args.profile === activeModelProfile) {
19013
- return;
19014
- }
19015
- const runtimeContext = retainRuntimeTurnContext(
19016
- args.runtimeContextSourceMessages ?? args.sourceMessages
19017
- );
19018
- const phaseUsage = usageSinceCurrentBoundary(args.sourceMessages);
19019
- const selectedProfile = profileConfig(botConfig, args.profile);
19020
- const handoffReasoningLevel = selectedProfile.reasoningLevel ?? turnRoute.reasoningLevel;
19021
- const target = {
19022
- modelId: selectedProfile.modelId,
19023
- modelProfile: args.profile,
19024
- reasoningLevel: handoffReasoningLevel
19025
- };
19026
- const handoffModel = resolveGatewayModel(target.modelId);
19027
- const handoffThinkingLevel = toPiReasoningLevel(handoffReasoningLevel);
19028
- void (async () => {
19029
- await observers.onStatus?.({ text: "Switching models" });
19030
- })().catch((error) => {
19031
- logWarn("assistant.status.observer.failed", {
19032
- "exception.message": error instanceof Error ? error.message : String(error)
19033
- });
19557
+ const pending = await commitHandoff({
19558
+ activeModelProfile,
19559
+ beforeMessageCount: runResume.beforeMessageCount,
19560
+ conversationContext: input.conversationContext,
19561
+ conversationId,
19562
+ metadata: handoffMetadata,
19563
+ onStatus: observers.onStatus,
19564
+ profile: args.profile,
19565
+ runtimeContextSourceMessages: args.runtimeContextSourceMessages,
19566
+ signal: args.signal,
19567
+ sourceMessages: args.sourceMessages,
19568
+ triggeringToolCallId: args.triggeringToolCallId,
19569
+ turnRoute
19034
19570
  });
19035
- const handoffMessages = await compactContextForHandoff(
19036
- {
19037
- conversationContext: input.conversationContext,
19038
- conversationId,
19039
- piMessages: args.sourceMessages,
19040
- runtimeContext,
19041
- signal: args.signal,
19042
- triggeringToolCallId: args.triggeringToolCallId,
19043
- target,
19044
- metadata: {
19045
- threadId: conversationId,
19046
- channelId: slackChannelId,
19047
- actorId: slackActor?.userId,
19048
- runId
19049
- }
19050
- },
19051
- {
19052
- completeText: (args2) => completeText(args2)
19053
- }
19054
- );
19055
- if (handoffReasoningLevel !== turnRoute.reasoningLevel) {
19056
- turnRoute = {
19057
- ...turnRoute,
19058
- reasoningLevel: handoffReasoningLevel,
19059
- reason: `profile_reasoning_override:${args.profile}:${turnRoute.reason}`
19060
- };
19571
+ if (!pending) {
19572
+ return;
19061
19573
  }
19062
- priorPhaseUsage = addAgentTurnUsage(priorPhaseUsage, phaseUsage);
19063
- pendingHandoff = {
19064
- messages: handoffMessages,
19065
- model: handoffModel,
19066
- thinkingLevel: handoffThinkingLevel
19067
- };
19068
- activeModelProfile = args.profile;
19069
- activeModelId = target.modelId;
19070
- };
19071
- const handoffControlFor = (activeProfile) => {
19072
- const profiles = handoffProfiles.filter(
19073
- (profile) => profile !== activeProfile
19074
- );
19075
- return profiles.length > 0 ? {
19076
- profiles,
19077
- execute: async (profile, options) => await scheduleHandoff({
19078
- profile,
19079
- signal: options.signal,
19080
- sourceMessages: [...agent.state.messages],
19081
- triggeringToolCallId: options.toolCallId
19082
- })
19083
- } : void 0;
19574
+ priorPhaseUsage = addAgentTurnUsage(priorPhaseUsage, pending.phaseUsage);
19575
+ pendingHandoff = pending;
19576
+ activeModelProfile = pending.modelProfile;
19577
+ activeModelId = pending.modelId;
19578
+ turnRoute = pending.turnRoute;
19084
19579
  };
19085
- const requestHandoff = handoffEnabled ? handoffControlFor(activeModelProfile) : void 0;
19580
+ const handoffExecute = async (profile, options) => await scheduleHandoff({
19581
+ profile,
19582
+ signal: options.signal,
19583
+ sourceMessages: [...agent.state.messages],
19584
+ triggeringToolCallId: options.toolCallId
19585
+ });
19586
+ const requestHandoff = handoffControl({
19587
+ activeProfile: activeModelProfile,
19588
+ enabled: handoffEnabled,
19589
+ execute: handoffExecute
19590
+ });
19086
19591
  setTags({
19087
19592
  ...runLogContext,
19088
19593
  modelId: activeModelId
@@ -19143,32 +19648,27 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
19143
19648
  await recordAgentsTransition(initialRepositoryInstructions);
19144
19649
  }
19145
19650
  const getPendingAuthPause = wiring.getPendingAuthPause;
19146
- const toolsWithoutHandoff = wiring.agentTools.filter(
19147
- (tool) => tool.name !== HANDOFF_TOOL_NAME
19148
- );
19149
- const handoffAgentTool = wiring.agentTools.find(
19150
- (tool) => tool.name === HANDOFF_TOOL_NAME
19151
- );
19152
- const toolsForActiveProfile = () => {
19153
- const handoff = handoffEnabled ? handoffControlFor(activeModelProfile) : void 0;
19154
- if (!handoff) {
19155
- return toolsWithoutHandoff;
19156
- }
19157
- if (!handoffAgentTool) {
19158
- throw new Error("Handoff control is missing its Pi tool");
19159
- }
19160
- const definition = createHandoffTool(handoff);
19161
- return wiring.agentTools.map(
19162
- (tool) => tool.name === HANDOFF_TOOL_NAME ? {
19163
- ...handoffAgentTool,
19164
- description: definition.description,
19165
- parameters: definition.inputSchema,
19166
- prepareArguments: definition.prepareArguments
19167
- } : tool
19168
- );
19651
+ const applyPendingHandoff = () => {
19652
+ if (!pendingHandoff) {
19653
+ return void 0;
19654
+ }
19655
+ const pending = pendingHandoff;
19656
+ pendingHandoff = void 0;
19657
+ return applyHandoff({
19658
+ agent,
19659
+ baseInstructions,
19660
+ pending,
19661
+ resume: runResume,
19662
+ tools: toolsForHandoffProfile({
19663
+ activeProfile: pending.modelProfile,
19664
+ agentTools: wiring.agentTools,
19665
+ enabled: handoffEnabled,
19666
+ execute: handoffExecute
19667
+ })
19668
+ });
19169
19669
  };
19170
19670
  const {
19171
- baseInstructions,
19671
+ baseInstructions: assembledBaseInstructions,
19172
19672
  contextContentParts: promptContextContentParts,
19173
19673
  inputMessages,
19174
19674
  inputMessagesAttribute,
@@ -19204,6 +19704,7 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
19204
19704
  toolRuntimeContext: wiring.toolRuntimeContext,
19205
19705
  userContentParts
19206
19706
  });
19707
+ baseInstructions = assembledBaseInstructions;
19207
19708
  const repositoryInstructionsContext = createRepositoryInstructionsContext({
19208
19709
  capture: wiring.captureRepositoryInstructions,
19209
19710
  hasSandbox: () => Boolean(wiring.getSandboxRef()),
@@ -19218,36 +19719,6 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
19218
19719
  shouldPromptAgent
19219
19720
  });
19220
19721
  runResume.setTurnContexts(turnContexts);
19221
- const applyPendingHandoff = () => {
19222
- if (!pendingHandoff) {
19223
- return void 0;
19224
- }
19225
- const { messages, model, thinkingLevel } = pendingHandoff;
19226
- const replacement = [...messages];
19227
- pendingHandoff = void 0;
19228
- agent.state.messages = replacement;
19229
- agent.state.model = model;
19230
- agent.state.thinkingLevel = thinkingLevel;
19231
- const tools = toolsForActiveProfile();
19232
- agent.state.tools = tools;
19233
- runResume.setBeforeMessageCount(replacement.length);
19234
- runResume.setTurnStartMessageIndex(0);
19235
- runResume.adoptCommittedBoundary(replacement);
19236
- setSpanAttributes({
19237
- "gen_ai.agent.model": activeModelId,
19238
- "gen_ai.agent.model_profile": activeModelProfile,
19239
- "gen_ai.agent.reasoning.level": turnRoute.reasoningLevel
19240
- });
19241
- return {
19242
- context: {
19243
- systemPrompt: baseInstructions,
19244
- messages: replacement,
19245
- tools
19246
- },
19247
- model,
19248
- thinkingLevel
19249
- };
19250
- };
19251
19722
  const applyActiveContextCompaction = async (messages, hookSignal, pendingMessages, clearSteeringQueueOnCommit = false, pairPendingRuntimeContext = false) => {
19252
19723
  const compaction = await compactActiveContextIfNeeded(
19253
19724
  {
@@ -19378,13 +19849,7 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
19378
19849
  const toolCalls2 = assistantMessage.content.filter(
19379
19850
  (part) => part.type === "toolCall"
19380
19851
  );
19381
- const containsHandoff = toolCalls2.some(
19382
- (call) => call.name === HANDOFF_TOOL_NAME
19383
- );
19384
- const containsWorkspaceSwitch = toolCalls2.some(
19385
- (call) => call.name === "switchWorkspace"
19386
- );
19387
- const exclusiveTool = containsHandoff ? HANDOFF_TOOL_NAME : containsWorkspaceSwitch ? "switchWorkspace" : void 0;
19852
+ const exclusiveTool = exclusiveToolName(toolCalls2);
19388
19853
  if (exclusiveTool && toolCalls2.length !== 1) {
19389
19854
  return {
19390
19855
  block: true,
@@ -19461,10 +19926,9 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
19461
19926
  if (event.message.stopReason === "error" || event.message.stopReason === "aborted") {
19462
19927
  return;
19463
19928
  }
19464
- const containsHandoff = event.message.content.some(
19929
+ if (event.message.content.some(
19465
19930
  (part) => part.type === "toolCall" && part.name === HANDOFF_TOOL_NAME
19466
- );
19467
- if (containsHandoff) {
19931
+ )) {
19468
19932
  return;
19469
19933
  }
19470
19934
  return deliverAssistantMessage(event.message);
@@ -19614,9 +20078,9 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
19614
20078
  }
19615
20079
  return result2;
19616
20080
  };
19617
- const requestedProfile = activeModelProfile === botConfig.defaultProfile ? turnRoute.profile : void 0;
19618
20081
  let run2;
19619
20082
  let handoffApplied = false;
20083
+ const requestedProfile = activeModelProfile === botConfig.defaultProfile ? turnRoute.profile : void 0;
19620
20084
  if (requestedProfile && requestedProfile !== botConfig.defaultProfile) {
19621
20085
  const handoffAbortController = new AbortController();
19622
20086
  await runAgentStep(
@@ -19910,6 +20374,10 @@ export {
19910
20374
  normalizeSandboxEgressTracePropagationDomains,
19911
20375
  shouldPropagateSandboxEgressTrace,
19912
20376
  resolveSandboxEgressProviderForHost,
20377
+ admitAutomatedTurn,
20378
+ recordFinishedTurnForAutomatedLimit,
20379
+ postAutomatedTurnLimitNoticeForDestination,
20380
+ maybePostAutomatedTurnLimitNotice,
19913
20381
  renderTaskInput,
19914
20382
  RESOURCE_EVENT_MESSAGE_AUTHOR,
19915
20383
  RESOURCE_EVENT_SYSTEM_ACTOR,