@sentry/junior 0.27.1 → 0.28.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.
package/dist/app.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  sandboxSkillDir,
26
26
  sandboxSkillFile,
27
27
  toOptionalTrimmed
28
- } from "./chunk-4PVJHUEV.js";
28
+ } from "./chunk-375D5V4U.js";
29
29
  import {
30
30
  CredentialUnavailableError,
31
31
  buildOAuthTokenRequest,
@@ -2174,7 +2174,8 @@ async function completeText(params) {
2174
2174
  "gen_ai.request.model": params.modelId,
2175
2175
  ...systemInstructionsAttribute ? { "gen_ai.system_instructions": systemInstructionsAttribute } : {},
2176
2176
  ...requestMessagesAttribute ? { "gen_ai.input.messages": requestMessagesAttribute } : {},
2177
- "app.ai.auth_mode": apiKey ? "oidc" : "api_key"
2177
+ "app.ai.auth_mode": apiKey ? "oidc" : "api_key",
2178
+ ...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
2178
2179
  };
2179
2180
  setSpanAttributes(startAttributes);
2180
2181
  const message = await completeSimple(
@@ -2187,6 +2188,7 @@ async function completeText(params) {
2187
2188
  ...apiKey ? { apiKey } : {},
2188
2189
  temperature: params.temperature,
2189
2190
  maxTokens: params.maxTokens,
2191
+ reasoning: params.thinkingLevel,
2190
2192
  signal: params.signal,
2191
2193
  metadata: params.metadata
2192
2194
  }
@@ -2205,7 +2207,8 @@ async function completeText(params) {
2205
2207
  "gen_ai.request.model": params.modelId,
2206
2208
  ...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : {},
2207
2209
  ...usageAttributes,
2208
- ...message.stopReason ? { "gen_ai.response.finish_reasons": [message.stopReason] } : {}
2210
+ ...message.stopReason ? { "gen_ai.response.finish_reasons": [message.stopReason] } : {},
2211
+ ...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
2209
2212
  };
2210
2213
  setSpanAttributes(endAttributes);
2211
2214
  if (message.stopReason === "error") {
@@ -2235,6 +2238,7 @@ async function completeObject(params) {
2235
2238
  ({ text } = await completeText({
2236
2239
  modelId: params.modelId,
2237
2240
  system: params.system,
2241
+ thinkingLevel: params.thinkingLevel,
2238
2242
  temperature: params.temperature,
2239
2243
  maxTokens: params.maxTokens,
2240
2244
  signal: params.signal,
@@ -3354,7 +3358,6 @@ function buildSystemPrompt(params) {
3354
3358
  [
3355
3359
  "- For factual or external questions, run tools/skills first, then answer from evidence.",
3356
3360
  "- Use tool descriptions as the source of truth for when each tool should or should not be called.",
3357
- "- Use `reportProgress` only for sparse, meaningful progress updates. Pass a short user-facing status message, and do not call it for every tool or small substep.",
3358
3361
  "- When using CLI tools through `bash`, prefer deterministic non-interactive flags and avoid commands that wait for prompts or editors.",
3359
3362
  "- Keep routine setup and research steps silent in user-facing replies. Do not narrate duplicate checks, credential issuance, file writes, or similar internal progress unless the result is user-relevant.",
3360
3363
  "- If a routine prerequisite check finds nothing notable, omit it entirely from the final reply and report only the user-relevant outcome.",
@@ -3409,6 +3412,10 @@ function buildSystemPrompt(params) {
3409
3412
  "- Use Slack-friendly markdown, not full CommonMark. Prefer bold section labels over markdown headings, and use bullets and short code blocks when helpful.",
3410
3413
  "- Keep normal responses brief and scannable.",
3411
3414
  "- If depth is needed, start with a concise summary and then provide fuller detail.",
3415
+ "- Prefer a single compact thread reply when the full answer comfortably fits within this inline budget.",
3416
+ "- When canvas creation is available and a research or document-style answer would likely need continuation, multiple sections, or future reference value, create a Slack canvas and keep the thread reply to a short summary plus the canvas link.",
3417
+ "- Typical canvas-first cases include long-form research summaries, timelines, bios or profiles, structured notes, plans, comparisons, and other reusable reference documents.",
3418
+ "- Do not create a canvas for short factual answers that fit cleanly in one normal thread reply.",
3412
3419
  "- For tool-heavy research, discovery, or source-checking requests, do not send an initial acknowledgment. Start the visible reply only once you can present the actual answer.",
3413
3420
  "- Do not narrate tool execution or repeated status updates in the visible reply.",
3414
3421
  "- Avoid tables and markdown links like `[label](url)` unless explicitly requested. Prefer plain URLs or Slack-native entities when exact rendering matters.",
@@ -5064,7 +5071,7 @@ function createReadFileTool() {
5064
5071
  import { Type as Type6 } from "@sinclair/typebox";
5065
5072
  function createReportProgressTool() {
5066
5073
  return tool({
5067
- description: "Update assistant status with a short user-facing progress message. Use this sparingly for meaningful progress changes, not for every tool call or minor substep.",
5074
+ description: "Update the user-visible assistant loading message with a short progress phase. For every non-trivial turn, call this early with the initial major work phase, then call it again only when the major phase meaningfully changes. Use concrete labels like Searching docs, Reviewing results, or Running checks. Skip trivial direct answers, generic filler, and minor substeps.",
5068
5075
  inputSchema: Type6.Object({
5069
5076
  message: Type6.String({
5070
5077
  minLength: 1,
@@ -5342,7 +5349,7 @@ function createOperationKey(toolName, input) {
5342
5349
  // src/chat/tools/slack/channel-post-message.ts
5343
5350
  function createSlackChannelPostMessageTool(context, state) {
5344
5351
  return tool({
5345
- description: "Post a message in the active Slack channel context (outside the thread). Use this when the user explicitly asks to post/send/share/say something in the channel. Do not use for normal thread replies or speculative broadcasts. Do not claim a channel message was posted unless this tool succeeds in this turn.",
5352
+ description: "Post a message in the active Slack channel context (outside the thread). Use this only when the user explicitly asks to post/send/share/say something in the current channel. Do not use it for normal thread replies, speculative broadcasts, or requests targeting another named channel; explain that limitation instead. Do not claim a channel message was posted unless this tool succeeds in this turn.",
5346
5353
  inputSchema: Type9.Object({
5347
5354
  text: Type9.String({
5348
5355
  minLength: 1,
@@ -5665,7 +5672,7 @@ function mergeRecentCanvases(existing, created) {
5665
5672
  }
5666
5673
  function createSlackCanvasCreateTool(context, state) {
5667
5674
  return tool({
5668
- description: "Create a Slack canvas for long-form output in the active assistant context channel. Use when content is too long for a thread reply or needs a persistent document. Do not use for short answers that fit in-thread.",
5675
+ description: "Create a Slack canvas for long-form output in the active assistant context channel. Use when the answer is better as a reusable document than a thread reply: long-form research, timelines, bios/profiles, structured notes, plans, comparisons, or anything likely to exceed one compact Slack reply. After creating it, keep the thread reply brief and include the canvas link. Do not use for short answers that fit cleanly in one normal thread reply.",
5669
5676
  inputSchema: Type11.Object({
5670
5677
  title: Type11.String({
5671
5678
  minLength: 1,
@@ -8711,7 +8718,7 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
8711
8718
  }
8712
8719
 
8713
8720
  // src/chat/tools/agent-tools.ts
8714
- function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor, capabilityRuntime, pluginAuthOrchestration, hooks) {
8721
+ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor, capabilityRuntime, pluginAuthOrchestration, onToolCall) {
8715
8722
  const shouldTrace = shouldEmitDevAgentTrace();
8716
8723
  return Object.entries(tools).map(([toolName, toolDef]) => ({
8717
8724
  name: toolName,
@@ -8721,7 +8728,7 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
8721
8728
  execute: async (toolCallId, params) => {
8722
8729
  const normalizedToolCallId = typeof toolCallId === "string" && toolCallId.length > 0 ? toolCallId : void 0;
8723
8730
  const toolArgumentsAttribute = serializeGenAiAttribute(params);
8724
- hooks?.onToolCall?.(toolName);
8731
+ onToolCall?.(toolName);
8725
8732
  const traceToolContext = {
8726
8733
  ...spanContext,
8727
8734
  conversationId: spanContext.conversationId,
@@ -9135,6 +9142,7 @@ function buildTurnResult(input) {
9135
9142
  shouldTrace,
9136
9143
  spanContext,
9137
9144
  usage,
9145
+ thinkingSelection,
9138
9146
  correlation,
9139
9147
  assistantUserName
9140
9148
  } = input;
@@ -9210,6 +9218,7 @@ function buildTurnResult(input) {
9210
9218
  outcome: resolvedOutcome,
9211
9219
  modelId: botConfig.modelId,
9212
9220
  assistantMessageCount: assistantMessages.length,
9221
+ thinkingLevel: thinkingSelection.thinkingLevel,
9213
9222
  toolCalls,
9214
9223
  toolResultCount: toolResults.length,
9215
9224
  toolErrorCount,
@@ -9232,6 +9241,120 @@ function buildTurnResult(input) {
9232
9241
  };
9233
9242
  }
9234
9243
 
9244
+ // src/chat/services/turn-thinking-level.ts
9245
+ import { z } from "zod";
9246
+ var CLASSIFIER_CONFIDENCE_THRESHOLD = 0.75;
9247
+ var MAX_ROUTER_CONTEXT_CHARS = 1200;
9248
+ var TURN_THINKING_LEVELS = ["none", "low", "medium", "high"];
9249
+ var turnExecutionProfileSchema = z.object({
9250
+ thinking_level: z.enum(TURN_THINKING_LEVELS),
9251
+ confidence: z.number().min(0).max(1),
9252
+ reason: z.string().min(1)
9253
+ });
9254
+ var DEFAULT_THINKING_LEVEL = "low";
9255
+ function trimContextForRouter(text) {
9256
+ const trimmed = text?.trim();
9257
+ if (!trimmed) {
9258
+ return void 0;
9259
+ }
9260
+ return trimmed.length <= MAX_ROUTER_CONTEXT_CHARS ? trimmed : trimmed.slice(-MAX_ROUTER_CONTEXT_CHARS);
9261
+ }
9262
+ function buildClassifierSystemPrompt() {
9263
+ return [
9264
+ "You route assistant turns to the cheapest thinking level that is still likely to succeed.",
9265
+ "Choose exactly one bucket: none, low, medium, or high.",
9266
+ "",
9267
+ "Use none for greetings, acknowledgments, and trivial single-step asks.",
9268
+ "Use low for straightforward explanations or simple one-step work.",
9269
+ "Use medium for investigations, ambiguous asks, multi-step analysis, or likely multi-tool work.",
9270
+ "Use high for code changes, debugging/root-cause analysis, research-heavy work, non-trivial drafting, or explicit requests to be thorough.",
9271
+ "",
9272
+ "Return JSON only with thinking_level, confidence, and reason."
9273
+ ].join("\n");
9274
+ }
9275
+ function buildClassifierPrompt(args) {
9276
+ const sections = [];
9277
+ const context = trimContextForRouter(args.conversationContext);
9278
+ if (context) {
9279
+ sections.push("<thread-background>", context, "</thread-background>", "");
9280
+ }
9281
+ sections.push(
9282
+ "<turn-context>",
9283
+ `- active_skills: ${args.activeSkillNames.join(", ") || "none"}`,
9284
+ `- attachment_count: ${args.attachmentCount}`,
9285
+ "</turn-context>",
9286
+ "",
9287
+ '<current-instruction priority="highest">',
9288
+ args.messageText.trim() || "[empty]",
9289
+ "</current-instruction>"
9290
+ );
9291
+ for (const block of args.currentTurnBlocks ?? []) {
9292
+ const trimmed = block.trim();
9293
+ if (!trimmed) {
9294
+ continue;
9295
+ }
9296
+ sections.push("", trimmed);
9297
+ }
9298
+ return sections.join("\n");
9299
+ }
9300
+ async function selectTurnThinkingLevel(args) {
9301
+ const activeSkillNames = [...new Set(args.activeSkillNames ?? [])].sort();
9302
+ try {
9303
+ const result = await args.completeObject({
9304
+ modelId: args.fastModelId,
9305
+ schema: turnExecutionProfileSchema,
9306
+ maxTokens: 120,
9307
+ metadata: {
9308
+ modelId: args.fastModelId,
9309
+ threadId: args.context?.threadId ?? "",
9310
+ channelId: args.context?.channelId ?? "",
9311
+ requesterId: args.context?.requesterId ?? "",
9312
+ runId: args.context?.runId ?? ""
9313
+ },
9314
+ prompt: buildClassifierPrompt({
9315
+ activeSkillNames,
9316
+ attachmentCount: args.attachmentCount ?? 0,
9317
+ conversationContext: args.conversationContext,
9318
+ currentTurnBlocks: args.currentTurnBlocks,
9319
+ messageText: args.messageText
9320
+ }),
9321
+ thinkingLevel: "low",
9322
+ system: buildClassifierSystemPrompt(),
9323
+ temperature: 0
9324
+ });
9325
+ const parsed = turnExecutionProfileSchema.parse(result.object);
9326
+ if (parsed.confidence < CLASSIFIER_CONFIDENCE_THRESHOLD) {
9327
+ return {
9328
+ confidence: parsed.confidence,
9329
+ thinkingLevel: DEFAULT_THINKING_LEVEL,
9330
+ reason: `low_confidence_default:${parsed.reason.trim()}`
9331
+ };
9332
+ }
9333
+ return {
9334
+ confidence: parsed.confidence,
9335
+ thinkingLevel: parsed.thinking_level,
9336
+ reason: parsed.reason.trim()
9337
+ };
9338
+ } catch {
9339
+ return {
9340
+ thinkingLevel: DEFAULT_THINKING_LEVEL,
9341
+ reason: "classifier_error_default"
9342
+ };
9343
+ }
9344
+ }
9345
+ function toAgentThinkingLevel(level) {
9346
+ switch (level) {
9347
+ case "none":
9348
+ return "off";
9349
+ case "low":
9350
+ return "low";
9351
+ case "medium":
9352
+ return "medium";
9353
+ case "high":
9354
+ return "high";
9355
+ }
9356
+ }
9357
+
9235
9358
  // src/chat/state/turn-session-store.ts
9236
9359
  var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
9237
9360
  var AGENT_TURN_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -9509,6 +9632,7 @@ function createMcpAuthOrchestration(deps, abortAgent) {
9509
9632
 
9510
9633
  // src/chat/respond.ts
9511
9634
  var startupDiscoveryLogged = false;
9635
+ var MAX_ROUTER_ATTACHMENT_PREVIEW_CHARS = 2e3;
9512
9636
  function buildOmittedImageAttachmentNotice(count) {
9513
9637
  return [
9514
9638
  "<omitted-image-attachments>",
@@ -9519,6 +9643,89 @@ function buildOmittedImageAttachmentNotice(count) {
9519
9643
  "</omitted-image-attachments>"
9520
9644
  ].join("\n");
9521
9645
  }
9646
+ function trimRouterAttachmentText(text) {
9647
+ const normalized = text.replaceAll("\0", " ").trim();
9648
+ if (!normalized) {
9649
+ return "";
9650
+ }
9651
+ return normalized.length <= MAX_ROUTER_ATTACHMENT_PREVIEW_CHARS ? normalized : `${normalized.slice(0, MAX_ROUTER_ATTACHMENT_PREVIEW_CHARS)}...`;
9652
+ }
9653
+ function supportsRouterTextPreview(mediaType) {
9654
+ const baseMediaType = mediaType.split(";", 1)[0]?.trim().toLowerCase();
9655
+ if (!baseMediaType) {
9656
+ return false;
9657
+ }
9658
+ return baseMediaType.startsWith("text/") || baseMediaType === "application/json" || baseMediaType === "application/xml" || baseMediaType === "application/x-www-form-urlencoded" || baseMediaType.endsWith("+json") || baseMediaType.endsWith("+xml");
9659
+ }
9660
+ function buildRouterAttachmentBlock(attachment) {
9661
+ if (attachment.promptText) {
9662
+ return trimRouterAttachmentText(attachment.promptText);
9663
+ }
9664
+ const header = [
9665
+ "<attachment>",
9666
+ `filename: ${attachment.filename ?? "unnamed"}`,
9667
+ `media_type: ${attachment.mediaType}`
9668
+ ];
9669
+ if (attachment.data && supportsRouterTextPreview(attachment.mediaType)) {
9670
+ const preview = trimRouterAttachmentText(attachment.data.toString("utf8"));
9671
+ if (preview) {
9672
+ return [
9673
+ ...header,
9674
+ "<text-preview>",
9675
+ preview,
9676
+ "</text-preview>",
9677
+ "</attachment>"
9678
+ ].join("\n");
9679
+ }
9680
+ }
9681
+ return [...header, "</attachment>"].join("\n");
9682
+ }
9683
+ function buildUserTurnInput(args) {
9684
+ const routerBlocks = [];
9685
+ const userContentParts = [
9686
+ { type: "text", text: args.userTurnText }
9687
+ ];
9688
+ if (args.omittedImageAttachmentCount > 0) {
9689
+ const omittedImagesNotice = buildOmittedImageAttachmentNotice(
9690
+ args.omittedImageAttachmentCount
9691
+ );
9692
+ userContentParts.push({ type: "text", text: omittedImagesNotice });
9693
+ routerBlocks.push(omittedImagesNotice);
9694
+ }
9695
+ for (const attachment of args.userAttachments ?? []) {
9696
+ routerBlocks.push(buildRouterAttachmentBlock(attachment));
9697
+ if (attachment.promptText) {
9698
+ userContentParts.push({
9699
+ type: "text",
9700
+ text: attachment.promptText
9701
+ });
9702
+ continue;
9703
+ }
9704
+ if (attachment.mediaType.startsWith("image/")) {
9705
+ if (!attachment.data) {
9706
+ throw new Error("Image attachment is missing image data");
9707
+ }
9708
+ userContentParts.push({
9709
+ type: "image",
9710
+ data: attachment.data.toString("base64"),
9711
+ mimeType: attachment.mediaType
9712
+ });
9713
+ continue;
9714
+ }
9715
+ if (!attachment.data) {
9716
+ throw new Error("Attachment is missing attachment data");
9717
+ }
9718
+ userContentParts.push({
9719
+ type: "text",
9720
+ text: encodeNonImageAttachmentForPrompt({
9721
+ data: attachment.data,
9722
+ mediaType: attachment.mediaType,
9723
+ filename: attachment.filename
9724
+ })
9725
+ });
9726
+ }
9727
+ return { routerBlocks, userContentParts };
9728
+ }
9522
9729
  function mcpToolsToDefinitions(mcpTools) {
9523
9730
  const defs = {};
9524
9731
  for (const tool2 of mcpTools) {
@@ -9546,6 +9753,7 @@ async function generateAssistantReply(messageText, context = {}) {
9546
9753
  let sandboxExecutor;
9547
9754
  let timedOut = false;
9548
9755
  let turnUsage;
9756
+ let thinkingSelection;
9549
9757
  const getSandboxMetadata = () => sandboxExecutor ? {
9550
9758
  sandboxId: sandboxExecutor.getSandboxId(),
9551
9759
  sandboxDependencyProfileHash: sandboxExecutor.getDependencyProfileHash()
@@ -9724,6 +9932,34 @@ async function generateAssistantReply(messageText, context = {}) {
9724
9932
  turnContext: { traceId: getActiveTraceId() }
9725
9933
  }
9726
9934
  );
9935
+ const { routerBlocks, userContentParts } = buildUserTurnInput({
9936
+ omittedImageAttachmentCount: context.omittedImageAttachmentCount ?? 0,
9937
+ userAttachments: context.userAttachments,
9938
+ userTurnText
9939
+ });
9940
+ thinkingSelection = await selectTurnThinkingLevel({
9941
+ activeSkillNames: activeSkills.map((skill) => skill.name),
9942
+ attachmentCount: context.userAttachments?.length,
9943
+ completeObject,
9944
+ conversationContext: context.conversationContext,
9945
+ context: {
9946
+ threadId: context.correlation?.threadId,
9947
+ channelId: context.correlation?.channelId,
9948
+ requesterId: context.correlation?.requesterId,
9949
+ runId: context.correlation?.runId
9950
+ },
9951
+ currentTurnBlocks: routerBlocks,
9952
+ fastModelId: botConfig.fastModelId,
9953
+ messageText: userInput
9954
+ });
9955
+ setSpanAttributes({
9956
+ "gen_ai.request.model": botConfig.modelId,
9957
+ "app.ai.reasoning_effort": thinkingSelection.thinkingLevel,
9958
+ "app.ai.thinking_level_reason": thinkingSelection.reason,
9959
+ ...thinkingSelection.confidence !== void 0 ? {
9960
+ "app.ai.thinking_level_confidence": thinkingSelection.confidence
9961
+ } : {}
9962
+ });
9727
9963
  timeoutResumeMessages = [];
9728
9964
  const generatedFiles = [];
9729
9965
  const replyFiles = [];
@@ -9885,44 +10121,6 @@ async function generateAssistantReply(messageText, context = {}) {
9885
10121
  runtimeMetadata: getRuntimeMetadata(),
9886
10122
  threadParticipants: context.threadParticipants
9887
10123
  });
9888
- const userContentParts = [{ type: "text", text: userTurnText }];
9889
- const omittedImageAttachmentCount = context.omittedImageAttachmentCount ?? 0;
9890
- if (omittedImageAttachmentCount > 0) {
9891
- userContentParts.push({
9892
- type: "text",
9893
- text: buildOmittedImageAttachmentNotice(omittedImageAttachmentCount)
9894
- });
9895
- }
9896
- for (const attachment of context.userAttachments ?? []) {
9897
- if (attachment.promptText) {
9898
- userContentParts.push({
9899
- type: "text",
9900
- text: attachment.promptText
9901
- });
9902
- } else if (attachment.mediaType.startsWith("image/")) {
9903
- if (!attachment.data) {
9904
- throw new Error("Image attachment is missing image data");
9905
- }
9906
- userContentParts.push({
9907
- type: "image",
9908
- data: attachment.data.toString("base64"),
9909
- mimeType: attachment.mediaType
9910
- });
9911
- } else {
9912
- if (!attachment.data) {
9913
- throw new Error("Attachment is missing attachment data");
9914
- }
9915
- const promptAttachment = {
9916
- data: attachment.data,
9917
- mediaType: attachment.mediaType,
9918
- filename: attachment.filename
9919
- };
9920
- userContentParts.push({
9921
- type: "text",
9922
- text: encodeNonImageAttachmentForPrompt(promptAttachment)
9923
- });
9924
- }
9925
- }
9926
10124
  const inputMessagesAttribute = serializeGenAiAttribute([
9927
10125
  {
9928
10126
  role: "system",
@@ -9933,21 +10131,8 @@ async function generateAssistantReply(messageText, context = {}) {
9933
10131
  content: userContentParts.map((part) => toObservablePromptPart(part))
9934
10132
  }
9935
10133
  ]);
9936
- const agentToolHooks = {
9937
- onToolCall: (toolName) => {
9938
- toolCalls.push(toolName);
9939
- Promise.resolve(context.onToolCall?.(toolName)).catch((error) => {
9940
- logWarn(
9941
- "streaming_tool_call_error",
9942
- {},
9943
- {
9944
- "error.message": error instanceof Error ? error.message : String(error),
9945
- "gen_ai.tool.name": toolName
9946
- },
9947
- "Failed to deliver tool call event to stream coordinator"
9948
- );
9949
- });
9950
- }
10134
+ const onToolCall = (toolName) => {
10135
+ toolCalls.push(toolName);
9951
10136
  };
9952
10137
  const baseAgentTools = createAgentTools(
9953
10138
  tools,
@@ -9957,7 +10142,7 @@ async function generateAssistantReply(messageText, context = {}) {
9957
10142
  sandboxExecutor,
9958
10143
  capabilityRuntime,
9959
10144
  pluginAuth,
9960
- agentToolHooks
10145
+ onToolCall
9961
10146
  );
9962
10147
  const agentTools = [...baseAgentTools];
9963
10148
  const syncMcpAgentTools = () => {
@@ -9971,7 +10156,7 @@ async function generateAssistantReply(messageText, context = {}) {
9971
10156
  sandboxExecutor,
9972
10157
  capabilityRuntime,
9973
10158
  pluginAuth,
9974
- agentToolHooks
10159
+ onToolCall
9975
10160
  );
9976
10161
  agentTools.length = 0;
9977
10162
  agentTools.push(...baseAgentTools, ...mcpAgentTools);
@@ -9982,6 +10167,7 @@ async function generateAssistantReply(messageText, context = {}) {
9982
10167
  initialState: {
9983
10168
  systemPrompt: baseInstructions,
9984
10169
  model: resolveGatewayModel(botConfig.modelId),
10170
+ thinkingLevel: toAgentThinkingLevel(thinkingSelection.thinkingLevel),
9985
10171
  tools: agentTools
9986
10172
  }
9987
10173
  });
@@ -10069,6 +10255,9 @@ async function generateAssistantReply(messageText, context = {}) {
10069
10255
  "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
10070
10256
  "gen_ai.operation.name": "invoke_agent",
10071
10257
  "gen_ai.request.model": botConfig.modelId,
10258
+ ...thinkingSelection ? {
10259
+ "app.ai.reasoning_effort": thinkingSelection.thinkingLevel
10260
+ } : {},
10072
10261
  "app.ai.turn_timeout_ms": botConfig.turnTimeoutMs
10073
10262
  },
10074
10263
  "Agent turn timed out and was aborted"
@@ -10113,6 +10302,7 @@ async function generateAssistantReply(messageText, context = {}) {
10113
10302
  "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
10114
10303
  "gen_ai.operation.name": "invoke_agent",
10115
10304
  "gen_ai.request.model": botConfig.modelId,
10305
+ "app.ai.reasoning_effort": thinkingSelection.thinkingLevel,
10116
10306
  ...inputMessagesAttribute ? { "gen_ai.input.messages": inputMessagesAttribute } : {}
10117
10307
  }
10118
10308
  );
@@ -10144,6 +10334,7 @@ async function generateAssistantReply(messageText, context = {}) {
10144
10334
  shouldTrace,
10145
10335
  spanContext,
10146
10336
  usage: turnUsage,
10337
+ thinkingSelection,
10147
10338
  correlation: context.correlation,
10148
10339
  assistantUserName: context.assistant?.userName
10149
10340
  });
@@ -10230,6 +10421,9 @@ async function generateAssistantReply(messageText, context = {}) {
10230
10421
  outcome: "provider_error",
10231
10422
  modelId: botConfig.modelId,
10232
10423
  assistantMessageCount: 0,
10424
+ ...thinkingSelection ? {
10425
+ thinkingLevel: thinkingSelection.thinkingLevel
10426
+ } : {},
10233
10427
  toolCalls: [],
10234
10428
  toolResultCount: 0,
10235
10429
  toolErrorCount: 0,
@@ -12292,14 +12486,14 @@ async function POST(request, waitUntil) {
12292
12486
  }
12293
12487
 
12294
12488
  // src/chat/services/subscribed-decision.ts
12295
- import { z } from "zod";
12296
- var replyDecisionSchema = z.object({
12297
- should_reply: z.boolean().describe("Whether Junior should respond to this thread message."),
12298
- should_unsubscribe: z.boolean().optional().describe(
12489
+ import { z as z2 } from "zod";
12490
+ var replyDecisionSchema = z2.object({
12491
+ should_reply: z2.boolean().describe("Whether Junior should respond to this thread message."),
12492
+ should_unsubscribe: z2.boolean().optional().describe(
12299
12493
  "Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
12300
12494
  ),
12301
- confidence: z.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
12302
- reason: z.string().optional().describe("Short reason for the decision.")
12495
+ confidence: z2.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
12496
+ reason: z2.string().optional().describe("Short reason for the decision.")
12303
12497
  });
12304
12498
  var ROUTER_CONFIDENCE_THRESHOLD = 0.8;
12305
12499
  var LEADING_SLACK_MENTION_RE = /^\s*<@([A-Z0-9]+)(?:\|([^>]+))?>[\s,:-]*/i;
@@ -13989,7 +14183,7 @@ function createReplyToThread(deps) {
13989
14183
  slackChannelId: channelId,
13990
14184
  runId,
13991
14185
  assistantUserName: botConfig.userName,
13992
- modelId: botConfig.modelId
14186
+ modelId: reply.diagnostics.modelId
13993
14187
  };
13994
14188
  const diagnosticsAttributes = {
13995
14189
  "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
@@ -14000,6 +14194,9 @@ function createReplyToThread(deps) {
14000
14194
  "app.ai.tool_error_results": reply.diagnostics.toolErrorCount,
14001
14195
  "app.ai.tool_call_count": reply.diagnostics.toolCalls.length,
14002
14196
  "app.ai.used_primary_text": reply.diagnostics.usedPrimaryText,
14197
+ ...reply.diagnostics.thinkingLevel ? {
14198
+ "app.ai.reasoning_effort": reply.diagnostics.thinkingLevel
14199
+ } : {},
14003
14200
  ...reply.diagnostics.stopReason ? {
14004
14201
  "gen_ai.response.finish_reasons": [
14005
14202
  reply.diagnostics.stopReason
@@ -84,8 +84,8 @@ function readBotConfig(env) {
84
84
  const maxTurnTimeoutMs = resolveMaxTurnTimeoutMs(functionMaxDurationSeconds);
85
85
  return {
86
86
  userName: env.JUNIOR_BOT_NAME ?? "junior",
87
- modelId: env.AI_MODEL ?? "anthropic/claude-sonnet-4.6",
88
- fastModelId: env.AI_FAST_MODEL ?? env.AI_MODEL ?? "anthropic/claude-haiku-4.5",
87
+ modelId: env.AI_MODEL ?? "openai/gpt-5.4",
88
+ fastModelId: env.AI_FAST_MODEL ?? env.AI_MODEL ?? "openai/gpt-5.4-mini",
89
89
  loadingMessages: parseLoadingMessages(env.JUNIOR_LOADING_MESSAGES),
90
90
  visionModelId: toOptionalTrimmed(env.AI_VISION_MODEL),
91
91
  turnTimeoutMs: parseAgentTurnTimeoutMs(
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  disconnectStateAdapter,
3
3
  resolveRuntimeDependencySnapshot
4
- } from "../chunk-4PVJHUEV.js";
4
+ } from "../chunk-375D5V4U.js";
5
5
  import {
6
6
  getPluginProviders,
7
7
  getPluginRuntimeDependencies,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior",
3
- "version": "0.27.1",
3
+ "version": "0.28.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"