@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
package/dist/app.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Hono } from "hono";
2
+ import type { ModelProfileInput } from "@/chat/model-profile";
2
3
  import { type ExperimentalFeaturesConfig } from "@/chat/experimental";
3
4
  import { type SandboxResourceConfig } from "@/chat/sandbox/resources";
4
5
  import { type JuniorPluginSet } from "./plugins";
@@ -8,6 +9,7 @@ import { JUNIOR_VERSION } from "./version";
8
9
  export { defineJuniorPlugins } from "./plugins";
9
10
  export { JUNIOR_VERSION };
10
11
  export type { JuniorPluginInput, JuniorPluginSet, JuniorPluginSetOptions, } from "./plugins";
12
+ export type { ModelProfileInput } from "@/chat/model-profile";
11
13
  export interface JuniorAppOptions {
12
14
  /** Authenticated dashboard mounted by core when configured. */
13
15
  dashboard?: JuniorDashboardOptions;
@@ -19,8 +21,12 @@ export interface JuniorAppOptions {
19
21
  experimental?: ExperimentalFeaturesConfig;
20
22
  /** Profile used for new conversations. Configure with `profiles`. */
21
23
  defaultProfile?: string;
22
- /** Named profiles available to the router and handoff tool. Configure with `defaultProfile`. */
23
- profiles?: Readonly<Record<string, string>>;
24
+ /**
25
+ * Named profiles available to the router and `handoff` tool. Configure with
26
+ * `defaultProfile`. Each value may be a model id string or an object with
27
+ * `modelId` and optional `description` and `reasoningLevel` settings.
28
+ */
29
+ profiles?: Readonly<Record<string, ModelProfileInput>>;
24
30
  /** Slack-specific overrides applied after env parsing. */
25
31
  slack?: {
26
32
  /** Slack emoji shown while Junior is processing. Defaults to `eyes`. */
package/dist/app.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  processConversationWork
3
- } from "./chunk-73JEAQRT.js";
3
+ } from "./chunk-LCAM2P7H.js";
4
4
  import {
5
5
  bindSpawnAgent
6
- } from "./chunk-XRDSML3K.js";
6
+ } from "./chunk-P3LE2CSJ.js";
7
7
  import {
8
8
  createAgentInvocationWorker,
9
9
  enqueueAgentInvocation,
10
10
  listPendingAgentInvocationMailboxAppends,
11
11
  resolveAgentInvocationId
12
- } from "./chunk-F2KSURTJ.js";
12
+ } from "./chunk-VKLQ2M7V.js";
13
13
  import {
14
14
  GET as GET2,
15
15
  GET2 as GET3,
@@ -37,12 +37,12 @@ import {
37
37
  startProcessingReaction,
38
38
  stripLeadingBotMention,
39
39
  wakePausedTurn
40
- } from "./chunk-INTBMGNX.js";
40
+ } from "./chunk-EEUFKVCD.js";
41
41
  import "./chunk-FA6POGLH.js";
42
42
  import {
43
43
  AgentRunError,
44
44
  executeTurn
45
- } from "./chunk-53IEEFFP.js";
45
+ } from "./chunk-KJGH3KWA.js";
46
46
  import {
47
47
  buildDeliveredTurnStatePatch,
48
48
  completeAuthPauseTurn,
@@ -53,7 +53,7 @@ import {
53
53
  getTurnUserSlackMessageTs,
54
54
  persistAuthPauseTurnState,
55
55
  requireTurnFailureEventId
56
- } from "./chunk-2NL3Y47F.js";
56
+ } from "./chunk-J357NJQ5.js";
57
57
  import {
58
58
  claimDispatchMailboxAppend,
59
59
  confirmDispatchMailboxAppend,
@@ -73,11 +73,11 @@ import {
73
73
  processPluginTask,
74
74
  resolveTurnSessionRouting,
75
75
  scheduleSessionCompletedPluginTasks
76
- } from "./chunk-NPO24LAN.js";
76
+ } from "./chunk-VVU7GHIZ.js";
77
77
  import {
78
78
  ConversationTurnLifecycleService,
79
79
  getTurnLifecycle
80
- } from "./chunk-6H2MKVV5.js";
80
+ } from "./chunk-VSOO3Y6M.js";
81
81
  import {
82
82
  coerceThreadConversationState,
83
83
  getLocationConfigurationService,
@@ -86,7 +86,7 @@ import {
86
86
  persistThreadRuntimeState,
87
87
  persistThreadState,
88
88
  persistThreadStateById
89
- } from "./chunk-GY5SEFVL.js";
89
+ } from "./chunk-QAINJHI4.js";
90
90
  import {
91
91
  GET,
92
92
  appendAndEnqueueWebMessage,
@@ -101,24 +101,24 @@ import {
101
101
  resolveSlackChannelTypeFromMessage,
102
102
  resolveSlackConversationContext,
103
103
  webActorFromEmail
104
- } from "./chunk-H4DCWLTR.js";
104
+ } from "./chunk-EFNUCRB5.js";
105
105
  import {
106
106
  createWebAuthorization,
107
107
  deleteWebAuthorization
108
- } from "./chunk-XND3J6AT.js";
108
+ } from "./chunk-RAWYH7TW.js";
109
109
  import {
110
110
  recordTaskExecution
111
- } from "./chunk-VOB2DKO6.js";
111
+ } from "./chunk-LGXI6PWX.js";
112
112
  import "./chunk-RC745GGZ.js";
