@sentry/junior 0.75.0 → 0.76.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 (100) hide show
  1. package/README.md +1 -1
  2. package/bin/junior.mjs +4 -66
  3. package/dist/agent-hooks-ZOE7RIED.js +37 -0
  4. package/dist/api-reference.d.ts +2 -0
  5. package/dist/app.js +317 -118
  6. package/dist/build/virtual-config.d.ts +2 -2
  7. package/dist/chat/agent-dispatch/runner.d.ts +2 -0
  8. package/dist/chat/config.d.ts +1 -0
  9. package/dist/chat/credentials/state-adapter-token-store.d.ts +2 -0
  10. package/dist/chat/credentials/user-token-store.d.ts +17 -12
  11. package/dist/chat/db.d.ts +8 -0
  12. package/dist/chat/mcp/auth-store.d.ts +2 -1
  13. package/dist/chat/mcp/oauth.d.ts +2 -1
  14. package/dist/chat/oauth-flow.d.ts +3 -1
  15. package/dist/chat/pi/client.d.ts +15 -7
  16. package/dist/chat/plugins/agent-hooks.d.ts +7 -0
  17. package/dist/chat/plugins/auth/oauth-request.d.ts +11 -7
  18. package/dist/chat/plugins/model.d.ts +9 -0
  19. package/dist/chat/plugins/prompt.d.ts +5 -0
  20. package/dist/chat/plugins/task-callback.d.ts +5 -0
  21. package/dist/chat/plugins/task-message.d.ts +23 -0
  22. package/dist/chat/plugins/task-queue.d.ts +5 -0
  23. package/dist/chat/plugins/task-runner.d.ts +12 -0
  24. package/dist/chat/plugins/task-signing.d.ts +31 -0
  25. package/dist/chat/prompt.d.ts +4 -0
  26. package/dist/chat/requester.d.ts +6 -5
  27. package/dist/chat/respond-helpers.d.ts +2 -0
  28. package/dist/chat/respond.d.ts +4 -2
  29. package/dist/chat/runtime/agent-continue-runner.d.ts +4 -0
  30. package/dist/chat/runtime/reply-executor.d.ts +5 -1
  31. package/dist/chat/runtime/slack-resume.d.ts +10 -2
  32. package/dist/chat/sentry.d.ts +1 -0
  33. package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -1
  34. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
  35. package/dist/chat/services/subscribed-decision.d.ts +2 -2
  36. package/dist/chat/services/turn-session-record.d.ts +11 -7
  37. package/dist/chat/state/turn-session.d.ts +8 -5
  38. package/dist/chat/tools/agent-tools.d.ts +8 -1
  39. package/dist/chat/tools/slack/context.d.ts +2 -2
  40. package/dist/chat/tools/types.d.ts +4 -4
  41. package/dist/chat/vercel-queue-client.d.ts +3 -0
  42. package/dist/{chunk-C3AM4Z4J.js → chunk-2ECJXSVQ.js} +5 -5
  43. package/dist/{chunk-OJODNL2P.js → chunk-4SCWV7TJ.js} +2 -2
  44. package/dist/chunk-4UO6FK4G.js +64 -0
  45. package/dist/{chunk-BNJIEFQC.js → chunk-56TBVRJG.js} +2 -2
  46. package/dist/{chunk-OK4KKR7B.js → chunk-EJN6G5A2.js} +28 -12
  47. package/dist/{chunk-TQ74BATR.js → chunk-HHDUKWVG.js} +428 -111
  48. package/dist/{chunk-XJHDZUGD.js → chunk-JBASI5VV.js} +4 -4
  49. package/dist/chunk-KNFROR7R.js +127 -0
  50. package/dist/{chunk-VNTLUFTY.js → chunk-KOIMO7S3.js} +126 -87
  51. package/dist/chunk-MLKGABMK.js +9 -0
  52. package/dist/{chunk-NPVUAXUE.js → chunk-NFTMTIP3.js} +303 -33
  53. package/dist/chunk-NYKJ3KON.js +1082 -0
  54. package/dist/{chunk-SJHUF3DP.js → chunk-OJ53FYVG.js} +2 -10
  55. package/dist/{chunk-62FUNJYS.js → chunk-Q6XFTRV5.js} +54 -3
  56. package/dist/{chunk-UJ7OTHPO.js → chunk-R6Z5XWY3.js} +12 -670
  57. package/dist/chunk-RV5RYIJW.js +56 -0
  58. package/dist/{chunk-EE6PJWY4.js → chunk-SG5WAA7H.js} +7 -5
  59. package/dist/chunk-ST6YNAXG.js +54 -0
  60. package/dist/{chunk-FCZO7LAR.js → chunk-T77LUIX3.js} +139 -153
  61. package/dist/{chunk-EIYL7I4S.js → chunk-VALUBQ7R.js} +22 -30
  62. package/dist/{chunk-OZSPLAQ4.js → chunk-XBBC6W45.js} +1 -1
  63. package/dist/{chunk-ZNNTSPNF.js → chunk-Y5OFBCBZ.js} +1 -1
  64. package/dist/{chunk-74HO27II.js → chunk-Z4CIQ3EB.js} +5 -1
  65. package/dist/{chunk-2RWFUS5F.js → chunk-ZLMBNBUG.js} +101 -44
  66. package/dist/{chunk-JEELK46E.js → chunk-ZQB37HUX.js} +11 -11
  67. package/dist/cli/chat.js +52 -23
  68. package/dist/cli/check.js +7 -7
  69. package/dist/cli/env.js +4 -53
  70. package/dist/cli/init.js +6 -1
  71. package/dist/cli/main.js +84 -0
  72. package/dist/cli/plugins.js +244 -0
  73. package/dist/cli/run.js +5 -52
  74. package/dist/cli/snapshot-warmup.js +9 -9
  75. package/dist/cli/upgrade.js +167 -48
  76. package/dist/db-7A7PFRGL.js +17 -0
  77. package/dist/deployment.d.ts +1 -0
  78. package/dist/instrumentation.js +14 -18
  79. package/dist/nitro.d.ts +1 -1
  80. package/dist/nitro.js +43 -22
  81. package/dist/plugins-PZMDS7AT.js +15 -0
  82. package/dist/plugins.d.ts +4 -2
  83. package/dist/{registry-NLZFIW23.js → registry-OIPAJU2O.js} +6 -6
  84. package/dist/reporting.js +34 -26
  85. package/dist/{runner-LUQZ5G67.js → runner-KPLNHDCV.js} +76 -23
  86. package/dist/sentry-4CP5NNQ5.js +31 -0
  87. package/dist/validation-SLA6IGF7.js +15 -0
  88. package/dist/vercel.js +1 -1
  89. package/package.json +7 -6
  90. package/dist/agent-hooks-2HEB4C3Q.js +0 -33
  91. package/dist/chat/conversations/configured.d.ts +0 -7
  92. package/dist/chat/conversations/state.d.ts +0 -4
  93. package/dist/chat/plugins/db.d.ts +0 -31
  94. package/dist/chunk-2KG3PWR4.js +0 -17
  95. package/dist/chunk-D7NFH5GD.js +0 -570
  96. package/dist/chunk-MCMROINU.js +0 -12
  97. package/dist/chunk-WBZ4M5N5.js +0 -59
  98. package/dist/db-A3ILH67H.js +0 -20
  99. package/dist/plugins-OMJKLRJ2.js +0 -13
  100. package/dist/validation-VMCPP3YO.js +0 -15
