@sentry/junior 0.27.2 → 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.",
|
|
@@ -5068,7 +5071,7 @@ function createReadFileTool() {
|
|
|
5068
5071
|
import { Type as Type6 } from "@sinclair/typebox";
|
|
5069
5072
|
function createReportProgressTool() {
|
|
5070
5073
|
return tool({
|
|
5071
|
-
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.",
|
|
5072
5075
|
inputSchema: Type6.Object({
|
|
5073
5076
|
message: Type6.String({
|
|
5074
5077
|
minLength: 1,
|
|
@@ -5346,7 +5349,7 @@ function createOperationKey(toolName, input) {
|
|
|
5346
5349
|
// src/chat/tools/slack/channel-post-message.ts
|
|
5347
5350
|
function createSlackChannelPostMessageTool(context, state) {
|
|
5348
5351
|
return tool({
|
|
5349
|
-
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.",
|
|
5350
5353
|
inputSchema: Type9.Object({
|
|
5351
5354
|
text: Type9.String({
|
|
5352
5355
|
minLength: 1,
|
|
@@ -8715,7 +8718,7 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
|
|
|
8715
8718
|
}
|
|
8716
8719
|
|
|
8717
8720
|
// src/chat/tools/agent-tools.ts
|
|
8718
|
-
function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor, capabilityRuntime, pluginAuthOrchestration,
|
|
8721
|
+
function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor, capabilityRuntime, pluginAuthOrchestration, onToolCall) {
|
|
8719
8722
|
const shouldTrace = shouldEmitDevAgentTrace();
|
|
8720
8723
|
return Object.entries(tools).map(([toolName, toolDef]) => ({
|
|
8721
8724
|
name: toolName,
|
|
@@ -8725,7 +8728,7 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
8725
8728
|
execute: async (toolCallId, params) => {
|
|
8726
8729
|
const normalizedToolCallId = typeof toolCallId === "string" && toolCallId.length > 0 ? toolCallId : void 0;
|
|
8727
8730
|
const toolArgumentsAttribute = serializeGenAiAttribute(params);
|
|
8728
|
-
|
|
8731
|
+
onToolCall?.(toolName);
|
|
8729
8732
|
const traceToolContext = {
|
|
8730
8733
|
...spanContext,
|
|
8731
8734
|
conversationId: spanContext.conversationId,
|
|
@@ -9139,6 +9142,7 @@ function buildTurnResult(input) {
|
|
|
9139
9142
|
shouldTrace,
|
|
9140
9143
|
spanContext,
|
|
9141
9144
|
usage,
|
|
9145
|
+
thinkingSelection,
|
|
9142
9146
|
correlation,
|
|
9143
9147
|
assistantUserName
|
|
9144
9148
|
} = input;
|
|
@@ -9214,6 +9218,7 @@ function buildTurnResult(input) {
|
|
|
9214
9218
|
outcome: resolvedOutcome,
|
|
9215
9219
|
modelId: botConfig.modelId,
|
|
9216
9220
|
assistantMessageCount: assistantMessages.length,
|
|
9221
|
+
thinkingLevel: thinkingSelection.thinkingLevel,
|
|
9217
9222
|
toolCalls,
|
|
9218
9223
|
toolResultCount: toolResults.length,
|
|
9219
9224
|
toolErrorCount,
|
|
@@ -9236,6 +9241,120 @@ function buildTurnResult(input) {
|
|
|
9236
9241
|
};
|
|
9237
9242
|
}
|
|
9238
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
|
+
|
|
9239
9358
|
// src/chat/state/turn-session-store.ts
|
|
9240
9359
|
var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
|
|
9241
9360
|
var AGENT_TURN_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -9513,6 +9632,7 @@ function createMcpAuthOrchestration(deps, abortAgent) {
|
|
|
9513
9632
|
|
|
9514
9633
|
// src/chat/respond.ts
|
|
9515
9634
|
var startupDiscoveryLogged = false;
|
|
9635
|
+
var MAX_ROUTER_ATTACHMENT_PREVIEW_CHARS = 2e3;
|
|
9516
9636
|
function buildOmittedImageAttachmentNotice(count) {
|
|
9517
9637
|
return [
|
|
9518
9638
|
"<omitted-image-attachments>",
|
|
@@ -9523,6 +9643,89 @@ function buildOmittedImageAttachmentNotice(count) {
|
|
|
9523
9643
|
"</omitted-image-attachments>"
|
|
9524
9644
|
].join("\n");
|
|
9525
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
|
+
}
|
|
9526
9729
|
function mcpToolsToDefinitions(mcpTools) {
|
|
9527
9730
|
const defs = {};
|
|
9528
9731
|
for (const tool2 of mcpTools) {
|
|
@@ -9550,6 +9753,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9550
9753
|
let sandboxExecutor;
|
|
9551
9754
|
let timedOut = false;
|
|
9552
9755
|
let turnUsage;
|
|
9756
|
+
let thinkingSelection;
|
|
9553
9757
|
const getSandboxMetadata = () => sandboxExecutor ? {
|
|
9554
9758
|
sandboxId: sandboxExecutor.getSandboxId(),
|
|
9555
9759
|
sandboxDependencyProfileHash: sandboxExecutor.getDependencyProfileHash()
|
|
@@ -9728,6 +9932,34 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9728
9932
|
turnContext: { traceId: getActiveTraceId() }
|
|
9729
9933
|
}
|
|
9730
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
|
+
});
|
|
9731
9963
|
timeoutResumeMessages = [];
|
|
9732
9964
|
const generatedFiles = [];
|
|
9733
9965
|
const replyFiles = [];
|
|
@@ -9889,44 +10121,6 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9889
10121
|
runtimeMetadata: getRuntimeMetadata(),
|
|
9890
10122
|
threadParticipants: context.threadParticipants
|
|
9891
10123
|
});
|
|
9892
|
-
const userContentParts = [{ type: "text", text: userTurnText }];
|
|
9893
|
-
const omittedImageAttachmentCount = context.omittedImageAttachmentCount ?? 0;
|
|
9894
|
-
if (omittedImageAttachmentCount > 0) {
|
|
9895
|
-
userContentParts.push({
|
|
9896
|
-
type: "text",
|
|
9897
|
-
text: buildOmittedImageAttachmentNotice(omittedImageAttachmentCount)
|
|
9898
|
-
});
|
|
9899
|
-
}
|
|
9900
|
-
for (const attachment of context.userAttachments ?? []) {
|
|
9901
|
-
if (attachment.promptText) {
|
|
9902
|
-
userContentParts.push({
|
|
9903
|
-
type: "text",
|
|
9904
|
-
text: attachment.promptText
|
|
9905
|
-
});
|
|
9906
|
-
} else if (attachment.mediaType.startsWith("image/")) {
|
|
9907
|
-
if (!attachment.data) {
|
|
9908
|
-
throw new Error("Image attachment is missing image data");
|
|
9909
|
-
}
|
|
9910
|
-
userContentParts.push({
|
|
9911
|
-
type: "image",
|
|
9912
|
-
data: attachment.data.toString("base64"),
|
|
9913
|
-
mimeType: attachment.mediaType
|
|
9914
|
-
});
|
|
9915
|
-
} else {
|
|
9916
|
-
if (!attachment.data) {
|
|
9917
|
-
throw new Error("Attachment is missing attachment data");
|
|
9918
|
-
}
|
|
9919
|
-
const promptAttachment = {
|
|
9920
|
-
data: attachment.data,
|
|
9921
|
-
mediaType: attachment.mediaType,
|
|
9922
|
-
filename: attachment.filename
|
|
9923
|
-
};
|
|
9924
|
-
userContentParts.push({
|
|
9925
|
-
type: "text",
|
|
9926
|
-
text: encodeNonImageAttachmentForPrompt(promptAttachment)
|
|
9927
|
-
});
|
|
9928
|
-
}
|
|
9929
|
-
}
|
|
9930
10124
|
const inputMessagesAttribute = serializeGenAiAttribute([
|
|
9931
10125
|
{
|
|
9932
10126
|
role: "system",
|
|
@@ -9937,21 +10131,8 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9937
10131
|
content: userContentParts.map((part) => toObservablePromptPart(part))
|
|
9938
10132
|
}
|
|
9939
10133
|
]);
|
|
9940
|
-
const
|
|
9941
|
-
|
|
9942
|
-
toolCalls.push(toolName);
|
|
9943
|
-
Promise.resolve(context.onToolCall?.(toolName)).catch((error) => {
|
|
9944
|
-
logWarn(
|
|
9945
|
-
"streaming_tool_call_error",
|
|
9946
|
-
{},
|
|
9947
|
-
{
|
|
9948
|
-
"error.message": error instanceof Error ? error.message : String(error),
|
|
9949
|
-
"gen_ai.tool.name": toolName
|
|
9950
|
-
},
|
|
9951
|
-
"Failed to deliver tool call event to stream coordinator"
|
|
9952
|
-
);
|
|
9953
|
-
});
|
|
9954
|
-
}
|
|
10134
|
+
const onToolCall = (toolName) => {
|
|
10135
|
+
toolCalls.push(toolName);
|
|
9955
10136
|
};
|
|
9956
10137
|
const baseAgentTools = createAgentTools(
|
|
9957
10138
|
tools,
|
|
@@ -9961,7 +10142,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9961
10142
|
sandboxExecutor,
|
|
9962
10143
|
capabilityRuntime,
|
|
9963
10144
|
pluginAuth,
|
|
9964
|
-
|
|
10145
|
+
onToolCall
|
|
9965
10146
|
);
|
|
9966
10147
|
const agentTools = [...baseAgentTools];
|
|
9967
10148
|
const syncMcpAgentTools = () => {
|
|
@@ -9975,7 +10156,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9975
10156
|
sandboxExecutor,
|
|
9976
10157
|
capabilityRuntime,
|
|
9977
10158
|
pluginAuth,
|
|
9978
|
-
|
|
10159
|
+
onToolCall
|
|
9979
10160
|
);
|
|
9980
10161
|
agentTools.length = 0;
|
|
9981
10162
|
agentTools.push(...baseAgentTools, ...mcpAgentTools);
|
|
@@ -9986,6 +10167,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9986
10167
|
initialState: {
|
|
9987
10168
|
systemPrompt: baseInstructions,
|
|
9988
10169
|
model: resolveGatewayModel(botConfig.modelId),
|
|
10170
|
+
thinkingLevel: toAgentThinkingLevel(thinkingSelection.thinkingLevel),
|
|
9989
10171
|
tools: agentTools
|
|
9990
10172
|
}
|
|
9991
10173
|
});
|
|
@@ -10073,6 +10255,9 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
10073
10255
|
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
10074
10256
|
"gen_ai.operation.name": "invoke_agent",
|
|
10075
10257
|
"gen_ai.request.model": botConfig.modelId,
|
|
10258
|
+
...thinkingSelection ? {
|
|
10259
|
+
"app.ai.reasoning_effort": thinkingSelection.thinkingLevel
|
|
10260
|
+
} : {},
|
|
10076
10261
|
"app.ai.turn_timeout_ms": botConfig.turnTimeoutMs
|
|
10077
10262
|
},
|
|
10078
10263
|
"Agent turn timed out and was aborted"
|
|
@@ -10117,6 +10302,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
10117
10302
|
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
10118
10303
|
"gen_ai.operation.name": "invoke_agent",
|
|
10119
10304
|
"gen_ai.request.model": botConfig.modelId,
|
|
10305
|
+
"app.ai.reasoning_effort": thinkingSelection.thinkingLevel,
|
|
10120
10306
|
...inputMessagesAttribute ? { "gen_ai.input.messages": inputMessagesAttribute } : {}
|
|
10121
10307
|
}
|
|
10122
10308
|
);
|
|
@@ -10148,6 +10334,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
10148
10334
|
shouldTrace,
|
|
10149
10335
|
spanContext,
|
|
10150
10336
|
usage: turnUsage,
|
|
10337
|
+
thinkingSelection,
|
|
10151
10338
|
correlation: context.correlation,
|
|
10152
10339
|
assistantUserName: context.assistant?.userName
|
|
10153
10340
|
});
|
|
@@ -10234,6 +10421,9 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
10234
10421
|
outcome: "provider_error",
|
|
10235
10422
|
modelId: botConfig.modelId,
|
|
10236
10423
|
assistantMessageCount: 0,
|
|
10424
|
+
...thinkingSelection ? {
|
|
10425
|
+
thinkingLevel: thinkingSelection.thinkingLevel
|
|
10426
|
+
} : {},
|
|
10237
10427
|
toolCalls: [],
|
|
10238
10428
|
toolResultCount: 0,
|
|
10239
10429
|
toolErrorCount: 0,
|
|
@@ -12296,14 +12486,14 @@ async function POST(request, waitUntil) {
|
|
|
12296
12486
|
}
|
|
12297
12487
|
|
|
12298
12488
|
// src/chat/services/subscribed-decision.ts
|
|
12299
|
-
import { z } from "zod";
|
|
12300
|
-
var replyDecisionSchema =
|
|
12301
|
-
should_reply:
|
|
12302
|
-
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(
|
|
12303
12493
|
"Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
|
|
12304
12494
|
),
|
|
12305
|
-
confidence:
|
|
12306
|
-
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.")
|
|
12307
12497
|
});
|
|
12308
12498
|
var ROUTER_CONFIDENCE_THRESHOLD = 0.8;
|
|
12309
12499
|
var LEADING_SLACK_MENTION_RE = /^\s*<@([A-Z0-9]+)(?:\|([^>]+))?>[\s,:-]*/i;
|
|
@@ -13993,7 +14183,7 @@ function createReplyToThread(deps) {
|
|
|
13993
14183
|
slackChannelId: channelId,
|
|
13994
14184
|
runId,
|
|
13995
14185
|
assistantUserName: botConfig.userName,
|
|
13996
|
-
modelId:
|
|
14186
|
+
modelId: reply.diagnostics.modelId
|
|
13997
14187
|
};
|
|
13998
14188
|
const diagnosticsAttributes = {
|
|
13999
14189
|
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
@@ -14004,6 +14194,9 @@ function createReplyToThread(deps) {
|
|
|
14004
14194
|
"app.ai.tool_error_results": reply.diagnostics.toolErrorCount,
|
|
14005
14195
|
"app.ai.tool_call_count": reply.diagnostics.toolCalls.length,
|
|
14006
14196
|
"app.ai.used_primary_text": reply.diagnostics.usedPrimaryText,
|
|
14197
|
+
...reply.diagnostics.thinkingLevel ? {
|
|
14198
|
+
"app.ai.reasoning_effort": reply.diagnostics.thinkingLevel
|
|
14199
|
+
} : {},
|
|
14007
14200
|
...reply.diagnostics.stopReason ? {
|
|
14008
14201
|
"gen_ai.response.finish_reasons": [
|
|
14009
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(
|