113
113
  import {
114
114
  createVercelPluginTaskCallback,
115
115
  queueCallback,
116
116
  registerVercelPluginTaskDevConsumer
117
- } from "./chunk-CFGBKPWQ.js";
117
+ } from "./chunk-7TUDDW3Y.js";
118
118
  import {
119
119
  validatePluginEgressCredentialHooks,
120
120
  validatePluginRegistrations
121
- } from "./chunk-KNIAWMBU.js";
121
+ } from "./chunk-PI6VXVBK.js";
122
122
  import {
123
123
  defineJuniorPlugins,
124
124
  pluginCatalogConfigFromEnv,
@@ -129,6 +129,7 @@ import {
129
129
  RESOURCE_EVENT_MESSAGE_AUTHOR,
130
130
  RESOURCE_EVENT_SYSTEM_ACTOR,
131
131
  SANDBOX_EGRESS_PROXY_PATH,
132
+ admitAutomatedTurn,
132
133
  buildSteeringPiMessage,
133
134
  clearSandboxEgressSignals,
134
135
  consumeSandboxEgressAuthRequiredSignal,
@@ -144,11 +145,14 @@ import {
144
145
  latestReportedProgress,
145
146
  listThreadReplies,
146
147
  logScheduledTaskRunSkipped,
148
+ maybePostAutomatedTurnLimitNotice,
147
149
  normalizeSandboxEgressTracePropagationDomains,
148
150
  parseSandboxEgressCredentialToken,
151
+ postAutomatedTurnLimitNoticeForDestination,
149
152
  processWorkspaceSnapshotJob,
150
153
  publicArtifactHeaders,
151
154
  readPublicArtifact,
155
+ recordFinishedTurnForAutomatedLimit,
152
156
  renderAttachmentText,
153
157
  renderBlockText,
154
158
  renderTaskInput,
@@ -158,11 +162,11 @@ import {
158
162
  shouldEmitDevAgentTrace,
159
163
  shouldPropagateSandboxEgressTrace,
160
164
  unpublishedArtifactHeaders
161
- } from "./chunk-G4RARFNT.js";
165
+ } from "./chunk-OVWAO5KY.js";
162
166
  import {
163
167
  AuthorizationFlowDisabledError,
164
168
  PluginCredentialFailureError
165
- } from "./chunk-QMEF4Z7R.js";
169
+ } from "./chunk-CNI74T7U.js";
166
170
  import "./chunk-6Y5B5PEX.js";
167
171
  import "./chunk-DIB4GX3G.js";
168
172
  import {
@@ -170,14 +174,14 @@ import {
170
174
  deleteMcpAuthSessionsForUserProvider,
171
175
  deleteMcpServerSessionId,
172
176
  deleteMcpStoredOAuthCredentials
173
- } from "./chunk-AWZS5SVX.js";
177
+ } from "./chunk-N2MSPOGG.js";
174
178
  import {
175
179
  RetryableDeliveryError,
176
180
  createAgentRunner,
177
181
  formatProviderLabel,
178
182
  postSlackMessage,
179
183
  startOAuthFlow
180
- } from "./chunk-ENWIHU54.js";
184
+ } from "./chunk-RFNMWONZ.js";
181
185
  import {
182
186
  ConversationTurnBoundaryError,
183
187
  CooperativeTurnYieldError,
@@ -193,7 +197,7 @@ import {
193
197
  markTurnCompleted,
194
198
  markTurnFailed,
195
199
  startActiveTurn
196
- } from "./chunk-G35QGPO2.js";
200
+ } from "./chunk-DFWJJOW3.js";
197
201
  import {
198
202
  abandonTurnRecord,
199
203
  appendThreadContextMessages,
@@ -230,7 +234,7 @@ import {
230
234
  trimTrailingAssistantMessages,
231
235
  turnHasReply,
232
236
  upsertConversationMessage
233
- } from "./chunk-OEQOAONV.js";
237
+ } from "./chunk-6LQNW2CJ.js";
234
238
  import {
235
239
  getExperimentalFeatures,
236
240
  isExperimentalFeatureEnabled,
@@ -250,10 +254,10 @@ import {
250
254
  scheduledRunId,
251
255
  scheduledRunSchema,
252
256
  withScheduledTaskLock
253
- } from "./chunk-WMJS5DDV.js";
257
+ } from "./chunk-GZ336GZ5.js";
254
258
  import {
255
259
  parseSlackThreadId
256
- } from "./chunk-IOGDKPVU.js";
260
+ } from "./chunk-VXAQTJSR.js";
257
261
  import {
258
262
  CONVERSATION_WORK_STALE_ENQUEUE_MS,
259
263
  appendAndEnqueueInboundMessage,
@@ -268,16 +272,16 @@ import {
268
272
  removeActiveConversation,
269
273
  requestConversationWork,
270
274
  stopConversationWork
271
- } from "./chunk-E53C73ML.js";
275
+ } from "./chunk-S74KAE77.js";
272
276
  import {
273
277
  buildDeterministicAssistantMessageId,
274
278
  buildDeterministicTurnId
275
279
  } from "./chunk-DA2KGZZI.js";