@@ -1,37 +1,86 @@
1
1
  import {
2
2
  createPluginLogger,
3
3
  createPluginState
4
- } from "./chunk-BNJIEFQC.js";
4
+ } from "./chunk-56TBVRJG.js";
5
+ import {
6
+ getDb
7
+ } from "./chunk-NYKJ3KON.js";
8
+ import {
9
+ SANDBOX_WORKSPACE_ROOT
10
+ } from "./chunk-G3E7SCME.js";
5
11
  import {
6
12
  isConversationChannel,
7
13
  isConversationScopedChannel,
8
14
  isDmChannel,
9
15
  normalizeSlackConversationId
10
- } from "./chunk-62FUNJYS.js";
16
+ } from "./chunk-Q6XFTRV5.js";
11
17
  import {
12
- getPluginDbForRegistration
13
- } from "./chunk-D7NFH5GD.js";
14
- import {
15
- SANDBOX_WORKSPACE_ROOT
16
- } from "./chunk-G3E7SCME.js";
18
+ botConfig,
19
+ completeObject,
20
+ embedTexts
21
+ } from "./chunk-T77LUIX3.js";
17
22
  import {
18
23
  isActorUserId,
19
24
  parseActorUserId
20
- } from "./chunk-EIYL7I4S.js";
25
+ } from "./chunk-VALUBQ7R.js";
21
26
  import {
22
- logInfo
23
- } from "./chunk-OK4KKR7B.js";
27
+ logInfo,
28
+ logWarn
29
+ } from "./chunk-EJN6G5A2.js";
30
+
31
+ // src/chat/plugins/agent-hooks.ts
32
+ import { promptMessageSchema } from "@sentry/junior-plugin-api";
33
+
34
+ // src/chat/plugins/model.ts
35
+ function createPluginModel(pluginName, options = {}, runtime = {}) {
36
+ return {
37
+ async completeObject(input) {
38
+ const modelId = options.structuredModelId ?? (options.structuredModel === "default" ? botConfig.modelId : botConfig.fastModelId);
39
+ const result = await completeObject({
40
+ modelId,
41
+ schema: input.schema,
42
+ prompt: input.prompt,
43
+ ...input.system !== void 0 ? { system: input.system } : {},
44
+ ...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {},
45
+ signal: runtime.signal,
46
+ metadata: {
47
+ pluginName,
48
+ pluginModelRole: "structured"
49
+ }
50
+ });
51
+ return { object: result.object };
52
+ }
53
+ };
54
+ }
55
+ function createPluginEmbedder(pluginName, runtime = {}) {
56
+ return {
57
+ async embedTexts(input) {
58
+ return await embedTexts({
59
+ modelId: botConfig.embeddingModelId,
60
+ texts: input.texts,
61
+ signal: runtime.signal,
62
+ metadata: {
63
+ pluginName,
64
+ pluginModelRole: "embedding"
65
+ }
66
+ });
67
+ }
68
+ };
69
+ }
24
70
 
