@sentry/junior 0.188.0 → 0.189.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 (109) hide show
  1. package/dist/{agent-hooks-5RQEVLQD.js → agent-hooks-6QRYH6PX.js} +11 -11
  2. package/dist/api/acp/conversations.d.ts +2 -2
  3. package/dist/api/conversations/list.d.ts +7 -0
  4. package/dist/api/people/shared.d.ts +54 -0
  5. package/dist/api.js +41 -52
  6. package/dist/app.d.ts +1 -1
  7. package/dist/app.js +1003 -346
  8. package/dist/{catalog-runtime-L4A6BJ3U.js → catalog-runtime-IETJLJFG.js} +4 -4
  9. package/dist/chat/agent/resume.d.ts +0 -2
  10. package/dist/chat/agent/types.d.ts +8 -9
  11. package/dist/chat/agent-dispatch/work.d.ts +1 -10
  12. package/dist/chat/agent-invocations/spawn.d.ts +1 -1
  13. package/dist/chat/agent-invocations/types.d.ts +296 -96
  14. package/dist/chat/app/conversation-work.d.ts +16 -8
  15. package/dist/chat/conversation-privacy.d.ts +7 -7
  16. package/dist/chat/conversations/destination.d.ts +12 -0
  17. package/dist/chat/conversations/projection.d.ts +2 -2
  18. package/dist/chat/conversations/sql/location.d.ts +13 -4
  19. package/dist/chat/{api-turns → conversations}/stop.d.ts +2 -2
  20. package/dist/chat/conversations/store.d.ts +4 -4
  21. package/dist/chat/conversations/structured-events.d.ts +1 -1
  22. package/dist/chat/{api-turns/authorization.d.ts → conversations/web-authorization.d.ts} +1 -0
  23. package/dist/chat/conversations/web-input.d.ts +98 -0
  24. package/dist/chat/conversations/web-mailbox.d.ts +12 -0
  25. package/dist/chat/event-tasks/tool-support.d.ts +0 -6
  26. package/dist/chat/providers/slack/runtime.d.ts +1 -0
  27. package/dist/chat/providers/slack/system-turn.d.ts +8 -0
  28. package/dist/chat/resource-events/actor.d.ts +13 -12
  29. package/dist/chat/resource-events/notification.d.ts +1 -1
  30. package/dist/chat/services/guardian-action-policy.d.ts +1 -1
  31. package/dist/chat/services/turn-session-routing.d.ts +2 -2
  32. package/dist/chat/task-execution/assistant-message.d.ts +32 -0
  33. package/dist/chat/task-execution/conversation-turn.d.ts +8 -0
  34. package/dist/chat/{api-turns → task-execution}/mailbox-input.d.ts +1 -2
  35. package/dist/chat/task-execution/mailbox-turn.d.ts +42 -0
  36. package/dist/chat/task-execution/paused-turn.d.ts +1 -1
  37. package/dist/chat/task-execution/slack-work.d.ts +0 -2
  38. package/dist/{chunk-AW77HH54.js → chunk-4RHJ3CXR.js} +14 -295
  39. package/dist/{chunk-ZX7RSBQ6.js → chunk-5CXCGDIL.js} +1 -1
  40. package/dist/{chunk-QVH6FW3T.js → chunk-5VWAY27R.js} +7 -3
  41. package/dist/{chunk-XJIPMHKI.js → chunk-6AUR6PWR.js} +3 -3
  42. package/dist/{chunk-QDHJTKPE.js → chunk-7R5JRPCY.js} +8 -6
  43. package/dist/{chunk-6JZGXLL2.js → chunk-AC7MDOJW.js} +5 -7
  44. package/dist/{chunk-Q7O74WOO.js → chunk-BYBSI5TI.js} +2 -2
  45. package/dist/{chunk-VFZAUQ5V.js → chunk-CMWIMFM6.js} +4 -182
  46. package/dist/{chunk-IUUQWIG2.js → chunk-CUYFCI4G.js} +59 -11
  47. package/dist/chunk-DA2KGZZI.js +13 -0
  48. package/dist/{chunk-FIUCHYT6.js → chunk-DYXVAO2E.js} +1 -1
  49. package/dist/{chunk-NZLZ4KYZ.js → chunk-E3PDZPGV.js} +1 -1
  50. package/dist/{chunk-Z5SKZE5B.js → chunk-GP32KD2J.js} +4 -12
  51. package/dist/{chunk-XI4PVY2T.js → chunk-KN32OWL2.js} +5 -5
  52. package/dist/chunk-LHKZKAZ4.js +285 -0
  53. package/dist/{chunk-6YGFBU3A.js → chunk-MFSET7Q7.js} +44 -334
  54. package/dist/{chunk-QCGNHSMA.js → chunk-MI6ZBDTS.js} +6 -6
  55. package/dist/{chunk-CIG6WI7Q.js → chunk-MRXMFB4L.js} +5 -5
  56. package/dist/{chunk-CVBDVIF4.js → chunk-MVPLEPSI.js} +1 -1
  57. package/dist/{chunk-32XSSFZV.js → chunk-NY2F7BZA.js} +1 -1
  58. package/dist/chunk-O35GZCKL.js +311 -0
  59. package/dist/{chunk-HCIVBCP5.js → chunk-OEIITG5F.js} +1 -1
  60. package/dist/{chunk-UVUXFRYN.js → chunk-PCPSX4ES.js} +209 -7
  61. package/dist/{chunk-QIMN3FXL.js → chunk-PY3EIEAF.js} +1 -1
  62. package/dist/{chunk-RMB7CERI.js → chunk-QNIOBNOY.js} +282 -121
  63. package/dist/{chunk-WGZJ5SU4.js → chunk-S3SGZUOI.js} +1 -1
  64. package/dist/chunk-SR6OMO5C.js +703 -0
  65. package/dist/{chunk-CDSLOYOR.js → chunk-UCWO5MKP.js} +6 -6
  66. package/dist/{chunk-PSHMPRIU.js → chunk-VKQWU4PO.js} +2 -2
  67. package/dist/{chunk-X55FOVZO.js → chunk-WDHPN2GH.js} +3 -3
  68. package/dist/{chunk-WW2Y7JIA.js → chunk-WMUAKAIF.js} +43 -44
  69. package/dist/{chunk-MQDIIFZM.js → chunk-WN6VLHOU.js} +12 -5
  70. package/dist/{chunk-W42ENMJW.js → chunk-WWYUYKKV.js} +1 -1
  71. package/dist/{chunk-ERZMACYA.js → chunk-WYDF6PGK.js} +3 -3
  72. package/dist/{chunk-SC67CH3C.js → chunk-YNZPOFF3.js} +14 -17
  73. package/dist/{chunk-3HEZWDS5.js → chunk-YYSEH2WC.js} +2 -2
  74. package/dist/{chunk-W2DDJCPS.js → chunk-YYZNESC3.js} +8 -8
  75. package/dist/{chunk-CZRWU4ZM.js → chunk-ZUPDSJUE.js} +2 -5
  76. package/dist/{chunk-QIOUTXTZ.js → chunk-ZV6PFUA4.js} +1 -1
  77. package/dist/cli/chat.js +34 -33
  78. package/dist/cli/check.js +5 -5
  79. package/dist/cli/plugins.js +12 -12
  80. package/dist/cli/snapshot-create.js +9 -9
  81. package/dist/cli/upgrade.js +6 -6
  82. package/dist/db/schema/agent-invocations.d.ts +0 -36
  83. package/dist/db/schema/conversations.d.ts +62 -0
  84. package/dist/db/schema.d.ts +31 -36
  85. package/dist/{db-YPRZAA2T.js → db-LPJKR2EO.js} +6 -6
  86. package/dist/instrumentation.js +3 -3
  87. package/dist/nitro.js +6 -6
  88. package/dist/{oauth-callback-server-DBBIR3XG.js → oauth-callback-server-DMXF4TTQ.js} +30 -28
  89. package/dist/{runner-FKVFFPLO.js → runner-L5DPVYCN.js} +25 -21
  90. package/dist/{skills-4RBAZEMV.js → skills-NXG3LBCK.js} +5 -5
  91. package/dist/spawn-VRUIGKWW.js +42 -0
  92. package/dist/task-runner-7YTBSPXW.js +36 -0
  93. package/dist/{validation-E6Z5LHZM.js → validation-CH36LTOS.js} +5 -5
  94. package/dist/version.js +1 -1
  95. package/dist/{work-OFTXWOK4.js → work-HBC5Y5VZ.js} +22 -21
  96. package/dist/{worker-OMWNOKTJ.js → worker-5RDZHLXH.js} +10 -10
  97. package/migrations/0037_conversation_location.sql +23 -0
  98. package/migrations/meta/0037_snapshot.json +3192 -0
  99. package/migrations/meta/_journal.json +7 -0
  100. package/package.json +5 -5
  101. package/dist/chat/api-turns/assistant-message.d.ts +0 -12
  102. package/dist/chat/api-turns/cancellation.d.ts +0 -24
  103. package/dist/chat/api-turns/routing.d.ts +0 -51
  104. package/dist/chat/api-turns/work.d.ts +0 -99
  105. package/dist/chat/task-execution/slack-resource-event.d.ts +0 -55
  106. package/dist/chunk-6FGN7ZEG.js +0 -221
  107. package/dist/chunk-LODJKINF.js +0 -1502
  108. package/dist/spawn-CO7QFCNJ.js +0 -41
  109. package/dist/task-runner-DUGZGI7V.js +0 -34