276
- import "./chunk-RFE7DCZK.js";
280
+ import "./chunk-B5WJBVHY.js";
277
281
  import {
278
282
  getSandboxResourceConfig,
279
283
  setSandboxResourceConfig
280
- } from "./chunk-ELCYG6UU.js";
284
+ } from "./chunk-KZX7LORG.js";
281
285
  import "./chunk-PDO5BLNM.js";
282
286
  import "./chunk-UIE3R5XU.js";
283
287
  import {
@@ -286,7 +290,7 @@ import {
286
290
  } from "./chunk-X6GDDWQH.js";
287
291
  import {
288
292
  getTurnRequestDeadline
289
- } from "./chunk-NWWDFHXP.js";
293
+ } from "./chunk-VRHZXY5X.js";
290
294
  import {
291
295
  getVercelConversationWorkQueue,
292
296
  resolveConversationWorkQueueTopic,
@@ -322,7 +326,7 @@ import {
322
326
  verifyEventTaskCredentialSubject,
323
327
  verifyScheduledTaskCredentialSubject,
324
328
  verifySlackDirectCredentialSubject
325
- } from "./chunk-CCTYK5RH.js";
329
+ } from "./chunk-NE2UQMC7.js";
326
330
  import "./chunk-3Y47VMHV.js";
327
331
  import {
328
332
  createSlackDestination,
@@ -334,7 +338,7 @@ import {
334
338
  requireSlackDestination,
335
339
  withConversationEventLock,
336
340
  withConversationMutationLock
337
- } from "./chunk-ADEACKAH.js";
341
+ } from "./chunk-XNXKRWWI.js";
338
342
  import {
339
343
  juniorAgentBindings,
340
344
  juniorAgentInvocations,
@@ -342,16 +346,16 @@ import {
342
346
  juniorConversations,
343
347
  juniorSchedulerRuns,
344
348
  juniorSchedulerTasks
345
- } from "./chunk-XLWZRHX5.js";
346
- import "./chunk-7ANA7PBB.js";
349
+ } from "./chunk-PIZJBSGZ.js";
350
+ import "./chunk-SR5FS2JP.js";
347
351
  import {
348
352
  acquireActiveLock,
349
353
  getStateAdapter,
350
354
  withActiveLock
351
- } from "./chunk-V4HXV5MY.js";
355
+ } from "./chunk-EQBHN4JK.js";
352
356
  import {
353
357
  instructionProvenanceFor
354
- } from "./chunk-GFBR4S3Q.js";
358
+ } from "./chunk-7NL7T6VU.js";
355
359
  import {
356
360
  juniorDestinations
357
361
  } from "./chunk-VFUK3X5B.js";