25
71
  // src/chat/tools/slack/context.ts
26
72
  function getSlackToolContext(context) {
27
73
  if (context.source.platform !== "slack") {
28
74
  return void 0;
29
75
  }
76
+ if (context.destination.platform !== "slack") {
77
+ throw new TypeError("Slack source requires a Slack destination");
78
+ }
30
79
  return {
31
- destination: context.destination?.platform === "slack" ? context.destination : void 0,
80
+ destination: context.destination,
32
81
  source: context.source,
33
82
  requester: context.requester?.platform === "slack" ? context.requester : void 0,
34
- destinationChannelId: context.destination?.platform === "slack" ? context.destination.channelId : void 0,
83
+ destinationChannelId: context.destination.channelId,
35
84
  messageTs: context.source.messageTs,
36
85
  sourceChannelId: context.source.channelId,
37
86
  teamId: context.source.teamId,
@@ -142,6 +191,7 @@ function resolveChannelCapabilities(channelId) {
142
191
  }
143
192
 
144
193
  // src/chat/plugins/agent-hooks.ts
194
+ import { z } from "zod";
145
195
  var PluginHookDeniedError = class extends Error {
146
196
  constructor(message) {
147
197
  super(message);
@@ -167,18 +217,80 @@ var PLUGIN_ROUTE_METHODS = /* @__PURE__ */ new Set([
167
217
  "OPTIONS",
168
218
  "ALL"
169
219
  ]);
220
+ var PLUGIN_PROMPT_CONTRIBUTION_TOTAL_MAX_CHARS = 16e3;
221
+ var systemPromptMessageArraySchema = z.array(promptMessageSchema);
222
+ var userPromptMessageArraySchema = z.array(promptMessageSchema);
170
223
  function isRecord(value) {
171
224
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
172
225
  }
173
226
  function basePluginContext(plugin) {
174
227
  const name = plugin.manifest.name;
175
- const db = getPluginDbForRegistration(plugin);
176
228
  return {
177
229
  plugin: { name },
178
230
  log: createPluginLogger(name),
179
- ...db ? { db } : {}
231
+ db: getDb()
180
232
  };
181
233
  }
234
+ function systemPromptPluginContext(plugin) {
235
+ return {
236
+ ...basePluginContext(plugin)
237
+ };
238
+ }
239
+ function invocationPluginContext(plugin, context) {
240
+ const base = basePluginContext(plugin);
241
+ const common = {
242
+ ...base,
243
+ conversationId: context.conversationId,
244
+ embedder: createPluginEmbedder(plugin.manifest.name),
245
+ source: context.source,
246
+ text: context.userText ?? "",
247
+ state: createPluginState(plugin.manifest.name)
248
+ };
249
+ if (context.source.platform === "slack") {
250
+ if (context.destination.platform !== "slack") {
251
+ throw new TypeError(
252
+ "Slack plugin prompt context requires Slack destination"
253
+ );
254
+ }
255
+ return {
256
+ ...common,
257
+ destination: context.destination,
258
+ requester: context.requester?.platform === "slack" ? context.requester : void 0
259
+ };
260
+ }
261
+ if (context.destination.platform !== "local") {
262
+ throw new TypeError(
263
+ "Local plugin prompt context requires local destination"
264
+ );
265
+ }
266
+ return {
267
+ ...common,
268
+ destination: context.destination,
269
+ requester: context.requester?.platform === "local" ? context.requester : void 0
270
+ };
271
+ }
272
+ function safeErrorMessage(error) {
273
+ return error instanceof Error ? error.message : String(error);
274
+ }
275
+ function toPromptContributionContext(args) {
276
+ return {
277
+ id: `${args.hookName}:${args.index}`,
278
+ pluginName: args.pluginName,
279
+ text: args.message.text
280
+ };
281
+ }
282
+ function logInvalidPromptContributions(args) {
283
+ logWarn(
284
+ "plugin_prompt_contribution_result_invalid",
285
+ {},
286
+ {
287
+ "app.plugin.hook": args.hookName,
288
+ "app.plugin.name": args.pluginName,
289
+ "app.plugin.validation_reason": "invalid_shape"
290
+ },
291
+ "Plugin prompt contribution result invalid"
292
+ );
293
+ }
182
294
  function validatePlugins(plugins) {
183
295
  const seen = /* @__PURE__ */ new Set();
184
296
  for (const plugin of plugins) {
@@ -191,6 +303,18 @@ function validatePlugins(plugins) {
191
303
  if (seen.has(name)) {
192
304
  throw new Error(`Duplicate plugin name "${name}"`);
193
305
  }
306
+ for (const [taskName, task] of Object.entries(plugin.tasks ?? {})) {
307
+ if (!PLUGIN_TOOL_NAME_RE.test(taskName)) {
308
+ throw new Error(
309
+ `Plugin task "${taskName}" from plugin "${name}" must be a camelCase identifier`
310
+ );
311
+ }
312
+ if (typeof task.run !== "function") {
313
+ throw new Error(
314
+ `Plugin task "${taskName}" from plugin "${name}" must define a run function`
315
+ );
316
+ }
317
+ }
194
318
  seen.add(name);
195
319
  }
196
320
  }
@@ -205,6 +329,130 @@ function setPlugins(nextPlugins) {
205
329
  function getPlugins() {
206
330
  return [...registeredPlugins];
207
331
  }
332
+ async function getPluginSystemPromptContributions(source) {
333
+ const contributions = [];
334
+ let totalChars = 0;
335
+ for (const plugin of getPlugins()) {
336
+ const pluginName = plugin.manifest.name;
337
+ const hook = plugin.hooks?.systemPrompt;
338
+ if (!hook) {
339
+ continue;
340
+ }
341
+ try {
342
+ const pluginContributions = await hook({
343
+ ...systemPromptPluginContext(plugin),
344
+ platform: source.platform
345
+ });
346
+ const result = systemPromptMessageArraySchema.safeParse(pluginContributions);
347
+ if (!result.success) {
348
+ logInvalidPromptContributions({
349
+ hookName: "systemPrompt",
350
+ pluginName
351
+ });
352
+ continue;
353
+ }
354
+ const acceptedContributions = result.data.map(
355
+ (message, index) => toPromptContributionContext({
356
+ hookName: "systemPrompt",
357
+ index,
358
+ message,
359
+ pluginName
360
+ })
361
+ );
362
+ const pluginContributionChars = acceptedContributions.reduce(
363
+ (sum, contribution) => sum + contribution.text.length,
364
+ 0
365
+ );
366
+ if (totalChars + pluginContributionChars > PLUGIN_PROMPT_CONTRIBUTION_TOTAL_MAX_CHARS) {
367
+ logWarn(
368
+ "plugin_system_prompt_contribution_budget_exceeded",
369
+ {},
370
+ {
371
+ "app.plugin.name": pluginName
372
+ },
373
+ "Plugin system prompt contributions exceeded budget"
374
+ );
375
+ continue;
376
+ }
377
+ totalChars += pluginContributionChars;
378
+ contributions.push(...acceptedContributions);
379
+ } catch (error) {
380
+ logWarn(
381
+ "plugin_system_prompt_hook_failed",
382
+ {},
383
+ {
384
+ "app.plugin.name": pluginName,
385
+ "exception.message": safeErrorMessage(error)
386
+ },
387
+ "Plugin system prompt hook failed"
388
+ );
389
+ }
390
+ }
391
+ return contributions;
392
+ }
393
+ async function getPluginUserPromptContributions(args) {
394
+ const contributions = [];
395
+ let totalChars = 0;
396
+ for (const plugin of getPlugins()) {
397
+ const pluginName = plugin.manifest.name;
398
+ const hook = plugin.hooks?.userPrompt;
399
+ if (!hook) {
400
+ continue;
401
+ }
402
+ try {
403
+ const rawResult = await hook({
404
+ ...invocationPluginContext(plugin, args.context)
405
+ });
406
+ if (rawResult === void 0) {
407
+ continue;
408
+ }
409
+ const result = userPromptMessageArraySchema.safeParse(rawResult);
410
+ if (!result.success) {
411
+ logInvalidPromptContributions({
412
+ hookName: "userPrompt",
413
+ pluginName
414
+ });
415
+ continue;
416
+ }
417
+ const acceptedContributions = result.data.map(
418
+ (message, index) => toPromptContributionContext({
419
+ hookName: "userPrompt",
420
+ index,
421
+ message,
422
+ pluginName
423
+ })
424
+ );
425
+ const pluginContributionChars = acceptedContributions.reduce(
426
+ (sum, contribution) => sum + contribution.text.length,
427
+ 0
428
+ );
429
+ if (totalChars + pluginContributionChars > PLUGIN_PROMPT_CONTRIBUTION_TOTAL_MAX_CHARS) {
430
+ logWarn(
431
+ "plugin_user_prompt_contribution_budget_exceeded",
432
+ {},
433
+ {
434
+ "app.plugin.name": pluginName
435
+ },
436
+ "Plugin user prompt contributions exceeded budget"
437
+ );
438
+ continue;
439
+ }
440
+ totalChars += pluginContributionChars;
441
+ contributions.push(...acceptedContributions);
442
+ } catch (error) {
443
+ logWarn(
444
+ "plugin_user_prompt_hook_failed",
445
+ {},
446
+ {
447
+ "app.plugin.name": pluginName,
448
+ "exception.message": safeErrorMessage(error)
449
+ },
450
+ "Plugin user prompt hook failed"
451
+ );
452
+ }
453
+ }
454
+ return contributions;
455
+ }
208
456
  function getPluginTools(context) {
209
457
  const tools = {};
210
458
  for (const plugin of getPlugins()) {
@@ -213,7 +461,6 @@ function getPluginTools(context) {
213
461
  if (!hook) {
214
462
  continue;
215
463
  }
216
- const destination = context.destination;
217
464
  const slackToolContext = getSlackToolContext(context);
218
465
  const credentialSubject = slackToolContext ? createSlackDirectCredentialSubject({
219
466
  channelId: slackToolContext.sourceChannelId,
@@ -226,24 +473,43 @@ function getPluginTools(context) {
226
473
  ),
227
474
  ...credentialSubject ? { credentialSubject } : {}
228
475
  } : void 0;
229
- const pluginContext = context.source.platform === "slack" ? {
230
- ...basePluginContext(plugin),
231
- requester: context.requester?.platform === "slack" ? context.requester : void 0,
232
- conversationId: context.conversationId,
233
- destination: destination?.platform === "slack" ? destination : void 0,
234
- slack: slackContext,
235
- source: context.source,
236
- userText: context.userText,
237
- state: createPluginState(pluginName)
238
- } : {
239
- ...basePluginContext(plugin),
240
- requester: context.requester?.platform === "local" ? context.requester : void 0,
241
- conversationId: context.conversationId,
242
- destination: destination?.platform === "local" ? destination : void 0,
243
- source: context.source,
244
- userText: context.userText,
245
- state: createPluginState(pluginName)
246
- };
476
+ let pluginContext;
477
+ if (context.source.platform === "slack") {
478
+ if (context.destination.platform !== "slack") {
479
+ throw new TypeError(
480
+ "Slack plugin tool context requires Slack destination"
481
+ );
482
+ }
483
+ pluginContext = {
484
+ ...basePluginContext(plugin),
485
+ requester: context.requester?.platform === "slack" ? context.requester : void 0,
486
+ conversationId: context.conversationId,
487
+ destination: context.destination,
488
+ slack: slackContext,
489
+ source: context.source,
490
+ userText: context.userText,
491
+ embedder: createPluginEmbedder(pluginName),
492
+ model: createPluginModel(pluginName, plugin.model),
493
+ state: createPluginState(pluginName)
494
+ };
495
+ } else {
496
+ if (context.destination.platform !== "local") {
497
+ throw new TypeError(
498
+ "Local plugin tool context requires local destination"
499
+ );
500
+ }
501
+ pluginContext = {
502
+ ...basePluginContext(plugin),
503
+ requester: context.requester?.platform === "local" ? context.requester : void 0,
504
+ conversationId: context.conversationId,
505
+ destination: context.destination,
506
+ source: context.source,
507
+ userText: context.userText,
508
+ embedder: createPluginEmbedder(pluginName),
509
+ model: createPluginModel(pluginName, plugin.model),
510
+ state: createPluginState(pluginName)
511
+ };
512
+ }
247
513
  const pluginTools = hook(pluginContext);
248
514
  for (const [name, tool] of Object.entries(pluginTools)) {
249
515
  if (!PLUGIN_TOOL_NAME_RE.test(name)) {
@@ -678,6 +944,8 @@ function createPluginHookRunner(input = {}) {
678
944
  }
679
945
 
680
946
  export {
947
+ createPluginModel,
948
+ createPluginEmbedder,
681
949
  getSlackToolContext,
682
950
  bindSlackDirectCredentialSubject,
683
951
  verifySlackDirectCredentialSubject,
@@ -686,6 +954,8 @@ export {
686
954
  validatePlugins,
687
955
  setPlugins,
688
956
  getPlugins,
957
+ getPluginSystemPromptContributions,
958
+ getPluginUserPromptContributions,
689
959
  getPluginTools,
690
960
  getPluginRoutes,
691
961
  getPluginSlackConversationLink,