@@ -0,0 +1,311 @@
1
+ import {
2
+ usageSchema
3
+ } from "./chunk-PDO5BLNM.js";
4
+ import {
5
+ botConfig
6
+ } from "./chunk-BYBSI5TI.js";
7
+ import {
8
+ logWarn
9
+ } from "./chunk-PY3EIEAF.js";
10
+
11
+ // src/chat/conversations/structured-events.ts
12
+ import {
13
+ conversationEventPresentationSchema,
14
+ defineConversationEvent
15
+ } from "@sentry/junior-plugin-api";
16
+ import { z } from "zod";
17
+ var JUNIOR_NATIVE_EVENT_NAMESPACE = "junior";
18
+ var authenticationEventContentSchema = z.object({
19
+ accountLabel: z.string().trim().min(1).max(120).optional(),
20
+ actorId: z.string().min(1),
21
+ authorizationId: z.string().min(1).optional(),
22
+ provider: z.string().regex(/^[a-z][a-z0-9-]*$/),
23
+ providerLabel: z.string().trim().min(1).max(80).optional()
24
+ }).strict();
25
+ var agentsInstructionsUpdatedContentSchema = z.object({
26
+ action: z.enum(["loaded", "replaced", "cleared"]),
27
+ directory: z.string().trim().min(1).max(500).optional(),
28
+ fingerprint: z.string().trim().min(1).max(128),
29
+ sources: z.array(
30
+ z.object({
31
+ content: z.string().min(1).max(32 * 1024),
32
+ path: z.string().trim().min(1).max(500)
33
+ }).strict()
34
+ ).max(32),
35
+ textBytes: z.number().int().nonnegative().optional()
36
+ }).strict();
37
+ function providerTitle(content) {
38
+ return content.providerLabel?.trim() || content.provider;
39
+ }
40
+ function agentsInstructionsTitle(action) {
41
+ if (action === "loaded") return "Loaded AGENTS.md";
42
+ if (action === "replaced") return "Updated AGENTS.md";
43
+ return "Cleared AGENTS.md";
44
+ }
45
+ function sourceFilename(sourcePath) {
46
+ return sourcePath.split("/").at(-1) || sourcePath;
47
+ }
48
+ function formatBytes(bytes) {
49
+ if (bytes < 1024) return `${bytes} bytes`;
50
+ const kilobytes = bytes / 1024;
51
+ return `${Number.isInteger(kilobytes) ? kilobytes : kilobytes.toFixed(1)} KB`;
52
+ }
53
+ function agentsInstructionsPreview(content) {
54
+ const source = content.sources[0];
55
+ if (!source) return void 0;
56
+ const filename = sourceFilename(source.path);
57
+ const label = content.sources.length === 1 ? filename : `${content.sources.length} AGENTS.md files`;
58
+ return typeof content.textBytes === "number" ? `${label} \xB7 ${formatBytes(content.textBytes)}` : label;
59
+ }
60
+ var authenticationLinkedEvent = defineConversationEvent({
61
+ name: "authentication_linked",
62
+ version: 1,
63
+ schema: authenticationEventContentSchema,
64
+ renderEvent(event) {
65
+ const provider = providerTitle(event);
66
+ return {
67
+ icon: "link",
68
+ title: `${provider} connected`,
69
+ ...event.accountLabel ? { preview: `Connected as \`${event.accountLabel}\`` } : void 0,
70
+ details: [
71
+ {
72
+ title: `${provider} connected`,
73
+ ...event.accountLabel ? { description: `Connected as \`${event.accountLabel}\`` } : void 0,
74
+ metadata: [event.provider]
75
+ }
76
+ ]
77
+ };
78
+ }
79
+ });
80
+ var authenticationUnlinkedEvent = defineConversationEvent({
81
+ name: "authentication_unlinked",
82
+ version: 1,
83
+ schema: authenticationEventContentSchema,
84
+ renderEvent(event) {
85
+ const provider = providerTitle(event);
86
+ return {
87
+ icon: "key",
88
+ title: `${provider} disconnected`,
89
+ details: [
90
+ {
91
+ title: `${provider} disconnected`,
92
+ metadata: [event.provider]
93
+ }
94
+ ]
95
+ };
96
+ }
97
+ });
98
+ var agentsInstructionsUpdatedEvent = defineConversationEvent({
99
+ name: "agents_instructions_updated",
100
+ version: 1,
101
+ schema: agentsInstructionsUpdatedContentSchema,
102
+ renderEvent(event) {
103
+ const title = agentsInstructionsTitle(event.action);
104
+ const preview = agentsInstructionsPreview(event);
105
+ return {
106
+ icon: "brain",
107
+ title,
108
+ ...preview ? { preview } : void 0,
109
+ ...event.sources.length > 0 ? {
110
+ details: event.sources.map((source) => ({
111
+ title: sourceFilename(source.path),
112
+ content: source.content
113
+ }))
114
+ } : void 0
115
+ };
116
+ }
117
+ });
118
+ var NATIVE_EVENT_DEFINITIONS = [
119
+ authenticationLinkedEvent,
120
+ authenticationUnlinkedEvent,
121
+ agentsInstructionsUpdatedEvent
122
+ ];
123
+ function getJuniorNativeEventDefinition(args) {
124
+ return NATIVE_EVENT_DEFINITIONS.find(
125
+ (definition) => definition.eventName === args.name && definition.version === args.version
126
+ );
127
+ }
128
+ function renderJuniorNativeConversationEvent(args) {
129
+ if (args.namespace !== JUNIOR_NATIVE_EVENT_NAMESPACE) return void 0;
130
+ const definition = getJuniorNativeEventDefinition(args);
131
+ if (!definition) return void 0;
132
+ const presentation = definition.renderEvent(definition.parse(args.content));
133
+ return presentation === void 0 ? void 0 : conversationEventPresentationSchema.parse(presentation);
134
+ }
135
+
136
+ // src/chat/usage.ts
137
+ var agentTurnUsageSchema = usageSchema;
138
+ var COMPONENT_USAGE_FIELDS = [
139
+ "inputTokens",
140
+ "outputTokens",
141
+ "cachedInputTokens",
142
+ "cacheCreationTokens"
143
+ ];
144
+ var COST_COMPONENT_FIELDS = [
145
+ "input",
146
+ "output",
147
+ "cacheRead",
148
+ "cacheWrite"
149
+ ];
150
+ function hasAgentTurnUsage(usage) {
151
+ return Boolean(
152
+ usage && (Object.entries(usage).some(
153
+ ([field, value]) => field !== "cost" && typeof value === "number" && Number.isFinite(value)
154
+ ) || Object.values(usage.cost ?? {}).some(
155
+ (value) => typeof value === "number" && Number.isFinite(value)
156
+ ))
157
+ );
158
+ }
159
+ function getFiniteCount(value) {
160
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : void 0;
161
+ }
162
+ function getFiniteCost(value) {
163
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : void 0;
164
+ }
165
+ function addCost(left, right) {
166
+ return Math.round(((left ?? 0) + right) * 1e12) / 1e12;
167
+ }
168
+ function getComponentTotal(usage) {
169
+ let total;
170
+ for (const field of COMPONENT_USAGE_FIELDS) {
171
+ const value = getFiniteCount(usage[field]);
172
+ if (value === void 0) continue;
173
+ total = (total ?? 0) + value;
174
+ }
175
+ return total;
176
+ }
177
+ function addAgentTurnUsage(...usages) {
178
+ const components = {};
179
+ let componentTotal;
180
+ let totalOnlyTokens;
181
+ let reasoningTokens;
182
+ const cost = {};
183
+ for (const usage of usages) {
184
+ if (!usage) continue;
185
+ const reasoning = getFiniteCount(usage.reasoningTokens);
186
+ if (reasoning !== void 0) {
187
+ reasoningTokens = (reasoningTokens ?? 0) + reasoning;
188
+ }
189
+ if (usage.cost) {
190
+ for (const field of [...COST_COMPONENT_FIELDS, "total"]) {
191
+ const value = getFiniteCost(usage.cost[field]);
192
+ if (value === void 0) continue;
193
+ cost[field] = addCost(cost[field], value);
194
+ }
195
+ }
196
+ const usageComponentTotal = getComponentTotal(usage);
197
+ if (usageComponentTotal !== void 0) {
198
+ componentTotal = (componentTotal ?? 0) + usageComponentTotal;
199
+ for (const field of COMPONENT_USAGE_FIELDS) {
200
+ const value = getFiniteCount(usage[field]);
201
+ if (value === void 0) continue;
202
+ components[field] = (components[field] ?? 0) + value;
203
+ }
204
+ continue;
205
+ }
206
+ const totalTokens = getFiniteCount(usage.totalTokens);
207
+ if (totalTokens !== void 0) {
208
+ totalOnlyTokens = (totalOnlyTokens ?? 0) + totalTokens;
209
+ }
210
+ }
211
+ if (totalOnlyTokens !== void 0) {
212
+ return {
213
+ totalTokens: totalOnlyTokens + (componentTotal ?? 0),
214
+ ...reasoningTokens !== void 0 ? { reasoningTokens } : void 0,
215
+ ...Object.keys(cost).length > 0 ? { cost } : void 0
216
+ };
217
+ }
218
+ const result = {
219
+ ...components,
220
+ ...reasoningTokens !== void 0 ? { reasoningTokens } : void 0,
221
+ ...Object.keys(cost).length > 0 ? { cost } : void 0
222
+ };
223
+ return hasAgentTurnUsage(result) ? result : void 0;
224
+ }
225
+
226
+ // src/chat/services/short-title.ts
227
+ var SHORT_TITLE_MAX_LENGTH = 60;
228
+ var TITLE_PROMPTS = {
229
+ conversation: [
230
+ "Generate a concise 5-8 word conversation title from the first user message below.",
231
+ "Capture the user's main request.",
232
+ "Reply with ONLY the title, with no quotes or trailing punctuation."
233
+ ],
234
+ task: [
235
+ "Generate a concise 5-8 word task title from the task instruction below.",
236
+ "Capture the task's main purpose.",
237
+ "Reply with ONLY the title, with no quotes or trailing punctuation."
238
+ ]
239
+ };
240
+ function normalizeShortTitle(value) {
241
+ return value.replace(/\s+/g, " ").trim().slice(0, SHORT_TITLE_MAX_LENGTH);
242
+ }
243
+ function fallbackShortTitle(sourceText, fallback = "Untitled") {
244
+ const firstLine = sourceText.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0) ?? "";
245
+ return normalizeShortTitle(firstLine) || fallback;
246
+ }
247
+ async function generateShortTitle(args) {
248
+ const sourceText = args.sourceText.trim();
249
+ if (!sourceText) return void 0;
250
+ try {
251
+ const result = await args.completeText({
252
+ modelId: botConfig.fastModelId,
253
+ temperature: 0,
254
+ promptName: `junior.${args.kind}_title`,
255
+ messages: [
256
+ {
257
+ role: "user",
258
+ content: [
259
+ ...TITLE_PROMPTS[args.kind],
260
+ "",
261
+ args.kind === "conversation" ? `First user message: ${sourceText.slice(0, 500)}` : `Task instruction: ${sourceText.slice(0, 500)}`
262
+ ].join("\n"),
263
+ timestamp: Date.now()
264
+ }
265
+ ],
266
+ metadata: {
267
+ modelId: botConfig.fastModelId
268
+ }
269
+ });
270
+ const title = normalizeShortTitle(result.text);
271
+ return title || void 0;
272
+ } catch (error) {
273
+ logWarn(`${args.kind}.title.generation.failed`, {
274
+ "exception.message": error instanceof Error ? error.message : String(error)
275
+ });
276
+ return void 0;
277
+ }
278
+ }
279
+ async function resolveTaskTitle(args) {
280
+ const explicit = normalizeShortTitle(args.title ?? "");
281
+ if (explicit) return explicit;
282
+ return generateShortTitle({
283
+ completeText: args.completeText,
284
+ kind: "task",
285
+ sourceText: args.instruction
286
+ });
287
+ }
288
+
289
+ // src/chat/tools/execution/tool-input-error.ts
290
+ var ToolInputError = class extends Error {
291
+ constructor(message, options) {
292
+ super(message, options);
293
+ this.name = "ToolInputError";
294
+ }
295
+ };
296
+
297
+ export {
298
+ JUNIOR_NATIVE_EVENT_NAMESPACE,
299
+ authenticationLinkedEvent,
300
+ authenticationUnlinkedEvent,
301
+ agentsInstructionsUpdatedEvent,
302
+ renderJuniorNativeConversationEvent,
303
+ SHORT_TITLE_MAX_LENGTH,
304
+ fallbackShortTitle,
305
+ generateShortTitle,
306
+ resolveTaskTitle,
307
+ ToolInputError,
308
+ agentTurnUsageSchema,
309
+ hasAgentTurnUsage,
310
+ addAgentTurnUsage
311
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-NZLZ4KYZ.js";
3
+ } from "./chunk-E3PDZPGV.js";
4
4
 