@@ -370,17 +374,17 @@ import {
370
374
  isProviderRetryError,
371
375
  setProfiles,
372
376
  setSlackReactionConfig
373
- } from "./chunk-U76RWMFR.js";
377
+ } from "./chunk-5XSEOJPC.js";
374
378
  import {
375
379
  defaultModelId,
376
380
  modelIdForProfile
377
- } from "./chunk-D4YV5TDV.js";
378
- import "./chunk-JOI3DHML.js";
379
- import "./chunk-P2P6MUQ4.js";
381
+ } from "./chunk-NHJU2ZAL.js";
382
+ import "./chunk-ES7KCEND.js";
383
+ import "./chunk-LSPUMNZK.js";
380
384
  import {
381
385
  pluginCatalogRuntime
382
- } from "./chunk-WWXJUURQ.js";
383
- import "./chunk-S7GX44BU.js";
386
+ } from "./chunk-G6YRPYDC.js";
387
+ import "./chunk-BXIVMNLR.js";
384
388
  import {
385
389
  credentialContextForActor
386
390
  } from "./chunk-CEMMLV5L.js";
@@ -416,13 +420,13 @@ import {
416
420
  withContext,
417
421
  withLogContext,
418
422
  withSpan
419
- } from "./chunk-X76JVHQ4.js";
423
+ } from "./chunk-CTS72G4B.js";
420
424
  import {
421
425
  continueTrace
422
426
  } from "./chunk-PEQXYSSE.js";
423
427
  import {
424
428
  JUNIOR_VERSION
425
- } from "./chunk-IME5OW4Y.js";
429
+ } from "./chunk-I7GEGEHZ.js";
426
430
 
427
431
  // src/app.ts
428
432
  import { createRequire } from "module";
@@ -4444,7 +4448,7 @@ Assess conversation floor ownership and whether the latest message continues wor
4444
4448
  - should_reply=false when the latest message is plainly human-to-human, even if it discusses the same project.
4445
4449
 
4446
4450
  # Unsubscribe Policy
4447
- - should_unsubscribe=true only when the latest message clearly tells ${assistantName} to stop watching, replying, participating, or to leave the thread.
4451
+ - should_unsubscribe=true when the latest message clearly tells ${assistantName} to stop or leave the thread.
4448
4452
  - If should_unsubscribe=true, should_reply must be false.
4449
4453
  - Ordinary disagreement, correction, or "not yet" is not an unsubscribe.
4450
4454
 
@@ -4472,14 +4476,9 @@ var RECENT_ASSISTANT_ENTRY_LIMIT = 40;
4472
4476
  var LEADING_SLACK_MENTION_RE = /^\s*<@([A-Z0-9]+)(?:\|([^>]+))?>[\s,:-]*/i;
4473
4477
  var LEADING_NAMED_MENTION_RE = /^\s*@([a-z0-9._-]+)\b[\s,:-]*/i;
4474
4478
  var TRANSCRIPT_MESSAGE_LINE_RE = /^\[(assistant|user)\]\s+([^:]+):\s+([\s\S]+)$/i;
