@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-
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
9937
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
12297
|
-
should_reply:
|
|
12298
|
-
should_unsubscribe:
|
|
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:
|
|
12302
|
-
reason:
|
|
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:
|
|
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 ?? "
|
|
88
|
-
fastModelId: env.AI_FAST_MODEL ?? env.AI_MODEL ?? "
|
|
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(
|