5
5
  // src/chat/plugins/validation.ts
6
6
  import { isDeepStrictEqual } from "util";
@@ -1,3 +1,6 @@
1
+ import {
2
+ isExperimentalFeatureEnabled
3
+ } from "./chunk-2LYHWMR4.js";
1
4
  import {
2
5
  SlackActionError,
3
6
  applyPluginFormatMarkdown,
@@ -5,19 +8,19 @@ import {
5
8
  isDmChannel,
6
9
  normalizeSlackConversationId,
7
10
  withSlackRetries
8
- } from "./chunk-QCGNHSMA.js";
11
+ } from "./chunk-MI6ZBDTS.js";
9
12
  import {
10
13
  parseDestination
11
- } from "./chunk-IUUQWIG2.js";
14
+ } from "./chunk-CUYFCI4G.js";
12
15
  import {
13
16
  getStateAdapter
14
- } from "./chunk-ZX7RSBQ6.js";
17
+ } from "./chunk-5CXCGDIL.js";
15
18
  import {
16
19
  normalizeSlackEmojiName
17
- } from "./chunk-Q7O74WOO.js";
20
+ } from "./chunk-BYBSI5TI.js";
18
21
  import {
19
22
  pluginCatalogRuntime
20
- } from "./chunk-NZLZ4KYZ.js";
23
+ } from "./chunk-E3PDZPGV.js";
21
24
  import {
22
25
  parseSlackMessageTs,
23
26
  parseSlackUserId
@@ -26,7 +29,198 @@ import {
26
29
  isRecord,
27
30
  logInfo,
28
31
  logWarn
29
- } from "./chunk-QIMN3FXL.js";
32
+ } from "./chunk-PY3EIEAF.js";
33
+
34
+ // src/chat/agent/types.ts
35
+ var RetryableDeliveryError = class extends Error {
36
+ constructor(cause) {
37
+ super("Assistant delivery was transient or ambiguous", { cause });
38
+ this.name = "RetryableDeliveryError";
39
+ }
40
+ };
41
+ function isAgentRunFeatureDisabled(disabledFeatures, feature) {
42
+ return disabledFeatures?.includes(feature) ?? false;
43
+ }
44
+ function actorFromRun(run) {
45
+ if (run.dispatch?.actor) {
46
+ return run.dispatch.actor;
47
+ }
48
+ if (run.actor) {
49
+ return run.actor;
50
+ }
51
+ if (run.credentialContext && !("type" in run.credentialContext.actor)) {
52
+ return run.credentialContext.actor;
53
+ }
54
+ return void 0;
55
+ }
56
+ function assertRunConsistency(run) {
57
+ const { destination, source } = run;
58
+ switch (source.platform) {
59
+ case "slack": {
60
+ if (destination.platform !== "slack") {
61
+ throw new TypeError(
62
+ "Run source and destination platforms do not match"
63
+ );
64
+ }
65
+ if (source.teamId !== destination.teamId) {
66
+ throw new TypeError("Slack source and destination teams do not match");
67
+ }
68
+ break;
69
+ }
70
+ case "local": {
71
+ if (destination.platform !== "local") {
72
+ throw new TypeError(
73
+ "Run source and destination platforms do not match"
74
+ );
75
+ }
76
+ if (source.conversationId !== destination.conversationId) {
77
+ throw new TypeError(
78
+ "Source and destination conversation IDs do not match"
79
+ );
80
+ }
81
+ if (run.surface !== "internal" && destination.conversationId !== run.conversationId) {
82
+ throw new TypeError(
83
+ "Source, destination, and run conversation IDs do not match"
84
+ );
85
+ }
86
+ break;
87
+ }
88
+ case "web": {
89
+ if (run.surface !== "internal" && source.conversationId !== run.conversationId) {
90
+ throw new TypeError("Web source and run conversation IDs do not match");
91
+ }
92
+ switch (destination.platform) {
93
+ case "local": {
94
+ if (source.conversationId !== destination.conversationId) {
95
+ throw new TypeError(
96
+ "Source and destination conversation IDs do not match"
97
+ );
98
+ }
99
+ if (run.surface !== "internal" && destination.conversationId !== run.conversationId) {
100
+ throw new TypeError(
101
+ "Source, destination, and run conversation IDs do not match"
102
+ );
103
+ }
104
+ break;
105
+ }
106
+ case "slack":
107
+ break;
108
+ }
109
+ break;
110
+ }
111
+ }
112
+ const actor = run.dispatch?.actor ?? run.actor;
113
+ if (!actor || actor.platform === "system") {
114
+ return;
115
+ }
116
+ if (actor.platform !== source.platform) {
117
+ throw new TypeError(
118
+ `Actor platform "${actor.platform}" does not match Source platform "${source.platform}"`
119
+ );
120
+ }
121
+ if (actor.platform === "slack" && source.platform === "slack" && actor.teamId !== source.teamId) {
122
+ throw new TypeError("Slack Actor team does not match Source team");
123
+ }
124
+ }
125
+ function toolInvocationDestination(run) {
126
+ if (run.destination.platform !== "slack" || !run.toolChannelId) {
127
+ return run.destination;
128
+ }
129
+ return {
130
+ platform: "slack",
131
+ teamId: run.destination.teamId,
132
+ channelId: run.toolChannelId
133
+ };
134
+ }
135
+ function surfaceFromRun(run) {
136
+ if (run.surface) {
137
+ return run.surface;
138
+ }
139
+ if (run.source.platform === "slack") {
140
+ return "slack";
141
+ }
142
+ if (run.source.platform === "web") {
143
+ return "api";
144
+ }
145
+ return "internal";
146
+ }
147
+
148
+ // src/chat/runtime/agent-runner.ts
149
+ var AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
150
+ function createAgentRunner(execute, options) {
151
+ const attachmentStorage = options?.attachmentStorage;
152
+ const streamFn = options?.streamFn;
153
+ const tracePropagation = options?.tracePropagation;
154
+ const bindSpawnAgent = options?.bindSpawnAgent;
155
+ const canBindSpawn = Boolean(bindSpawnAgent) && isExperimentalFeatureEnabled("subagents");
156
+ return {
157
+ run: async (run) => {
158
+ const spawnAgent = bindSpawnAgent && canBindSpawn && !isAgentRunFeatureDisabled(run.disabledFeatures, "subagents") ? bindSpawnAgent(run) : void 0;
159
+ const nextRun = {
160
+ ...run,
161
+ environment: {
162
+ ...run.environment,
163
+ attachmentStorage: run.environment?.attachmentStorage ?? attachmentStorage,
164
+ sandboxTracePropagation: run.environment?.sandboxTracePropagation ?? tracePropagation
165
+ },
166
+ ...spawnAgent ? {
167
+ durability: {
168
+ ...run.durability,
169
+ spawnAgent
170
+ }
171
+ } : void 0
172
+ };
173
+ return await execute(nextRun, streamFn);
174
+ }
175
+ };
176
+ }
177
+ async function waitForAgentSettlement(runPromise) {
178
+ let timeoutId;
179
+ const settleGrace = new Promise((resolve) => {
180
+ timeoutId = setTimeout(resolve, AGENT_ABORT_SETTLE_GRACE_MS);
181
+ timeoutId.unref?.();
182
+ });
183
+ await Promise.race([
184
+ runPromise.then(
185
+ () => void 0,
186
+ () => void 0
187
+ ),
188
+ settleGrace
189
+ ]);
190
+ if (timeoutId) {
191
+ clearTimeout(timeoutId);
192
+ }
193
+ }
194
+ async function runAgentWithTimeout(agentRunner, run, timeoutMs) {
195
+ if (typeof timeoutMs !== "number") {
196
+ return await agentRunner.run(run);
197
+ }
198
+ const timeoutError = new Error(
199
+ `executeAgentRun timed out after ${timeoutMs}ms`
200
+ );
201
+ const abortController = new AbortController();
202
+ const signal = run.signal ? AbortSignal.any([run.signal, abortController.signal]) : abortController.signal;
203
+ const runPromise = agentRunner.run({ ...run, signal });
204
+ let timeoutId;
205
+ const timeoutPromise = new Promise((_, reject) => {
206
+ timeoutId = setTimeout(() => {
207
+ abortController.abort(timeoutError);
208
+ reject(timeoutError);
209
+ }, timeoutMs);
210
+ });
211
+ try {
212
+ return await Promise.race([runPromise, timeoutPromise]);
213
+ } catch (error) {
214
+ if (abortController.signal.aborted) {
215
+ await waitForAgentSettlement(runPromise);
216
+ }
217
+ throw error;
218
+ } finally {
219
+ if (timeoutId) {
220
+ clearTimeout(timeoutId);
221
+ }
222
+ }
223
+ }
30
224
 
31
225
  // src/chat/slack/outbound.ts
32
226
  var MAX_SLACK_MESSAGE_TEXT_CHARS = 4e4;
@@ -705,6 +899,12 @@ async function startOAuthFlow(provider, input) {
705
899
  }
706
900
 
707
901
  export {
902
+ RetryableDeliveryError,
903
+ isAgentRunFeatureDisabled,
904
+ actorFromRun,
905
+ assertRunConsistency,
906
+ toolInvocationDestination,
907
+ surfaceFromRun,
708
908
  getSlackMessagePermalink,
709
909
  postSlackMessage,
710
910
  uploadFilesToConversation,
@@ -719,5 +919,7 @@ export {
719
919
  formatProviderLabel,
720
920
  resolveBaseUrl,
721
921
  deliverOAuthAuthorization,
722
- startOAuthFlow
922
+ startOAuthFlow,
923
+ createAgentRunner,
924
+ runAgentWithTimeout
723
925
  };
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-PEQXYSSE.js";
13
13
  import {
14
14
  JUNIOR_VERSION
15
- } from "./chunk-32XSSFZV.js";
15
+ } from "./chunk-NY2F7BZA.js";
16
16
 
17
17
  // src/deployment.ts
18
18
  var JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";