4475
- var FORCED_THREAD_OPTOUT_RE = /^!stop(?:\s|$)/i;
4476
- var THREAD_OPTOUT_PATTERNS = [
4477
- /\bstop (?:watching|replying|participating)\b/i,
4478
- /\bstay out\b/i,
4479
- /\bdon['’]t (?:reply|participate|watch)\b/i,
4480
- /\bunsubscribe\b/i,
4481
- /\bleave (?:this )?thread\b/i
4482
- ];
4479
+ var BANG_STOP_RE = /(?:^|\s)!stop(?=\s|$|[.!?,;:])/i;
4480
+ var LEADING_ADDRESS_RE = /^(?:(?:<@[^>]+>|@[\w.-]+)\s*[,:\-–—]?\s*)+/i;
4481
+ var BARE_STOP_RE = /^stop(?:\s*[.!…]+)?$/i;
4483
4482
  var ACKNOWLEDGMENT_ONLY_RE = /^(?:thanks(?: you)?|thank you|thx|ty|got it|sounds good|sgtm|lgtm|ok(?:ay)?|cool|nice|perfect|awesome|great|makes sense|understood|roger|yep|yup|kk|on it|will do)(?:[.!]+)?$/i;
4484
4483
  var DIRECTED_FOLLOW_UP_CUE_RE = /\b(?:you said|you just said|your last response|your last answer|what did you just say|what do you mean|what did you mean|explain(?: that| this| it| more)?|clarify(?: that| this| it)?|expand(?: on)?(?: that| this| it)?|elaborate(?: on)?(?: that| this| it)?|say more)\b/i;
4485
4484
  var TERSE_CLARIFICATION_RE = /^(?:which one|which ones|why|how so|what do you mean|what did you mean|say more|explain that|clarify that|expand on that|elaborate on that)\??$/i;
@@ -4514,13 +4513,35 @@ function detectLeadingOtherPartyAddress(rawText, text, botUserName) {
4514
4513
  }
4515
4514
  return `named_mention:${directedName}`;
4516
4515
  }
4517
- function isForcedThreadOptOutCommand(rawText, text) {
4518
- return FORCED_THREAD_OPTOUT_RE.test(rawText.trim()) || FORCED_THREAD_OPTOUT_RE.test(text.trim());
4516
+ function hasBangStop(rawText, text) {
4517
+ return BANG_STOP_RE.test(rawText.trim()) || BANG_STOP_RE.test(text.trim());
4519
4518
  }
4520
- function isThreadOptOutInstruction(rawText, text) {
4521
- return THREAD_OPTOUT_PATTERNS.some(
4522
- (pattern) => pattern.test(rawText) || pattern.test(text)
4523
- );
4519
+ function isBareStop(rawText, text) {
4520
+ return [rawText, text].some((value) => {
4521
+ const candidate = value.trim().replace(LEADING_ADDRESS_RE, "").trim();
4522
+ return candidate.length > 0 && BARE_STOP_RE.test(candidate);
4523
+ });
4524
+ }
4525
+ function getThreadStopDecision(args) {
4526
+ const text = args.text.trim();
4527
+ const rawText = args.rawText.trim();
4528
+ if (hasBangStop(rawText, text)) {
4529
+ return {
4530
+ shouldReply: false,
4531
+ shouldUnsubscribe: true,
4532
+ reason: "thread_opt_out" /* ThreadOptOut */,
4533
+ reasonDetail: "!stop"
4534
+ };
4535
+ }
4536
+ if (isBareStop(rawText, text)) {
4537
+ return {
4538
+ shouldReply: false,
4539
+ shouldUnsubscribe: true,
4540
+ reason: "thread_opt_out" /* ThreadOptOut */,
4541
+ reasonDetail: "stop"
4542
+ };
4543
+ }
4544
+ return void 0;
4524
4545
  }
4525
4546
  function isAcknowledgmentOnly(text) {
4526
4547
  return ACKNOWLEDGMENT_ONLY_RE.test(text.trim());
@@ -4696,13 +4717,9 @@ function getSubscribedReplyPreflightDecision(args) {
4696
4717
  async function decideSubscribedThreadReply(args) {
4697
4718
  const text = args.input.text.trim();
4698
4719
  const rawText = args.input.rawText.trim();
4699
- if (isForcedThreadOptOutCommand(rawText, text)) {
4700
- return {
4701
- shouldReply: false,
4702
- shouldUnsubscribe: true,
4703
- reason: "thread_opt_out" /* ThreadOptOut */,
4704
- reasonDetail: "forced !stop command"
4705
- };
4720
+ const stopDecision = getThreadStopDecision({ rawText, text });
4721
+ if (stopDecision) {
4722
+ return stopDecision;
4706
4723
  }
4707
4724
  const preflightDecision = getSubscribedReplyPreflightDecision({
4708
4725
  botUserName: args.botUserName,
@@ -4717,14 +4734,6 @@ async function decideSubscribedThreadReply(args) {
4717
4734
  return { shouldReply: false, reason: "empty_message" /* EmptyMessage */ };
4718
4735
  }
4719
4736
  if (args.input.isExplicitMention) {
4720
- if (isThreadOptOutInstruction(rawText, text)) {
4721
- return {
4722
- shouldReply: false,
4723
- shouldUnsubscribe: true,
4724
- reason: "thread_opt_out" /* ThreadOptOut */,
4725
- reasonDetail: "explicit stop instruction"
4726
- };
4727
- }
4728
4737
  return {
4729
4738
  shouldReply: true,
4730
4739
  reason: "explicit_mention" /* ExplicitMention */
@@ -5402,6 +5411,33 @@ function createSlackTurnRuntime(deps) {
5402
5411
  });
5403
5412
  const combinedText = combineTurnText(queuedMessages, currentText);
5404
5413
  const turnIsExplicitMention = Boolean(message.isMention) || queuedMessages.some((queued) => queued.explicitMention);
5414
+ const stopDecision = [...queuedMessages, currentText].map(
5415
+ (entry) => getThreadStopDecision({
5416
+ rawText: entry.rawText,
5417
+ text: entry.userText
5418
+ })
5419
+ ).find((decision2) => decision2?.shouldUnsubscribe);
5420
+ if (stopDecision) {
5421
+ const decision2 = {
5422
+ shouldReply: false,
5423
+ shouldUnsubscribe: true,
5424
+ reason: stopDecision.reasonDetail ? `${stopDecision.reason}:${stopDecision.reasonDetail}` : stopDecision.reason
5425
+ };
5426
+ await maybeHandleThreadOptOutDecision({
5427
+ thread,
5428
+ decision: decision2,
5429
+ beforeFirstResponsePost: hooks.beforeFirstResponsePost
5430
+ });
5431
+ await skipSubscribedMessage({
5432
+ thread,
5433
+ message,
5434
+ decision: decision2,
5435
+ context: threadContext,
5436
+ ack: hooks.ack,
5437
+ text: combinedText
5438
+ });
5439
+ return;
5440
+ }
5405
5441
  const preflightDecision = getSubscribedReplyPreflightDecision({
5406
5442
  botUserName: deps.assistantUserName,
5407
5443
  rawText: combinedText.rawText,
@@ -7251,6 +7287,21 @@ function createSlackTurn(deps) {
7251
7287
  })
7252
7288
  );
7253
7289
  await persistThreadRuntimeStateWithRetry(thread, completedState);
7290
+ const automatedTurnLimit = await recordFinishedTurnForAutomatedLimit(
7291
+ {
7292
+ conversationId,
7293
+ destination,
7294
+ maxTurns: botConfig.maxConsecutiveAutomatedTurns,
7295
+ source
7296
+ }
7297
+ );
7298
+ await maybePostAutomatedTurnLimitNotice({
7299
+ conversationId,
7300
+ destination,
7301
+ maxTurns: botConfig.maxConsecutiveAutomatedTurns,
7302
+ threadTs,
7303
+ update: automatedTurnLimit
7304
+ });
7254
7305
  } catch (saveError) {
7255
7306
  saveFailed = true;
7256
7307
  saveFailureEventId = logException(
@@ -9141,6 +9192,19 @@ function createConversationTurnWorker(agentRunner, deliverMessage) {
9141
9192
  surface
9142
9193
  });
9143
9194
  }
9195
+ const automatedTurnLimit = await recordFinishedTurnForAutomatedLimit({
9196
+ conversationId: context.conversationId,
9197
+ destination,
9198
+ maxTurns: botConfig.maxConsecutiveAutomatedTurns,
9199
+ source
9200
+ });
9201
+ await maybePostAutomatedTurnLimitNotice({
9202
+ conversationId: context.conversationId,
9203
+ destination,
9204
+ maxTurns: botConfig.maxConsecutiveAutomatedTurns,
9205
+ threadTs: conversationLocation?.provider === "slack" ? conversationLocation.threadTs : void 0,
9206
+ update: automatedTurnLimit
9207
+ });
9144
9208
  completedSuccessfully = reply.diagnostics.outcome === "success";
9145
9209
  return completedSuccessfully ? {
9146
9210
  outcome: assistantMessageDelivered ? "success" : "no_reply"
@@ -9523,8 +9587,40 @@ async function ingestEventTasks(input, options) {
9523
9587
  const tasks = await findMatchingEventTasks(db, event, options.teamId);
9524
9588
  let dispatched = 0;
9525
9589
  const errors = [];
9590
+ const maxTurns = botConfig.maxConsecutiveAutomatedTurns;
9591
+ const noticedDestinations = /* @__PURE__ */ new Set();
9526
9592
  for (const task of tasks) {
9527
9593
  try {
9594
+ const decision = await admitAutomatedTurn({
9595
+ maxTurns,
9596
+ nowMs,
9597
+ scope: { kind: "destination", destination: task.destination }
9598
+ });
9599
+ if (decision.status === "paused") {
9600
+ const destinationId = `${task.destination.teamId}:${task.destination.channelId}`;
9601
+ logInfo("event_tasks.automated_turn_limit.paused", {
9602
+ "app.automated_turn_limit.consecutive": decision.consecutiveAutomatedTurns,
9603
+ "app.automated_turn_limit.max": maxTurns,
9604
+ "app.event_task.id": task.id,
9605
+ "app.resource_event.event_type": event.eventType,
9606
+ "app.resource_event.namespace": event.namespace,
9607
+ "app.slack.channel_id": task.destination.channelId,
9608
+ "app.slack.team_id": task.destination.teamId
9609
+ });
9610
+ if (decision.shouldPostNotice && !noticedDestinations.has(destinationId)) {
9611
+ const posted = await postAutomatedTurnLimitNoticeForDestination({
9612
+ destination: task.destination,
9613
+ maxTurns,
9614
+ nowMs,
9615
+ resumeIn: "channel",
9616
+ scope: { kind: "destination", destination: task.destination }
9617
+ });
9618
+ if (posted) {
9619
+ noticedDestinations.add(destinationId);
9620
+ }
9621
+ }
9622
+ continue;
9623
+ }
9528
9624
  const idempotencyKey = eventTaskDispatchKey(
9529
9625
  task.id,
9530
9626
  event.namespace,
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-WWXJUURQ.js";
4
- import "./chunk-S7GX44BU.js";
3
+ } from "./chunk-G6YRPYDC.js";
4
+ import "./chunk-BXIVMNLR.js";
5
5
  import "./chunk-CEMMLV5L.js";
6
6
  import "./chunk-N7TMSOZH.js";
7
7
  import "./chunk-DWPN6SCH.js";
8
8
  import "./chunk-TXKUKMVO.js";
9
- import "./chunk-X76JVHQ4.js";
9
+ import "./chunk-CTS72G4B.js";
10
10
  import "./chunk-PEQXYSSE.js";
11
- import "./chunk-IME5OW4Y.js";
11
+ import "./chunk-I7GEGEHZ.js";
12
12
  export {
13
13
  pluginCatalogRuntime
14
14
  };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Model-profile handoff helpers for one agent run slice.
3
+ *
4
+ * Owns the durable handoff commit, Pi apply shape, tool control, and the few
5
+ * loop checks that only care about handoff tool calls.
6
+ */
7
+ import { type Agent, type AgentLoopTurnUpdate, type AgentTool } from "@earendil-works/pi-agent-core";
8
+ import type { ResumeState } from "@/chat/agent/resume";
9
+ import { type ModelProfile } from "@/chat/model-profile";
10
+ import { resolveGatewayModel } from "@/chat/pi/client";
11
+ import type { PiMessage } from "@/chat/pi/messages";
12
+ import { type CompactContextArgs } from "@/chat/services/context-compaction";
13
+ import { type TurnRoute } from "@/chat/services/turn-router";
14
+ import type { ToolRuntimeContext } from "@/chat/tools/types";
15
+ import { type AgentTurnUsage } from "@/chat/usage";
16
+ /** Staged handoff waiting for the next Pi turn boundary. */
17
+ export type PendingHandoff = {
18
+ messages: PiMessage[];
19
+ model: ReturnType<typeof resolveGatewayModel>;
20
+ modelId: string;
21
+ modelProfile: ModelProfile;
22
+ phaseUsage?: AgentTurnUsage;
23
+ thinkingLevel: NonNullable<AgentLoopTurnUpdate["thinkingLevel"]>;
24
+ turnRoute: TurnRoute;
25
+ };
26
+ /** Return the exclusive tool name when one is present among the calls. */
27
+ export declare function exclusiveToolName(toolCalls: ReadonlyArray<{
28
+ name: string;
29
+ }>): string | undefined;
30
+ /** Build the tool control for every configured profile except the active one. */
31
+ export declare function handoffControl(args: {
32
+ activeProfile: ModelProfile;
33
+ enabled: boolean;
34
+ execute: NonNullable<ToolRuntimeContext["handoff"]>["execute"];
35
+ }): ToolRuntimeContext["handoff"];
36
+ /**
37
+ * Rebind the handoff tool description and schema for the active profile.
38
+ * Other tools stay as wired.
39
+ */
40
+ export declare function toolsForHandoffProfile(args: {
41
+ activeProfile: ModelProfile;
42
+ agentTools: AgentTool[];
43
+ enabled: boolean;
44
+ execute: NonNullable<ToolRuntimeContext["handoff"]>["execute"];
45
+ }): AgentTool[];
46
+ /**
47
+ * Commit the durable handoff epoch and return the staged Pi swap.
48
+ * No-op when the requested profile is already active.
49
+ */
50
+ export declare function commitHandoff(args: {
51
+ activeModelProfile: ModelProfile;
52
+ beforeMessageCount: number;
53
+ conversationContext?: string;
54
+ conversationId: string;
55
+ metadata?: CompactContextArgs["metadata"];
56
+ onStatus?: (status: {
57
+ text: string;
58
+ }) => void | Promise<void>;
59
+ profile: ModelProfile;
60
+ runtimeContextSourceMessages?: PiMessage[];
61
+ signal?: AbortSignal;
62
+ sourceMessages: PiMessage[];
63
+ triggeringToolCallId?: string;
64
+ turnRoute: TurnRoute;
65
+ }): Promise<PendingHandoff | undefined>;
66
+ /** Apply a committed handoff to Pi and reset its durable resume baseline. */
67
+ export declare function applyHandoff(args: {
68
+ agent: Agent;
69
+ baseInstructions: string;
70
+ pending: PendingHandoff;
71
+ resume: ResumeState;
72
+ tools: AgentTool[];
73
+ }): AgentLoopTurnUpdate;
@@ -1,5 +1,5 @@
1
1
  import { type TurnReasoningLevel } from "@/chat/reasoning-level";
2
- import { type ModelProfileConfig, type ModelProfile } from "@/chat/model-profile";
2
+ import { type ModelProfileConfig, type ModelProfile, type ModelProfileInput } from "@/chat/model-profile";
3
3
  export declare const DEFAULT_SQL_STATEMENT_TIMEOUT_MS = 30000;
4
4
  /**
5
5
  * Buffer between the Vercel function timeout and the agent turn timeout so
@@ -22,6 +22,7 @@ export interface BotConfig {
22
22
  visionModelId?: string;
23
23
  maxSlicesPerTurn: number;
24
24
  maxToolCallsPerTurn: number;
25
+ maxConsecutiveAutomatedTurns: number;
25
26
  turnTimeoutMs: number;
26
27
  userName: string;
27
28
  webSearchModelId: string;
@@ -76,7 +77,7 @@ export interface SlackReactionConfig {
76
77
  processingReactionEmoji: string;
77
78
  }
78
79
  /** Apply profiles from createApp(). */
79
- export declare function setProfiles(profiles: Readonly<Record<string, string>> | undefined, defaultProfile: string | undefined): void;
80
+ export declare function setProfiles(profiles: Readonly<Record<string, ModelProfileInput>> | undefined, defaultProfile: string | undefined): void;
80
81
  /** Return the current Slack reaction emoji config. */
81
82
  export declare function getSlackReactionConfig(): SlackReactionConfig;
82
83
  /** Apply Slack reaction emoji overrides from createApp() options, validating names. */