@sentry/junior 0.121.0 → 0.122.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/{agent-hooks-CQDGDBCP.js → agent-hooks-HJMLQLCB.js} +8 -8
- package/dist/api.js +14 -14
- package/dist/app.js +604 -997
- package/dist/{catalog-runtime-AD3YNTTM.js → catalog-runtime-CYPZUYJD.js} +5 -5
- package/dist/chat/agent/index.d.ts +19 -2
- package/dist/chat/agent/request.d.ts +8 -8
- package/dist/chat/agent/resume.d.ts +1 -3
- package/dist/chat/agent/retry-usage.d.ts +8 -0
- package/dist/chat/agent/skills.d.ts +0 -9
- package/dist/chat/conversations/messages.d.ts +7 -0
- package/dist/chat/conversations/projection.d.ts +16 -0
- package/dist/chat/logging.d.ts +46 -13
- package/dist/chat/runtime/processing-reaction.d.ts +2 -4
- package/dist/chat/runtime/slack-runtime.d.ts +2 -2
- package/dist/chat/services/assistant-reply.d.ts +16 -0
- package/dist/chat/services/empty-output-continuation.d.ts +20 -0
- package/dist/chat/services/turn-failure-response.d.ts +1 -3
- package/dist/chat/services/turn-result.d.ts +0 -5
- package/dist/chat/services/turn-session-record.d.ts +0 -11
- package/dist/chat/tool-support/zod-tool.d.ts +11 -6
- package/dist/chat/tools/execute-tool.d.ts +1 -33
- package/dist/chat/tools/execution/tool-error-handler.d.ts +2 -2
- package/dist/chat/tools/query-conversation-events.d.ts +3 -1
- package/dist/chat/tools/sandbox/bash.d.ts +1 -33
- package/dist/chat/tools/sandbox/edit-file.d.ts +1 -33
- package/dist/chat/tools/sandbox/find-files.d.ts +1 -33
- package/dist/chat/tools/sandbox/grep.d.ts +1 -33
- package/dist/chat/tools/sandbox/list-dir.d.ts +1 -33
- package/dist/chat/tools/sandbox/read-file.d.ts +1 -33
- package/dist/chat/tools/sandbox/write-file.d.ts +1 -33
- package/dist/{chunk-IDXLBKPS.js → chunk-2RFM7STT.js} +11 -22
- package/dist/{chunk-XDRGYDED.js → chunk-32FPGM2V.js} +1 -1
- package/dist/{chunk-JZ47AFSH.js → chunk-4SPRQJOW.js} +37 -45
- package/dist/{chunk-KLUMVJRQ.js → chunk-4TGVC42X.js} +133 -206
- package/dist/{chunk-UXQ5XSA2.js → chunk-BDE5RZVF.js} +2 -2
- package/dist/{chunk-ITMEXX5H.js → chunk-CYW4M6IV.js} +4 -4
- package/dist/{chunk-254MFDOF.js → chunk-DOB5RVMH.js} +2 -2
- package/dist/{chunk-TRECK7RV.js → chunk-E5SRLZQV.js} +14 -29
- package/dist/{chunk-LE77HHF3.js → chunk-GFTZKOTP.js} +1 -1
- package/dist/{chunk-ET2SDCNV.js → chunk-GN6WW7WR.js} +16 -31
- package/dist/{chunk-D2EMOH3N.js → chunk-ISQYBTPG.js} +3 -3
- package/dist/{chunk-IK4QSS5H.js → chunk-L2KJ2GNL.js} +1 -1
- package/dist/{chunk-VWBKDPMQ.js → chunk-NIJG6G6X.js} +472 -684
- package/dist/{chunk-Z2XXPUZG.js → chunk-NNGYYGX5.js} +2061 -2015
- package/dist/{chunk-WUP7NWMP.js → chunk-OKUZIXQM.js} +1 -1
- package/dist/{chunk-HDFGNU5E.js → chunk-S7G34U75.js} +3 -1
- package/dist/{chunk-UURFXX66.js → chunk-TZVZCIYL.js} +1 -1
- package/dist/{chunk-7HYV7KFM.js → chunk-USKP7IM2.js} +49 -92
- package/dist/{chunk-JYDIBXFY.js → chunk-V6XPIKYA.js} +13 -19
- package/dist/{chunk-3DBMANUI.js → chunk-VCC7XFX2.js} +22 -45
- package/dist/cli/chat.js +22 -22
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +11 -11
- package/dist/cli/snapshot-create.js +9 -9
- package/dist/cli/upgrade.js +6 -6
- package/dist/{db-7HQT2SXQ.js → db-E6O2DXUQ.js} +6 -6
- package/dist/instrumentation.js +3 -3
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-VHTUCNHK.js → oauth-callback-server-6SCPUFFD.js} +15 -15
- package/dist/{runner-3ONPZRED.js → runner-JFKCMVVY.js} +62 -51
- package/dist/{skills-WGAYGGPA.js → skills-RD66F2OB.js} +6 -6
- package/dist/{validation-ZIWNBG4D.js → validation-XVRNX6IU.js} +6 -6
- package/dist/version.js +1 -1
- package/package.json +8 -8
|
@@ -30,15 +30,18 @@ import {
|
|
|
30
30
|
toMcpProviderError,
|
|
31
31
|
toolInvocationDestination,
|
|
32
32
|
uploadFilesToConversation
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-VCC7XFX2.js";
|
|
34
34
|
import {
|
|
35
35
|
CooperativeTurnYieldError,
|
|
36
36
|
JUNIOR_THREAD_STATE_TTL_MS,
|
|
37
|
+
NO_REPLY_MARKER,
|
|
37
38
|
TURN_CONTEXT_TAG,
|
|
38
39
|
TurnInputCommitLostError,
|
|
39
40
|
TurnSliceLimitExceededError,
|
|
40
41
|
abandonReplacedPendingAuth,
|
|
41
42
|
canReusePendingAuthLink,
|
|
43
|
+
containsNoReplyMarker,
|
|
44
|
+
decideReply,
|
|
42
45
|
estimateTextTokens,
|
|
43
46
|
extractAssistantText,
|
|
44
47
|
getAgentContextCompactionTriggerTokens,
|
|
@@ -49,6 +52,7 @@ import {
|
|
|
49
52
|
historyItemFromPiMessage,
|
|
50
53
|
isAssistantMessage,
|
|
51
54
|
isContinuablePiBoundary,
|
|
55
|
+
isNoReplyMarker,
|
|
52
56
|
isToolResultError,
|
|
53
57
|
isToolResultMessage,
|
|
54
58
|
isTurnInputCommitLostError,
|
|
@@ -69,10 +73,11 @@ import {
|
|
|
69
73
|
recordToolExecutionStarted,
|
|
70
74
|
recordTurnRoute,
|
|
71
75
|
retainRuntimeTurnContext,
|
|
76
|
+
sanitizeAssistantText,
|
|
72
77
|
stripRuntimeTurnContext,
|
|
73
78
|
trimTrailingAssistantMessages,
|
|
74
79
|
updateConversationStats
|
|
75
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-NNGYYGX5.js";
|
|
76
81
|
import {
|
|
77
82
|
parseSandboxEgressAuthRequiredSignal,
|
|
78
83
|
parseSandboxEgressPermissionDeniedSignal,
|
|
@@ -96,10 +101,10 @@ import {
|
|
|
96
101
|
runNonInteractiveCommand,
|
|
97
102
|
throwSandboxOperationError,
|
|
98
103
|
wrapSandboxSetupError
|
|
99
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-CYW4M6IV.js";
|
|
100
105
|
import {
|
|
101
106
|
incrementStat
|
|
102
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-32FPGM2V.js";
|
|
103
108
|
import {
|
|
104
109
|
addAgentTurnUsage,
|
|
105
110
|
hasAgentTurnUsage
|
|
@@ -121,7 +126,7 @@ import {
|
|
|
121
126
|
normalizeSlackConversationId,
|
|
122
127
|
resolveChannelCapabilities,
|
|
123
128
|
withSlackRetries
|
|
124
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-USKP7IM2.js";
|
|
125
130
|
import {
|
|
126
131
|
KNOWN_CONVERSATION_EVENT_TYPES,
|
|
127
132
|
contextProvenance,
|
|
@@ -130,7 +135,7 @@ import {
|
|
|
130
135
|
getConversationStore,
|
|
131
136
|
instructionActors,
|
|
132
137
|
instructionProvenanceFor
|
|
133
|
-
} from "./chunk-
|
|
138
|
+
} from "./chunk-DOB5RVMH.js";
|
|
134
139
|
import {
|
|
135
140
|
SANDBOX_DATA_ROOT,
|
|
136
141
|
SANDBOX_SKILLS_ROOT,
|
|
@@ -140,7 +145,7 @@ import {
|
|
|
140
145
|
sandboxSkillFile,
|
|
141
146
|
sandboxSkillPathResolution,
|
|
142
147
|
sleep
|
|
143
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-TZVZCIYL.js";
|
|
144
149
|
import {
|
|
145
150
|
ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
|
|
146
151
|
COMPACTION_SUMMARY_PREFIX,
|
|
@@ -171,7 +176,7 @@ import {
|
|
|
171
176
|
renderCurrentInstruction,
|
|
172
177
|
resolveGatewayModel,
|
|
173
178
|
unwrapCurrentInstruction
|
|
174
|
-
} from "./chunk-
|
|
179
|
+
} from "./chunk-2RFM7STT.js";
|
|
175
180
|
import {
|
|
176
181
|
canExposeConversationPayload,
|
|
177
182
|
parseSlackThreadId,
|
|
@@ -182,16 +187,16 @@ import {
|
|
|
182
187
|
toGenAiMessagesTraceAttributes,
|
|
183
188
|
toGenAiPayloadMetadata,
|
|
184
189
|
toGenAiPayloadTraceAttributes
|
|
185
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-S7G34U75.js";
|
|
186
191
|
import {
|
|
187
192
|
discoverSkills,
|
|
188
193
|
findSkillByName,
|
|
189
194
|
loadSkillsByName,
|
|
190
195
|
parseSkillInvocation
|
|
191
|
-
} from "./chunk-
|
|
196
|
+
} from "./chunk-E5SRLZQV.js";
|
|
192
197
|
import {
|
|
193
198
|
pluginCatalogRuntime
|
|
194
|
-
} from "./chunk-
|
|
199
|
+
} from "./chunk-OKUZIXQM.js";
|
|
195
200
|
import {
|
|
196
201
|
CredentialUnavailableError,
|
|
197
202
|
OAuthProviderError,
|
|
@@ -199,7 +204,7 @@ import {
|
|
|
199
204
|
getOAuthProviderErrorAttributes,
|
|
200
205
|
resolveAuthTokenPlaceholder,
|
|
201
206
|
resolvePluginCommandEnv
|
|
202
|
-
} from "./chunk-
|
|
207
|
+
} from "./chunk-GN6WW7WR.js";
|
|
203
208
|
import {
|
|
204
209
|
credentialUserSubjectId
|
|
205
210
|
} from "./chunk-W3U3YQYI.js";
|
|
@@ -223,7 +228,7 @@ import {
|
|
|
223
228
|
summarizeMessageText,
|
|
224
229
|
withLogContext,
|
|
225
230
|
withSpan
|
|
226
|
-
} from "./chunk-
|
|
231
|
+
} from "./chunk-4SPRQJOW.js";
|
|
227
232
|
import {
|
|
228
233
|
parseSlackChannelId,
|
|
229
234
|
parseSlackMessageTs,
|
|
@@ -320,7 +325,9 @@ function shouldPropagateSandboxEgressTrace(host, config = {}) {
|
|
|
320
325
|
}
|
|
321
326
|
|
|
322
327
|
// src/chat/agent/index.ts
|
|
323
|
-
import {
|
|
328
|
+
import {
|
|
329
|
+
Agent
|
|
330
|
+
} from "@earendil-works/pi-agent-core";
|
|
324
331
|
|
|
325
332
|
// src/chat/sandbox/skill-sandbox.ts
|
|
326
333
|
import fs from "fs/promises";
|
|
@@ -661,103 +668,6 @@ function shouldEmitDevAgentTrace() {
|
|
|
661
668
|
|
|
662
669
|
// src/chat/services/turn-result.ts
|
|
663
670
|
import { isRetryableAssistantError } from "@earendil-works/pi-ai";
|
|
664
|
-
|
|
665
|
-
// src/chat/no-reply.ts
|
|
666
|
-
var NO_REPLY_MARKER = "[[NO_REPLY]]";
|
|
667
|
-
function isNoReplyMarker(text) {
|
|
668
|
-
return text.trim() === NO_REPLY_MARKER;
|
|
669
|
-
}
|
|
670
|
-
function containsNoReplyMarker(text) {
|
|
671
|
-
return text.includes(NO_REPLY_MARKER);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
// src/chat/services/turn-result.ts
|
|
675
|
-
function isExecutionDeferralResponse(text) {
|
|
676
|
-
return /\b(want me to proceed|do you want me to proceed|shall i proceed|can i proceed|should i proceed|let me do that now|give me a moment|tag me again|fresh invocation)\b/i.test(
|
|
677
|
-
text
|
|
678
|
-
);
|
|
679
|
-
}
|
|
680
|
-
function isToolAccessDisclaimerResponse(text) {
|
|
681
|
-
return /\b(i (don't|do not) have access to (active )?tool|tool results came back empty|prior results .* empty|cannot access .*tool|need to (run|load) .*tool .* first)\b/i.test(
|
|
682
|
-
text
|
|
683
|
-
);
|
|
684
|
-
}
|
|
685
|
-
function isExecutionEscapeResponse(text) {
|
|
686
|
-
const trimmed = text.trim();
|
|
687
|
-
if (!trimmed) return false;
|
|
688
|
-
return isExecutionDeferralResponse(trimmed) || isToolAccessDisclaimerResponse(trimmed);
|
|
689
|
-
}
|
|
690
|
-
function parseJsonCandidate(text) {
|
|
691
|
-
const trimmed = text.trim();
|
|
692
|
-
if (!trimmed) return void 0;
|
|
693
|
-
try {
|
|
694
|
-
return JSON.parse(trimmed);
|
|
695
|
-
} catch {
|
|
696
|
-
const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
697
|
-
if (!fenced) return void 0;
|
|
698
|
-
try {
|
|
699
|
-
return JSON.parse(fenced[1]);
|
|
700
|
-
} catch {
|
|
701
|
-
return void 0;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
function isToolPayloadShape(payload) {
|
|
706
|
-
if (!payload || typeof payload !== "object") return false;
|
|
707
|
-
const record = payload;
|
|
708
|
-
const type = typeof record.type === "string" ? record.type.toLowerCase() : "";
|
|
709
|
-
if (type.startsWith("tool-")) return true;
|
|
710
|
-
if (type === "tool_use" || type === "tool_call" || type === "tool_result" || type === "tool_error")
|
|
711
|
-
return true;
|
|
712
|
-
const hasToolName = typeof record.toolName === "string" || typeof record.name === "string";
|
|
713
|
-
const hasToolInput = Object.prototype.hasOwnProperty.call(record, "input") || Object.prototype.hasOwnProperty.call(record, "args");
|
|
714
|
-
if (hasToolName && hasToolInput) return true;
|
|
715
|
-
return false;
|
|
716
|
-
}
|
|
717
|
-
function isRawToolPayloadResponse(text) {
|
|
718
|
-
const parsed = parseJsonCandidate(text);
|
|
719
|
-
if (Array.isArray(parsed)) {
|
|
720
|
-
return parsed.some((entry) => isToolPayloadShape(entry));
|
|
721
|
-
}
|
|
722
|
-
if (isToolPayloadShape(parsed)) {
|
|
723
|
-
return true;
|
|
724
|
-
}
|
|
725
|
-
return false;
|
|
726
|
-
}
|
|
727
|
-
var THINKING_XML_BLOCK_PATTERN = /[ \t]*<thinking\b[^>]*>[\s\S]*?<\/thinking>[ \t]*(?:\r?\n)?/gi;
|
|
728
|
-
var FENCED_CODE_BLOCK_PATTERN = /```[\s\S]*?```/g;
|
|
729
|
-
function stripThinkingXmlBlocks(text) {
|
|
730
|
-
let result = "";
|
|
731
|
-
let cursor = 0;
|
|
732
|
-
for (const match of text.matchAll(FENCED_CODE_BLOCK_PATTERN)) {
|
|
733
|
-
const start = match.index;
|
|
734
|
-
if (start === void 0) {
|
|
735
|
-
continue;
|
|
736
|
-
}
|
|
737
|
-
result += text.slice(cursor, start).replace(THINKING_XML_BLOCK_PATTERN, "");
|
|
738
|
-
result += match[0];
|
|
739
|
-
cursor = start + match[0].length;
|
|
740
|
-
}
|
|
741
|
-
result += text.slice(cursor).replace(THINKING_XML_BLOCK_PATTERN, "");
|
|
742
|
-
return result;
|
|
743
|
-
}
|
|
744
|
-
function getVisibleAssistantText(rawText) {
|
|
745
|
-
const text = stripThinkingXmlBlocks(rawText).trim();
|
|
746
|
-
if (!text || isNoReplyMarker(text) || containsNoReplyMarker(text) || isRawToolPayloadResponse(text)) {
|
|
747
|
-
return void 0;
|
|
748
|
-
}
|
|
749
|
-
return text;
|
|
750
|
-
}
|
|
751
|
-
function getAssistantMessageText(message) {
|
|
752
|
-
if (message.content.some((part) => part.type === "toolCall")) {
|
|
753
|
-
return void 0;
|
|
754
|
-
}
|
|
755
|
-
const text = getVisibleAssistantText(extractAssistantText(message));
|
|
756
|
-
if (!text) {
|
|
757
|
-
return void 0;
|
|
758
|
-
}
|
|
759
|
-
return isExecutionEscapeResponse(text) ? void 0 : text;
|
|
760
|
-
}
|
|
761
671
|
function buildTurnResult(input) {
|
|
762
672
|
const {
|
|
763
673
|
newMessages,
|
|
@@ -766,74 +676,53 @@ function buildTurnResult(input) {
|
|
|
766
676
|
sandboxRef,
|
|
767
677
|
durationMs,
|
|
768
678
|
shouldTrace,
|
|
769
|
-
spanContext,
|
|
770
679
|
usage,
|
|
771
680
|
executionProfile,
|
|
772
|
-
assistantUserName,
|
|
773
681
|
modelId
|
|
774
682
|
} = input;
|
|
775
683
|
const toolResults = newMessages.filter(isToolResultMessage);
|
|
776
684
|
const assistantMessages = newMessages.filter(isAssistantMessage);
|
|
777
685
|
const terminalAssistantMessages = getTerminalAssistantMessages(newMessages);
|
|
778
|
-
const rawPrimaryText =
|
|
686
|
+
const rawPrimaryText = sanitizeAssistantText(
|
|
779
687
|
terminalAssistantMessages.map((message) => extractAssistantText(message)).join("\n\n")
|
|
780
688
|
).trim();
|
|
781
689
|
const exactNoReplyMarker = isNoReplyMarker(rawPrimaryText);
|
|
782
690
|
const mixedNoReplyMarker = !exactNoReplyMarker && containsNoReplyMarker(rawPrimaryText);
|
|
783
691
|
const noReplyRequested = exactNoReplyMarker || mixedNoReplyMarker;
|
|
784
|
-
const primaryText = noReplyRequested ? "" : terminalAssistantMessages.map((message) =>
|
|
692
|
+
const primaryText = noReplyRequested ? "" : terminalAssistantMessages.map((message) => decideReply(message)).filter(
|
|
693
|
+
(output) => output.kind === "deliver"
|
|
694
|
+
).map((output) => output.text).join("\n\n");
|
|
785
695
|
const toolErrorCount = toolResults.filter((result) => result.isError).length;
|
|
786
696
|
const reactionPerformed = toolResults.some(
|
|
787
697
|
(result) => !isToolResultError(result) && normalizeToolNameFromResult(result) === "addReaction"
|
|
788
698
|
);
|
|
789
699
|
const completedWithoutTerminalText = noReplyRequested;
|
|
790
|
-
const resultLogContext = {
|
|
791
|
-
...spanContext,
|
|
792
|
-
assistantUserName,
|
|
793
|
-
modelId
|
|
794
|
-
};
|
|
795
700
|
const lastAssistant = terminalAssistantMessages.at(-1);
|
|
796
701
|
const stopReason = typeof lastAssistant?.stopReason === "string" ? lastAssistant.stopReason : void 0;
|
|
797
702
|
const errorMessage = typeof lastAssistant?.errorMessage === "string" ? lastAssistant.errorMessage : void 0;
|
|
798
703
|
const isProviderError = stopReason === "error";
|
|
799
704
|
if (exactNoReplyMarker) {
|
|
800
705
|
const markerCategory = reactionPerformed ? "reaction" : "none";
|
|
801
|
-
const markerContext = resultLogContext;
|
|
802
706
|
const markerAttributes = {
|
|
803
707
|
"app.ai.no_reply_marker": true,
|
|
804
708
|
"app.ai.no_reply_marker_category": markerCategory,
|
|
805
709
|
"app.ai.no_reply_marker_accepted": !isProviderError
|
|
806
710
|
};
|
|
807
711
|
if (!isProviderError) {
|
|
808
|
-
logInfo(
|
|
809
|
-
"ai_no_reply_marker_accepted",
|
|
810
|
-
markerContext,
|
|
811
|
-
markerAttributes,
|
|
812
|
-
"No-reply marker suppressed visible thread text"
|
|
813
|
-
);
|
|
712
|
+
logInfo("ai.no_reply_marker.accepted", markerAttributes);
|
|
814
713
|
}
|
|
815
714
|
} else if (mixedNoReplyMarker) {
|
|
816
|
-
logWarn(
|
|
817
|
-
"
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
"app.ai.no_reply_marker": true,
|
|
821
|
-
"app.ai.no_reply_marker_mode": "mixed"
|
|
822
|
-
},
|
|
823
|
-
"No-reply marker appeared with visible assistant text"
|
|
824
|
-
);
|
|
715
|
+
logWarn("ai.no_reply_marker.mixed_text", {
|
|
716
|
+
"app.ai.no_reply_marker": true,
|
|
717
|
+
"app.ai.no_reply_marker_mode": "mixed"
|
|
718
|
+
});
|
|
825
719
|
}
|
|
826
720
|
if (!primaryText && !completedWithoutTerminalText && !isProviderError) {
|
|
827
|
-
logWarn(
|
|
828
|
-
"
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
"app.ai.tool_error_results": toolErrorCount,
|
|
833
|
-
"app.ai.generated_files": input.generatedFileCount
|
|
834
|
-
},
|
|
835
|
-
"Model returned empty text response"
|
|
836
|
-
);
|
|
721
|
+
logWarn("ai.model_response.empty", {
|
|
722
|
+
"app.ai.tool_results": toolResults.length,
|
|
723
|
+
"app.ai.tool_error_results": toolErrorCount,
|
|
724
|
+
"app.ai.generated_files": input.generatedFileCount
|
|
725
|
+
});
|
|
837
726
|
}
|
|
838
727
|
const usedPrimaryText = Boolean(rawPrimaryText);
|
|
839
728
|
let outcome;
|
|
@@ -844,24 +733,19 @@ function buildTurnResult(input) {
|
|
|
844
733
|
} else {
|
|
845
734
|
outcome = "execution_failure";
|
|
846
735
|
}
|
|
847
|
-
const
|
|
736
|
+
const suppressedPrimaryText = Boolean(
|
|
848
737
|
rawPrimaryText && !noReplyRequested && !primaryText
|
|
849
738
|
);
|
|
850
|
-
const resolvedOutcome =
|
|
739
|
+
const resolvedOutcome = suppressedPrimaryText ? "execution_failure" : outcome;
|
|
851
740
|
if (shouldTrace) {
|
|
852
|
-
logInfo(
|
|
853
|
-
"
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
"app.ai.assistant_messages": assistantMessages.length,
|
|
861
|
-
...stopReason ? { "gen_ai.response.finish_reasons": [stopReason] } : {}
|
|
862
|
-
},
|
|
863
|
-
"Agent message sent"
|
|
864
|
-
);
|
|
741
|
+
logInfo("agent.message.generated", {
|
|
742
|
+
"app.message.kind": "assistant_outbound",
|
|
743
|
+
"app.message.length": primaryText.length,
|
|
744
|
+
"app.message.output": summarizeMessageText(primaryText),
|
|
745
|
+
"app.ai.outcome": resolvedOutcome,
|
|
746
|
+
"app.ai.assistant_messages": assistantMessages.length,
|
|
747
|
+
...stopReason ? { "gen_ai.response.finish_reasons": [stopReason] } : {}
|
|
748
|
+
});
|
|
865
749
|
}
|
|
866
750
|
const resolvedDiagnostics = {
|
|
867
751
|
outcome: resolvedOutcome,
|
|
@@ -924,6 +808,45 @@ function nextProviderRetry(args) {
|
|
|
924
808
|
return { delayMs, messages };
|
|
925
809
|
}
|
|
926
810
|
|
|
811
|
+
// src/chat/services/empty-output-continuation.ts
|
|
812
|
+
function nextEmptyOutputContinuation(args) {
|
|
813
|
+
if (!hasCompactedConversationContext(args.messages)) {
|
|
814
|
+
return { kind: "none" };
|
|
815
|
+
}
|
|
816
|
+
if (args.lastAssistant?.stopReason === "error" || args.lastAssistant?.stopReason === "aborted") {
|
|
817
|
+
return { kind: "none" };
|
|
818
|
+
}
|
|
819
|
+
if (args.lastAssistant && decideReply(args.lastAssistant).kind !== "empty") {
|
|
820
|
+
return { kind: "none" };
|
|
821
|
+
}
|
|
822
|
+
if (args.attempt > 0) {
|
|
823
|
+
return { kind: "exhausted" };
|
|
824
|
+
}
|
|
825
|
+
if (!args.lastAssistant) {
|
|
826
|
+
return isContinuablePiBoundary(args.messages) ? {
|
|
827
|
+
kind: "retry",
|
|
828
|
+
messages: [...args.messages]
|
|
829
|
+
} : { kind: "exhausted" };
|
|
830
|
+
}
|
|
831
|
+
if (args.messages.at(-1) !== args.lastAssistant) {
|
|
832
|
+
return { kind: "exhausted" };
|
|
833
|
+
}
|
|
834
|
+
const messages = args.messages.slice(0, -1);
|
|
835
|
+
return isContinuablePiBoundary(messages) ? { kind: "retry", messages } : { kind: "exhausted" };
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/chat/agent/retry-usage.ts
|
|
839
|
+
function getDiscardedRetryUsage(messages, retryMessages) {
|
|
840
|
+
const keepsExactPrefix = retryMessages.length <= messages.length && retryMessages.every((message, index) => message === messages[index]);
|
|
841
|
+
if (!keepsExactPrefix) {
|
|
842
|
+
throw new Error("Agent retry must retain an exact message prefix");
|
|
843
|
+
}
|
|
844
|
+
const usage = extractGenAiUsageSummary(
|
|
845
|
+
...messages.slice(retryMessages.length).filter(isAssistantMessage)
|
|
846
|
+
);
|
|
847
|
+
return hasAgentTurnUsage(usage) ? usage : void 0;
|
|
848
|
+
}
|
|
849
|
+
|
|
927
850
|
// src/chat/tool-support/structured-result.ts
|
|
928
851
|
import { z } from "zod";
|
|
929
852
|
var juniorToolContinuationSchema = z.object({
|
|
@@ -1262,20 +1185,9 @@ async function classifyTurn(args) {
|
|
|
1262
1185
|
source: "router"
|
|
1263
1186
|
};
|
|
1264
1187
|
} catch (error) {
|
|
1265
|
-
logWarn(
|
|
1266
|
-
"
|
|
1267
|
-
|
|
1268
|
-
messageConversationId: args.metadata.threadId,
|
|
1269
|
-
destinationName: args.metadata.channelId,
|
|
1270
|
-
userId: args.metadata.actorId,
|
|
1271
|
-
runId: args.metadata.runId,
|
|
1272
|
-
modelId: args.fastModelId
|
|
1273
|
-
},
|
|
1274
|
-
{
|
|
1275
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
1276
|
-
},
|
|
1277
|
-
"Turn router classifier failed; using the default route"
|
|
1278
|
-
);
|
|
1188
|
+
logWarn("turn.router.classifier.failed", {
|
|
1189
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
1190
|
+
});
|
|
1279
1191
|
return {
|
|
1280
1192
|
profile: STANDARD_MODEL_PROFILE,
|
|
1281
1193
|
reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
|
|
@@ -1509,18 +1421,13 @@ async function discoverRunSkills(args) {
|
|
|
1509
1421
|
const roots = [
|
|
1510
1422
|
...new Set(availableSkills.map((skill) => skill.skillPath))
|
|
1511
1423
|
].sort();
|
|
1512
|
-
logInfo(
|
|
1513
|
-
"
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
"app.plugin.count": plugins.length,
|
|
1520
|
-
"app.plugin.names": plugins.map((plugin) => plugin.manifest.name).sort()
|
|
1521
|
-
},
|
|
1522
|
-
"Discovered startup SOUL/skills/plugins"
|
|
1523
|
-
);
|
|
1424
|
+
logInfo("startup.discovery.completed", {
|
|
1425
|
+
"app.skill.count": availableSkills.length,
|
|
1426
|
+
"app.skill.names": availableSkills.map((skill) => skill.name).sort(),
|
|
1427
|
+
"app.file.directories": roots,
|
|
1428
|
+
"app.plugin.count": plugins.length,
|
|
1429
|
+
"app.plugin.names": plugins.map((plugin) => plugin.manifest.name).sort()
|
|
1430
|
+
});
|
|
1524
1431
|
}
|
|
1525
1432
|
return availableSkills;
|
|
1526
1433
|
}
|
|
@@ -1557,7 +1464,7 @@ function getLoggedMarkdownFiles() {
|
|
|
1557
1464
|
globalState.__juniorLoggedMarkdownFiles ??= /* @__PURE__ */ new Set();
|
|
1558
1465
|
return globalState.__juniorLoggedMarkdownFiles;
|
|
1559
1466
|
}
|
|
1560
|
-
function loadOptionalMarkdownFile(candidates, fileName) {
|
|
1467
|
+
function loadOptionalMarkdownFile(candidates, fileName, loadedEventName) {
|
|
1561
1468
|
for (const resolved of candidates) {
|
|
1562
1469
|
try {
|
|
1563
1470
|
const raw = fs2.readFileSync(resolved, "utf8").trim();
|
|
@@ -1566,14 +1473,9 @@ function loadOptionalMarkdownFile(candidates, fileName) {
|
|
|
1566
1473
|
const logKey = `${fileName}:${resolved}`;
|
|
1567
1474
|
if (!loggedMarkdownFiles.has(logKey)) {
|
|
1568
1475
|
loggedMarkdownFiles.add(logKey);
|
|
1569
|
-
logInfo(
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
{
|
|
1573
|
-
"file.path": resolved
|
|
1574
|
-
},
|
|
1575
|
-
`Loaded ${fileName}`
|
|
1576
|
-
);
|
|
1476
|
+
logInfo(loadedEventName, {
|
|
1477
|
+
"file.path": resolved
|
|
1478
|
+
});
|
|
1577
1479
|
}
|
|
1578
1480
|
return raw;
|
|
1579
1481
|
}
|
|
@@ -1584,35 +1486,33 @@ function loadOptionalMarkdownFile(candidates, fileName) {
|
|
|
1584
1486
|
return null;
|
|
1585
1487
|
}
|
|
1586
1488
|
function loadSoul() {
|
|
1587
|
-
const soul = loadOptionalMarkdownFile(
|
|
1489
|
+
const soul = loadOptionalMarkdownFile(
|
|
1490
|
+
soulPathCandidates(),
|
|
1491
|
+
"SOUL.md",
|
|
1492
|
+
"soul.loaded"
|
|
1493
|
+
);
|
|
1588
1494
|
if (soul) {
|
|
1589
1495
|
return soul;
|
|
1590
1496
|
}
|
|
1591
|
-
logWarn(
|
|
1592
|
-
"
|
|
1593
|
-
|
|
1594
|
-
{
|
|
1595
|
-
"app.file.candidates": soulPathCandidates()
|
|
1596
|
-
},
|
|
1597
|
-
"SOUL.md not found; using built-in default personality"
|
|
1598
|
-
);
|
|
1497
|
+
logWarn("soul.load.defaulted", {
|
|
1498
|
+
"app.file.candidates": soulPathCandidates()
|
|
1499
|
+
});
|
|
1599
1500
|
return DEFAULT_SOUL;
|
|
1600
1501
|
}
|
|
1601
1502
|
function loadWorld() {
|
|
1602
|
-
return loadOptionalMarkdownFile(
|
|
1503
|
+
return loadOptionalMarkdownFile(
|
|
1504
|
+
worldPathCandidates(),
|
|
1505
|
+
"WORLD.md",
|
|
1506
|
+
"world.loaded"
|
|
1507
|
+
);
|
|
1603
1508
|
}
|
|
1604
1509
|
var JUNIOR_PERSONALITY = (() => {
|
|
1605
1510
|
try {
|
|
1606
1511
|
return loadSoul();
|
|
1607
1512
|
} catch (error) {
|
|
1608
|
-
logWarn(
|
|
1609
|
-
"
|
|
1610
|
-
|
|
1611
|
-
{
|
|
1612
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
1613
|
-
},
|
|
1614
|
-
"Failed to load SOUL.md; using built-in default personality"
|
|
1615
|
-
);
|
|
1513
|
+
logWarn("soul.load.failed", {
|
|
1514
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
1515
|
+
});
|
|
1616
1516
|
return DEFAULT_SOUL;
|
|
1617
1517
|
}
|
|
1618
1518
|
})();
|
|
@@ -1620,14 +1520,9 @@ var JUNIOR_WORLD = (() => {
|
|
|
1620
1520
|
try {
|
|
1621
1521
|
return loadWorld();
|
|
1622
1522
|
} catch (error) {
|
|
1623
|
-
logWarn(
|
|
1624
|
-
"
|
|
1625
|
-
|
|
1626
|
-
{
|
|
1627
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
1628
|
-
},
|
|
1629
|
-
"Failed to load WORLD.md; omitting world prompt context"
|
|
1630
|
-
);
|
|
1523
|
+
logWarn("world.load.failed", {
|
|
1524
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
1525
|
+
});
|
|
1631
1526
|
return null;
|
|
1632
1527
|
}
|
|
1633
1528
|
})();
|
|
@@ -1828,7 +1723,7 @@ var SAFETY_RULES = [
|
|
|
1828
1723
|
var FAILURE_RULES = [
|
|
1829
1724
|
"- For tool/runtime failures, run the named check before diagnosing and report the exact failed command plus stderr/exit code.",
|
|
1830
1725
|
"- If a fact cannot be verified after focused checks, say what you checked and what blocked a stronger answer.",
|
|
1831
|
-
"-
|
|
1726
|
+
"- Keep raw tool payloads and internal routing metadata out of the final answer."
|
|
1832
1727
|
];
|
|
1833
1728
|
function renderRuleSection(tag, lines) {
|
|
1834
1729
|
return [`<${tag}>`, ...lines, `</${tag}>`].join("\n");
|
|
@@ -2559,17 +2454,12 @@ ${usage}
|
|
|
2559
2454
|
updatedBy: deps.actorId,
|
|
2560
2455
|
source: "jr-rpc"
|
|
2561
2456
|
});
|
|
2562
|
-
logInfo(
|
|
2563
|
-
"
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
"app.config.source": entry.source ?? "jr-rpc",
|
|
2569
|
-
...deps.activeSkill?.name ? { "app.skill.name": deps.activeSkill.name } : {}
|
|
2570
|
-
},
|
|
2571
|
-
"Set channel configuration via jr-rpc"
|
|
2572
|
-
);
|
|
2457
|
+
logInfo("jr_rpc.config.updated", {
|
|
2458
|
+
"app.config.key": entry.key,
|
|
2459
|
+
"app.config.scope": entry.scope,
|
|
2460
|
+
"app.config.source": entry.source ?? "jr-rpc",
|
|
2461
|
+
...deps.activeSkill?.name ? { "app.skill.name": deps.activeSkill.name } : {}
|
|
2462
|
+
});
|
|
2573
2463
|
deps.onConfigurationValueChanged?.(entry.key, entry.value);
|
|
2574
2464
|
return commandResult({
|
|
2575
2465
|
stdout: {
|
|
@@ -2604,15 +2494,10 @@ ${usage}
|
|
|
2604
2494
|
}
|
|
2605
2495
|
const deleted = await configuration.unset(key);
|
|
2606
2496
|
if (deleted) {
|
|
2607
|
-
logInfo(
|
|
2608
|
-
"
|
|
2609
|
-
{}
|
|
2610
|
-
|
|
2611
|
-
"app.config.key": key,
|
|
2612
|
-
...deps.activeSkill?.name ? { "app.skill.name": deps.activeSkill.name } : {}
|
|
2613
|
-
},
|
|
2614
|
-
"Unset channel configuration via jr-rpc"
|
|
2615
|
-
);
|
|
2497
|
+
logInfo("jr_rpc.config.removed", {
|
|
2498
|
+
"app.config.key": key,
|
|
2499
|
+
...deps.activeSkill?.name ? { "app.skill.name": deps.activeSkill.name } : {}
|
|
2500
|
+
});
|
|
2616
2501
|
deps.onConfigurationValueChanged?.(key, void 0);
|
|
2617
2502
|
}
|
|
2618
2503
|
return commandResult({
|
|
@@ -3563,17 +3448,13 @@ function createSandboxRuntime(options) {
|
|
|
3563
3448
|
} : {},
|
|
3564
3449
|
...dependencyProfileHash ? { "app.sandbox.current_profile_hash": dependencyProfileHash } : {}
|
|
3565
3450
|
});
|
|
3566
|
-
logInfo(
|
|
3567
|
-
"
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
...dependencyProfileHash ? { "app.sandbox.current_profile_hash": dependencyProfileHash } : {}
|
|
3574
|
-
},
|
|
3575
|
-
"Dependency profile changed; discarding sandbox hint and creating fresh session"
|
|
3576
|
-
);
|
|
3451
|
+
logInfo("sandbox.hint.discarded", {
|
|
3452
|
+
"app.decision.reason": "dependency_profile_mismatch",
|
|
3453
|
+
...sandboxRef.profileHash ? {
|
|
3454
|
+
"app.sandbox.previous_profile_hash": sandboxRef.profileHash
|
|
3455
|
+
} : {},
|
|
3456
|
+
...dependencyProfileHash ? { "app.sandbox.current_profile_hash": dependencyProfileHash } : {}
|
|
3457
|
+
});
|
|
3577
3458
|
sandboxRef = void 0;
|
|
3578
3459
|
};
|
|
3579
3460
|
const tryReuseCachedSandbox = async () => {
|
|
@@ -4294,6 +4175,19 @@ import { z as z3 } from "zod";
|
|
|
4294
4175
|
function isContentOnlyToolResult(value) {
|
|
4295
4176
|
return value !== null && typeof value === "object" && Array.isArray(value.content) && !("details" in value);
|
|
4296
4177
|
}
|
|
4178
|
+
function isStructuredToolResultEnvelope(value) {
|
|
4179
|
+
return value !== null && typeof value === "object" && Array.isArray(value.content) && "details" in value;
|
|
4180
|
+
}
|
|
4181
|
+
function parseToolContent(content) {
|
|
4182
|
+
for (const item of content) {
|
|
4183
|
+
if (!item || typeof item !== "object" || (item.type === "text" ? typeof item.text !== "string" : item.type === "image" ? typeof item.data !== "string" || typeof item.mimeType !== "string" : true)) {
|
|
4184
|
+
throw new TypeError(
|
|
4185
|
+
"zodTool() content must contain valid text or image items."
|
|
4186
|
+
);
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
return content;
|
|
4190
|
+
}
|
|
4297
4191
|
function formatZodPath(path9) {
|
|
4298
4192
|
return path9.length > 0 ? path9.map(String).join(".") : "root";
|
|
4299
4193
|
}
|
|
@@ -4356,6 +4250,14 @@ function zodTool(definition) {
|
|
|
4356
4250
|
"zodTool() content-only tools must return { content } without details."
|
|
4357
4251
|
);
|
|
4358
4252
|
}
|
|
4253
|
+
if (isStructuredToolResultEnvelope(result)) {
|
|
4254
|
+
return {
|
|
4255
|
+
content: parseToolContent(result.content),
|
|
4256
|
+
details: outputSchema.parse(
|
|
4257
|
+
juniorToolResultSchema.parse(result.details)
|
|
4258
|
+
)
|
|
4259
|
+
};
|
|
4260
|
+
}
|
|
4359
4261
|
return outputSchema.parse(juniorToolResultSchema.parse(result));
|
|
4360
4262
|
}
|
|
4361
4263
|
} : {}
|
|
@@ -5434,15 +5336,10 @@ function createSandbox(options) {
|
|
|
5434
5336
|
if (runtime.sandboxRef()) {
|
|
5435
5337
|
return;
|
|
5436
5338
|
}
|
|
5437
|
-
logInfo(
|
|
5438
|
-
"
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
"app.sandbox.boot.trigger": trigger,
|
|
5442
|
-
...details
|
|
5443
|
-
},
|
|
5444
|
-
"Sandbox boot requested"
|
|
5445
|
-
);
|
|
5339
|
+
logInfo("sandbox.boot.requested", {
|
|
5340
|
+
"app.sandbox.boot.trigger": trigger,
|
|
5341
|
+
...details
|
|
5342
|
+
});
|
|
5446
5343
|
};
|
|
5447
5344
|
const executeBashTool = async (rawInput, command, context) => {
|
|
5448
5345
|
const env = parseEnv(rawInput.env);
|
|
@@ -6747,12 +6644,7 @@ var McpToolManager = class {
|
|
|
6747
6644
|
};
|
|
6748
6645
|
setSpanAttributes(errorAttributes);
|
|
6749
6646
|
if (error instanceof McpToolError) {
|
|
6750
|
-
logWarn(
|
|
6751
|
-
"mcp_tool_call_failed",
|
|
6752
|
-
{},
|
|
6753
|
-
errorAttributes,
|
|
6754
|
-
"MCP tool call failed"
|
|
6755
|
-
);
|
|
6647
|
+
logWarn("mcp.tool_call.failed", errorAttributes);
|
|
6756
6648
|
}
|
|
6757
6649
|
throw error;
|
|
6758
6650
|
}
|
|
@@ -6908,22 +6800,16 @@ async function enrichImagePrompt(rawPrompt) {
|
|
|
6908
6800
|
maxTokens: 1024
|
|
6909
6801
|
});
|
|
6910
6802
|
if (text && text.trim().length > 0) {
|
|
6911
|
-
logInfo(
|
|
6912
|
-
"
|
|
6913
|
-
|
|
6914
|
-
{ "app.image.enriched_prompt_length": text.trim().length },
|
|
6915
|
-
"Image prompt enriched with persona"
|
|
6916
|
-
);
|
|
6803
|
+
logInfo("image.prompt.enriched", {
|
|
6804
|
+
"app.image.enriched_prompt_length": text.trim().length
|
|
6805
|
+
});
|
|
6917
6806
|
return text.trim();
|
|
6918
6807
|
}
|
|
6919
6808
|
return rawPrompt;
|
|
6920
6809
|
} catch (error) {
|
|
6921
|
-
logWarn(
|
|
6922
|
-
"
|
|
6923
|
-
|
|
6924
|
-
{ "exception.message": String(error) },
|
|
6925
|
-
"Image prompt enrichment failed, using raw prompt"
|
|
6926
|
-
);
|
|
6810
|
+
logWarn("image.prompt.enrichment.failed", {
|
|
6811
|
+
"exception.message": String(error)
|
|
6812
|
+
});
|
|
6927
6813
|
return rawPrompt;
|
|
6928
6814
|
}
|
|
6929
6815
|
}
|
|
@@ -9002,18 +8888,13 @@ async function grantChannelCanvasAccess(canvasId, channelId) {
|
|
|
9002
8888
|
}
|
|
9003
8889
|
}
|
|
9004
8890
|
);
|
|
9005
|
-
} catch
|
|
9006
|
-
logWarn(
|
|
9007
|
-
"
|
|
9008
|
-
|
|
9009
|
-
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
"app.slack.canvas.channel_id_prefix": channelId.slice(0, 1),
|
|
9013
|
-
"app.slack.canvas.access_level": "write"
|
|
9014
|
-
},
|
|
9015
|
-
error instanceof Error ? error.message : "Failed to grant channel access to canvas"
|
|
9016
|
-
);
|
|
8891
|
+
} catch {
|
|
8892
|
+
logWarn("slack.canvas.access_set.failed", {
|
|
8893
|
+
"app.slack.action": "canvases.access.set",
|
|
8894
|
+
"app.slack.canvas.canvas_id_prefix": canvasId.slice(0, 1),
|
|
8895
|
+
"app.slack.canvas.channel_id_prefix": channelId.slice(0, 1),
|
|
8896
|
+
"app.slack.canvas.access_level": "write"
|
|
8897
|
+
});
|
|
9017
8898
|
}
|
|
9018
8899
|
}
|
|
9019
8900
|
async function writeCanvasMarkdown(input) {
|
|
@@ -9150,16 +9031,11 @@ function createSlackCanvasCreateTool(context, state) {
|
|
|
9150
9031
|
execute: async ({ title, markdown }) => {
|
|
9151
9032
|
const targetChannelId = context.destinationChannelId;
|
|
9152
9033
|
if (!isConversationScopedChannel(targetChannelId)) {
|
|
9153
|
-
logError(
|
|
9154
|
-
"
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
"messaging.destination.name": targetChannelId ?? "none",
|
|
9159
|
-
"app.slack.canvas.has_channel_context": Boolean(targetChannelId)
|
|
9160
|
-
},
|
|
9161
|
-
"Canvas create failed due to missing or invalid assistant channel context"
|
|
9162
|
-
);
|
|
9034
|
+
logError("slack.canvas.create.context_invalid", {
|
|
9035
|
+
"gen_ai.tool.name": "slackCanvasCreate",
|
|
9036
|
+
"messaging.destination.name": targetChannelId ?? "none",
|
|
9037
|
+
"app.slack.canvas.has_channel_context": Boolean(targetChannelId)
|
|
9038
|
+
});
|
|
9163
9039
|
throw new Error(
|
|
9164
9040
|
"Cannot create a canvas without an active assistant channel context (C/G/D)."
|
|
9165
9041
|
);
|
|
@@ -9292,15 +9168,10 @@ function createSlackCanvasEditTool(state) {
|
|
|
9292
9168
|
return response;
|
|
9293
9169
|
} catch (error) {
|
|
9294
9170
|
const message = error instanceof Error ? error.message : "canvas edit failed";
|
|
9295
|
-
logWarn(
|
|
9296
|
-
"
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
"gen_ai.tool.name": "slackCanvasEdit",
|
|
9300
|
-
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9301
|
-
},
|
|
9302
|
-
message
|
|
9303
|
-
);
|
|
9171
|
+
logWarn("slack.canvas.edit.failed", {
|
|
9172
|
+
"gen_ai.tool.name": "slackCanvasEdit",
|
|
9173
|
+
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9174
|
+
});
|
|
9304
9175
|
return {
|
|
9305
9176
|
ok: false,
|
|
9306
9177
|
status: "error",
|
|
@@ -9371,15 +9242,10 @@ function createSlackCanvasReadTool() {
|
|
|
9371
9242
|
};
|
|
9372
9243
|
} catch (error) {
|
|
9373
9244
|
const message = error instanceof Error ? error.message : "canvas read failed";
|
|
9374
|
-
logWarn(
|
|
9375
|
-
"
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
"gen_ai.tool.name": "slackCanvasRead",
|
|
9379
|
-
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9380
|
-
},
|
|
9381
|
-
message
|
|
9382
|
-
);
|
|
9245
|
+
logWarn("slack.canvas.read.failed", {
|
|
9246
|
+
"gen_ai.tool.name": "slackCanvasRead",
|
|
9247
|
+
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9248
|
+
});
|
|
9383
9249
|
return {
|
|
9384
9250
|
ok: false,
|
|
9385
9251
|
status: "error",
|
|
@@ -9438,15 +9304,10 @@ function createSlackCanvasWriteTool(state) {
|
|
|
9438
9304
|
return response;
|
|
9439
9305
|
} catch (error) {
|
|
9440
9306
|
const message = error instanceof Error ? error.message : "canvas write failed";
|
|
9441
|
-
logWarn(
|
|
9442
|
-
"
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
"gen_ai.tool.name": "slackCanvasWrite",
|
|
9446
|
-
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9447
|
-
},
|
|
9448
|
-
message
|
|
9449
|
-
);
|
|
9307
|
+
logWarn("slack.canvas.write.failed", {
|
|
9308
|
+
"gen_ai.tool.name": "slackCanvasWrite",
|
|
9309
|
+
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9310
|
+
});
|
|
9450
9311
|
return {
|
|
9451
9312
|
ok: false,
|
|
9452
9313
|
status: "error",
|
|
@@ -10494,6 +10355,10 @@ function createSystemTimeTool() {
|
|
|
10494
10355
|
import { z as z37 } from "zod";
|
|
10495
10356
|
var DEFAULT_LIMIT3 = 25;
|
|
10496
10357
|
var MAX_LIMIT = 100;
|
|
10358
|
+
var MAX_EVENT_DATA_BYTES = 4e3;
|
|
10359
|
+
var MAX_EVENTS_JSON_BYTES = 2e4;
|
|
10360
|
+
var MAX_IDENTITY_CHARS = 256;
|
|
10361
|
+
var textEncoder = new TextEncoder();
|
|
10497
10362
|
var CONVERSATION_EVENTS_TOOL_SOURCE = {
|
|
10498
10363
|
id: "conversation-events",
|
|
10499
10364
|
description: "Inspect Junior's durable conversation event log for debugging runtime behavior."
|
|
@@ -10507,7 +10372,7 @@ var projectedEventSchema = z37.object({
|
|
|
10507
10372
|
created_at: z37.iso.datetime().describe("When the event was recorded."),
|
|
10508
10373
|
idempotency_key: z37.string().min(1).optional().describe("Retry-stable event identity, when one was assigned."),
|
|
10509
10374
|
data: z37.record(z37.string(), z37.unknown()).describe(
|
|
10510
|
-
"Event
|
|
10375
|
+
"Event data. Oversized payloads are replaced by identifying fields, payload_omitted, and payload_json_bytes."
|
|
10511
10376
|
)
|
|
10512
10377
|
}).strict();
|
|
10513
10378
|
var queryConversationEventsOutputSchema = juniorToolResultSchema.extend({
|
|
@@ -10518,6 +10383,9 @@ var queryConversationEventsOutputSchema = juniorToolResultSchema.extend({
|
|
|
10518
10383
|
),
|
|
10519
10384
|
has_newer: z37.boolean().describe(
|
|
10520
10385
|
"Whether matching events exist after this page; request them with after_seq set to the last returned seq."
|
|
10386
|
+
),
|
|
10387
|
+
omitted_event_count: z37.number().int().nonnegative().optional().describe(
|
|
10388
|
+
"Fetched events omitted to keep this response bounded. Continue with the pagination cursor for the omitted direction."
|
|
10521
10389
|
)
|
|
10522
10390
|
});
|
|
10523
10391
|
function createQueryConversationEventsTool(context) {
|
|
@@ -10597,14 +10465,17 @@ function createQueryConversationEventsTool(context) {
|
|
|
10597
10465
|
...beforeSeq === void 0 ? {} : { beforeSeq },
|
|
10598
10466
|
...types === void 0 ? {} : { types }
|
|
10599
10467
|
});
|
|
10600
|
-
const
|
|
10468
|
+
const newestFirst = afterSeq === void 0;
|
|
10469
|
+
const projected = projectEventsForTool(page, { newestFirst });
|
|
10601
10470
|
return {
|
|
10602
10471
|
ok: true,
|
|
10603
10472
|
status: "success",
|
|
10604
10473
|
conversation_id: conversationId,
|
|
10605
|
-
events,
|
|
10606
|
-
has_older: page.hasOlder,
|
|
10607
|
-
has_newer: page.hasNewer
|
|
10474
|
+
events: projected.events,
|
|
10475
|
+
has_older: page.hasOlder || newestFirst && projected.omittedEventCount > 0,
|
|
10476
|
+
has_newer: page.hasNewer || !newestFirst && projected.omittedEventCount > 0,
|
|
10477
|
+
truncated: projected.omittedEventCount > 0,
|
|
10478
|
+
...projected.omittedEventCount > 0 ? { omitted_event_count: projected.omittedEventCount } : {}
|
|
10608
10479
|
};
|
|
10609
10480
|
}
|
|
10610
10481
|
});
|
|
@@ -10689,11 +10560,30 @@ function assertCanQueryConversationEvents(args) {
|
|
|
10689
10560
|
`Conversation events are not accessible: ${targetConversationId}`
|
|
10690
10561
|
);
|
|
10691
10562
|
}
|
|
10692
|
-
function projectEventsForTool(page) {
|
|
10693
|
-
|
|
10563
|
+
function projectEventsForTool(page, options) {
|
|
10564
|
+
const projected = page.events.map(projectEvent);
|
|
10565
|
+
const events = [];
|
|
10566
|
+
let jsonBytes = 2;
|
|
10567
|
+
const candidates = options.newestFirst ? [...projected].reverse() : projected;
|
|
10568
|
+
for (const event of candidates) {
|
|
10569
|
+
const eventBytes = jsonByteLength(event);
|
|
10570
|
+
const separatorBytes = events.length === 0 ? 0 : 1;
|
|
10571
|
+
if (jsonBytes + separatorBytes + eventBytes > MAX_EVENTS_JSON_BYTES) {
|
|
10572
|
+
break;
|
|
10573
|
+
}
|
|
10574
|
+
events.push(event);
|
|
10575
|
+
jsonBytes += separatorBytes + eventBytes;
|
|
10576
|
+
}
|
|
10577
|
+
if (options.newestFirst) {
|
|
10578
|
+
events.reverse();
|
|
10579
|
+
}
|
|
10580
|
+
return {
|
|
10581
|
+
events,
|
|
10582
|
+
omittedEventCount: projected.length - events.length
|
|
10583
|
+
};
|
|
10694
10584
|
}
|
|
10695
10585
|
function projectEvent(event) {
|
|
10696
|
-
const data = stripReplacementHistory(event.data);
|
|
10586
|
+
const data = boundEventData(stripReplacementHistory(event.data));
|
|
10697
10587
|
return {
|
|
10698
10588
|
seq: event.seq,
|
|
10699
10589
|
history_version: event.historyVersion,
|
|
@@ -10702,6 +10592,46 @@ function projectEvent(event) {
|
|
|
10702
10592
|
data
|
|
10703
10593
|
};
|
|
10704
10594
|
}
|
|
10595
|
+
function boundEventData(data) {
|
|
10596
|
+
const payloadJsonBytes = jsonByteLength(data);
|
|
10597
|
+
if (payloadJsonBytes <= MAX_EVENT_DATA_BYTES) {
|
|
10598
|
+
return data;
|
|
10599
|
+
}
|
|
10600
|
+
return {
|
|
10601
|
+
...eventIdentity(data),
|
|
10602
|
+
payload_omitted: true,
|
|
10603
|
+
payload_json_bytes: payloadJsonBytes
|
|
10604
|
+
};
|
|
10605
|
+
}
|
|
10606
|
+
function jsonByteLength(value) {
|
|
10607
|
+
return textEncoder.encode(JSON.stringify(value)).byteLength;
|
|
10608
|
+
}
|
|
10609
|
+
function eventIdentity(data) {
|
|
10610
|
+
const identityKeys = [
|
|
10611
|
+
"type",
|
|
10612
|
+
"originalType",
|
|
10613
|
+
"messageId",
|
|
10614
|
+
"role",
|
|
10615
|
+
"turnId",
|
|
10616
|
+
"toolCallId",
|
|
10617
|
+
"toolName",
|
|
10618
|
+
"subagentInvocationId",
|
|
10619
|
+
"subagentKind",
|
|
10620
|
+
"childConversationId",
|
|
10621
|
+
"outcome",
|
|
10622
|
+
"failureCode",
|
|
10623
|
+
"provider",
|
|
10624
|
+
"kind",
|
|
10625
|
+
"modelProfile",
|
|
10626
|
+
"modelId"
|
|
10627
|
+
];
|
|
10628
|
+
return Object.fromEntries(
|
|
10629
|
+
identityKeys.flatMap((key) => {
|
|
10630
|
+
const value = data[key];
|
|
10631
|
+
return typeof value === "string" ? [[key, value.slice(0, MAX_IDENTITY_CHARS)]] : [];
|
|
10632
|
+
})
|
|
10633
|
+
);
|
|
10634
|
+
}
|
|
10705
10635
|
function stripReplacementHistory(data) {
|
|
10706
10636
|
if (data.type === "unknown") {
|
|
10707
10637
|
return {
|
|
@@ -11368,18 +11298,12 @@ function createWebSearchTool(modelId, override) {
|
|
|
11368
11298
|
const message = formatSearchFailure(error);
|
|
11369
11299
|
const timeout = /timed out/i.test(message);
|
|
11370
11300
|
const retryable = !isAuthFailure(message);
|
|
11371
|
-
logException(
|
|
11372
|
-
|
|
11373
|
-
"
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
|
|
11377
|
-
"app.web_search.timeout": timeout,
|
|
11378
|
-
"app.web_search.retryable": retryable,
|
|
11379
|
-
"app.web_search.query": query
|
|
11380
|
-
},
|
|
11381
|
-
message
|
|
11382
|
-
);
|
|
11301
|
+
logException(error, "web.search.failed", {
|
|
11302
|
+
"gen_ai.tool.name": "webSearch",
|
|
11303
|
+
"app.web_search.timeout": timeout,
|
|
11304
|
+
"app.web_search.retryable": retryable,
|
|
11305
|
+
"app.web_search.query": query
|
|
11306
|
+
});
|
|
11383
11307
|
return {
|
|
11384
11308
|
ok: false,
|
|
11385
11309
|
status: "error",
|
|
@@ -12097,7 +12021,7 @@ function getToolErrorAttributes(error) {
|
|
|
12097
12021
|
...error.detailRule ? { "app.slack.detail_rule": error.detailRule } : {}
|
|
12098
12022
|
};
|
|
12099
12023
|
}
|
|
12100
|
-
function handleToolExecutionError(error, toolName, toolCallId, shouldTrace,
|
|
12024
|
+
function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, conversationPrivacy, setExecutionSpanAttributes) {
|
|
12101
12025
|
const errorType = getToolErrorType(error);
|
|
12102
12026
|
const errorMessage = getMcpAwareTelemetryMessage(error, conversationPrivacy);
|
|
12103
12027
|
const errorAttributes = {
|
|
@@ -12113,50 +12037,34 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
|
|
|
12113
12037
|
}
|
|
12114
12038
|
if (error instanceof PluginCredentialFailureError) {
|
|
12115
12039
|
if (shouldTrace) {
|
|
12116
|
-
logInfo(
|
|
12117
|
-
"
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
|
|
12124
|
-
"error.type": errorType
|
|
12125
|
-
},
|
|
12126
|
-
"Plugin credentials were rejected during tool execution"
|
|
12127
|
-
);
|
|
12040
|
+
logInfo("plugin.credential.rejected", {
|
|
12041
|
+
"app.credential.provider": error.provider,
|
|
12042
|
+
"gen_ai.operation.name": "execute_tool",
|
|
12043
|
+
"gen_ai.tool.name": toolName,
|
|
12044
|
+
...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
|
|
12045
|
+
"error.type": errorType
|
|
12046
|
+
});
|
|
12128
12047
|
}
|
|
12129
12048
|
throw error;
|
|
12130
12049
|
}
|
|
12131
12050
|
if (shouldTrace) {
|
|
12132
|
-
logWarn(
|
|
12133
|
-
"
|
|
12134
|
-
|
|
12135
|
-
{
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
...errorAttributes,
|
|
12140
|
-
"exception.message": errorMessage
|
|
12141
|
-
},
|
|
12142
|
-
"Agent tool call failed"
|
|
12143
|
-
);
|
|
12051
|
+
logWarn("agent.tool_call.failed", {
|
|
12052
|
+
"gen_ai.operation.name": "execute_tool",
|
|
12053
|
+
"gen_ai.tool.name": toolName,
|
|
12054
|
+
...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
|
|
12055
|
+
...errorAttributes,
|
|
12056
|
+
"exception.message": errorMessage
|
|
12057
|
+
});
|
|
12144
12058
|
}
|
|
12145
12059
|
const isExpectedToolFailure = error instanceof McpToolError || error instanceof ToolInputError || isPluginToolInputError(error);
|
|
12146
12060
|
if (!isExpectedToolFailure) {
|
|
12147
|
-
logException(
|
|
12148
|
-
|
|
12149
|
-
"
|
|
12150
|
-
{},
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
|
|
12155
|
-
...errorAttributes,
|
|
12156
|
-
...getToolErrorAttributes(error)
|
|
12157
|
-
},
|
|
12158
|
-
"Agent tool call failed"
|
|
12159
|
-
);
|
|
12061
|
+
logException(error, "agent.tool_call.failed", {
|
|
12062
|
+
"gen_ai.operation.name": "execute_tool",
|
|
12063
|
+
"gen_ai.tool.name": toolName,
|
|
12064
|
+
...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
|
|
12065
|
+
...errorAttributes,
|
|
12066
|
+
...getToolErrorAttributes(error)
|
|
12067
|
+
});
|
|
12160
12068
|
}
|
|
12161
12069
|
throw error;
|
|
12162
12070
|
}
|
|
@@ -12524,15 +12432,10 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
|
|
|
12524
12432
|
try {
|
|
12525
12433
|
await onToolResult?.(report);
|
|
12526
12434
|
} catch (error) {
|
|
12527
|
-
logWarn(
|
|
12528
|
-
"
|
|
12529
|
-
|
|
12530
|
-
|
|
12531
|
-
"gen_ai.tool.name": report.toolName,
|
|
12532
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
12533
|
-
},
|
|
12534
|
-
"Tool result observer failed"
|
|
12535
|
-
);
|
|
12435
|
+
logWarn("tool.result.observer.failed", {
|
|
12436
|
+
"gen_ai.tool.name": report.toolName,
|
|
12437
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
12438
|
+
});
|
|
12536
12439
|
}
|
|
12537
12440
|
};
|
|
12538
12441
|
const toolResultOk = (details) => {
|
|
@@ -12591,15 +12494,10 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
|
|
|
12591
12494
|
projectedPrivateResult = toolDef.privateTraceResult(resultAttributeValue);
|
|
12592
12495
|
hasProjectedPrivateResult = projectedPrivateResult !== void 0;
|
|
12593
12496
|
} catch (error) {
|
|
12594
|
-
logWarn(
|
|
12595
|
-
"
|
|
12596
|
-
|
|
12597
|
-
|
|
12598
|
-
"error.type": error instanceof Error ? error.name : typeof error,
|
|
12599
|
-
"gen_ai.tool.name": toolName
|
|
12600
|
-
},
|
|
12601
|
-
"Tool private trace projection failed"
|
|
12602
|
-
);
|
|
12497
|
+
logWarn("tool.private.trace_projection.failed", {
|
|
12498
|
+
"error.type": error instanceof Error ? error.name : typeof error,
|
|
12499
|
+
"gen_ai.tool.name": toolName
|
|
12500
|
+
});
|
|
12603
12501
|
}
|
|
12604
12502
|
}
|
|
12605
12503
|
const toolResultAttribute = effectiveConversationPrivacy === "private" && toolDef.privateTraceResult && !hasProjectedPrivateResult ? void 0 : serializeToolPayload(
|
|
@@ -12713,7 +12611,6 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
|
|
|
12713
12611
|
executionToolName,
|
|
12714
12612
|
toolCallId,
|
|
12715
12613
|
shouldTrace,
|
|
12716
|
-
spanContext,
|
|
12717
12614
|
effectiveConversationPrivacy,
|
|
12718
12615
|
setSpanAttributes2
|
|
12719
12616
|
);
|
|
@@ -13186,26 +13083,21 @@ function logSandboxEgressUpstreamRequest(input) {
|
|
|
13186
13083
|
if (!shouldLogSandboxEgressInfo()) {
|
|
13187
13084
|
return;
|
|
13188
13085
|
}
|
|
13189
|
-
logInfo(
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13199
|
-
|
|
13200
|
-
|
|
13201
|
-
|
|
13202
|
-
|
|
13203
|
-
|
|
13204
|
-
...routingAttributes(input.request, input.upstreamUrl),
|
|
13205
|
-
"app.sandbox.egress.upstream_ok": input.upstream.ok
|
|
13206
|
-
},
|
|
13207
|
-
`Sandbox egress ${input.request.method} ${input.upstreamUrl.hostname}${displayedUpstreamPath(input.upstreamUrl)} -> ${input.upstream.status}`
|
|
13208
|
-
);
|
|
13086
|
+
logInfo("sandbox.egress.upstream.requested", {
|
|
13087
|
+
...egressAttributes({
|
|
13088
|
+
egressId: input.egressId,
|
|
13089
|
+
grantAccess: input.grantAccess,
|
|
13090
|
+
grantName: input.grantName,
|
|
13091
|
+
grantReason: input.grantReason,
|
|
13092
|
+
host: input.upstreamUrl.hostname,
|
|
13093
|
+
method: input.request.method,
|
|
13094
|
+
path: input.upstreamUrl.pathname,
|
|
13095
|
+
provider: input.provider,
|
|
13096
|
+
status: input.upstream.status
|
|
13097
|
+
}),
|
|
13098
|
+
...routingAttributes(input.request, input.upstreamUrl),
|
|
13099
|
+
"app.sandbox.egress.upstream_ok": input.upstream.ok
|
|
13100
|
+
});
|
|
13209
13101
|
}
|
|
13210
13102
|
async function requestBodyBytes(request) {
|
|
13211
13103
|
if (request.method === "GET" || request.method === "HEAD" || request.body === null) {
|
|
@@ -13402,22 +13294,18 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13402
13294
|
});
|
|
13403
13295
|
} catch (error) {
|
|
13404
13296
|
if (isEgressPolicyDenied(error)) {
|
|
13405
|
-
logWarn(
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
...routingAttributes(request, upstreamUrl)
|
|
13418
|
-
},
|
|
13419
|
-
error.message
|
|
13420
|
-
);
|
|
13297
|
+
logWarn("sandbox.egress.policy.denied", {
|
|
13298
|
+
...egressAttributes({
|
|
13299
|
+
egressId: activeEgressId,
|
|
13300
|
+
host: upstreamUrl.hostname,
|
|
13301
|
+
method: request.method,
|
|
13302
|
+
path: upstreamUrl.pathname,
|
|
13303
|
+
provider,
|
|
13304
|
+
status: 403
|
|
13305
|
+
}),
|
|
13306
|
+
...routingAttributes(request, upstreamUrl),
|
|
13307
|
+
"app.sandbox.egress.policy.reason": error.message
|
|
13308
|
+
});
|
|
13421
13309
|
return policyDeniedResponse(error);
|
|
13422
13310
|
}
|
|
13423
13311
|
throw error;
|
|
@@ -13445,8 +13333,7 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13445
13333
|
});
|
|
13446
13334
|
const isAuthRequired = error.kind === "auth_required";
|
|
13447
13335
|
logWarn(
|
|
13448
|
-
isAuthRequired ? "
|
|
13449
|
-
{},
|
|
13336
|
+
isAuthRequired ? "sandbox.egress.credential.needed" : "sandbox.egress.credential.unavailable",
|
|
13450
13337
|
{
|
|
13451
13338
|
...egressAttributes({
|
|
13452
13339
|
egressId: activeEgressId,
|
|
@@ -13460,8 +13347,7 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13460
13347
|
status: 401
|
|
13461
13348
|
}),
|
|
13462
13349
|
...routingAttributes(request, upstreamUrl)
|
|
13463
|
-
}
|
|
13464
|
-
isAuthRequired ? "Sandbox egress grant needs user authorization before issuing a credential lease" : "Sandbox egress credential lease is unavailable for selected grant"
|
|
13350
|
+
}
|
|
13465
13351
|
);
|
|
13466
13352
|
return authRequiredResponse({
|
|
13467
13353
|
provider: error.provider,
|
|
@@ -13481,17 +13367,12 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13481
13367
|
upstreamUrl
|
|
13482
13368
|
});
|
|
13483
13369
|
if (!hasSandboxEgressLeaseTransformForHost(lease, upstreamUrl.hostname)) {
|
|
13484
|
-
logWarn(
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
(transform) => transform.domain
|
|
13491
|
-
)
|
|
13492
|
-
},
|
|
13493
|
-
"Sandbox egress credential lease does not cover forwarded host"
|
|
13494
|
-
);
|
|
13370
|
+
logWarn("sandbox.egress.transform.missing", {
|
|
13371
|
+
...attributes(403),
|
|
13372
|
+
"app.sandbox.egress.transform_domains": lease.headerTransforms.map(
|
|
13373
|
+
(transform) => transform.domain
|
|
13374
|
+
)
|
|
13375
|
+
});
|
|
13495
13376
|
return Response.json(
|
|
13496
13377
|
{ error: "Credential lease does not cover forwarded host" },
|
|
13497
13378
|
{ status: 403 }
|
|
@@ -13545,14 +13426,9 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13545
13426
|
upstream,
|
|
13546
13427
|
upstreamUrl
|
|
13547
13428
|
});
|
|
13548
|
-
logWarn(
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
{
|
|
13552
|
-
...attributes(upstream.status, upstream)
|
|
13553
|
-
},
|
|
13554
|
-
"Sandbox egress plugin classified upstream response as permission denied"
|
|
13555
|
-
);
|
|
13429
|
+
logWarn("sandbox.egress.upstream_permission.classified", {
|
|
13430
|
+
...attributes(upstream.status, upstream)
|
|
13431
|
+
});
|
|
13556
13432
|
}
|
|
13557
13433
|
} catch (error) {
|
|
13558
13434
|
if (!isEgressAuthRequired(error)) {
|
|
@@ -13566,14 +13442,9 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13566
13442
|
authorization: error.authorization ?? lease.authorization,
|
|
13567
13443
|
message: error.message
|
|
13568
13444
|
});
|
|
13569
|
-
logWarn(
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
{
|
|
13573
|
-
...attributes(upstream.status, upstream)
|
|
13574
|
-
},
|
|
13575
|
-
"Sandbox egress plugin classified upstream response as auth required"
|
|
13576
|
-
);
|
|
13445
|
+
logWarn("sandbox.egress.upstream_auth_requirement.classified", {
|
|
13446
|
+
...attributes(upstream.status, upstream)
|
|
13447
|
+
});
|
|
13577
13448
|
await upstream.body?.cancel().catch(() => void 0);
|
|
13578
13449
|
return authRequiredResponse({
|
|
13579
13450
|
provider,
|
|
@@ -13592,28 +13463,18 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13592
13463
|
upstreamUrl
|
|
13593
13464
|
});
|
|
13594
13465
|
if (upstream.status >= 400) {
|
|
13595
|
-
logWarn(
|
|
13596
|
-
|
|
13597
|
-
{}
|
|
13598
|
-
|
|
13599
|
-
...attributes(upstream.status, upstream),
|
|
13600
|
-
"error.type": `http_${upstream.status}`
|
|
13601
|
-
},
|
|
13602
|
-
`Sandbox egress upstream returned HTTP ${upstream.status}`
|
|
13603
|
-
);
|
|
13466
|
+
logWarn("sandbox.egress.upstream_response.failed", {
|
|
13467
|
+
...attributes(upstream.status, upstream),
|
|
13468
|
+
"error.type": `http_${upstream.status}`
|
|
13469
|
+
});
|
|
13604
13470
|
}
|
|
13605
13471
|
if (upstream.status === UPSTREAM_TOKEN_REJECTION_STATUS || upstream.status === UPSTREAM_PERMISSION_REJECTION_STATUS) {
|
|
13606
|
-
logWarn(
|
|
13607
|
-
|
|
13608
|
-
{
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
"app.sandbox.egress.www_authenticate": upstream.headers.get("www-authenticate") ?? void 0
|
|
13613
|
-
} : {}
|
|
13614
|
-
},
|
|
13615
|
-
upstream.status === UPSTREAM_TOKEN_REJECTION_STATUS ? "Sandbox egress upstream auth rejected injected credential" : "Sandbox egress upstream permission denied"
|
|
13616
|
-
);
|
|
13472
|
+
logWarn("sandbox.egress.upstream_auth.rejected", {
|
|
13473
|
+
...attributes(upstream.status, upstream),
|
|
13474
|
+
...upstream.status === UPSTREAM_TOKEN_REJECTION_STATUS ? {
|
|
13475
|
+
"app.sandbox.egress.www_authenticate": upstream.headers.get("www-authenticate") ?? void 0
|
|
13476
|
+
} : {}
|
|
13477
|
+
});
|
|
13617
13478
|
if (upstream.status === UPSTREAM_TOKEN_REJECTION_STATUS) {
|
|
13618
13479
|
await clearCredentialLease(provider, lease.grant, credentialContext);
|
|
13619
13480
|
await recordAuthRequired({
|
|
@@ -13712,7 +13573,7 @@ function createPluginEgress(deps) {
|
|
|
13712
13573
|
}
|
|
13713
13574
|
|
|
13714
13575
|
// src/chat/agent/tools.ts
|
|
13715
|
-
async function tryRecordSkillLoadStat(skill
|
|
13576
|
+
async function tryRecordSkillLoadStat(skill) {
|
|
13716
13577
|
if (!process.env.DATABASE_URL) return;
|
|
13717
13578
|
try {
|
|
13718
13579
|
await incrementStat({
|
|
@@ -13721,16 +13582,11 @@ async function tryRecordSkillLoadStat(skill, spanContext) {
|
|
|
13721
13582
|
name: skill.name
|
|
13722
13583
|
});
|
|
13723
13584
|
} catch (error) {
|
|
13724
|
-
logWarn(
|
|
13725
|
-
"
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
"app.plugin.name": skill.pluginProvider,
|
|
13730
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
13731
|
-
},
|
|
13732
|
-
"Failed to record skill load stat"
|
|
13733
|
-
);
|
|
13585
|
+
logWarn("skill.load.stat.failed", {
|
|
13586
|
+
"app.skill.name": skill.name,
|
|
13587
|
+
"app.plugin.name": skill.pluginProvider,
|
|
13588
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
13589
|
+
});
|
|
13734
13590
|
}
|
|
13735
13591
|
}
|
|
13736
13592
|
async function wireAgentTools(args) {
|
|
@@ -13890,7 +13746,7 @@ async function wireAgentTools(args) {
|
|
|
13890
13746
|
if (await mcpToolManager.activateForSkill(effective)) {
|
|
13891
13747
|
await args.recordConnectedMcpProvider(effective.pluginProvider);
|
|
13892
13748
|
}
|
|
13893
|
-
await tryRecordSkillLoadStat(effective
|
|
13749
|
+
await tryRecordSkillLoadStat(effective);
|
|
13894
13750
|
if (mcpAuth.getPendingPause()) {
|
|
13895
13751
|
return void 0;
|
|
13896
13752
|
}
|
|
@@ -13956,15 +13812,10 @@ async function wireAgentTools(args) {
|
|
|
13956
13812
|
toolName
|
|
13957
13813
|
});
|
|
13958
13814
|
} catch (error) {
|
|
13959
|
-
logWarn(
|
|
13960
|
-
"
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
"gen_ai.tool.name": toolName,
|
|
13964
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
13965
|
-
},
|
|
13966
|
-
"Tool invocation observer failed"
|
|
13967
|
-
);
|
|
13815
|
+
logWarn("tool.invocation.observer.failed", {
|
|
13816
|
+
"gen_ai.tool.name": toolName,
|
|
13817
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
13818
|
+
});
|
|
13968
13819
|
}
|
|
13969
13820
|
};
|
|
13970
13821
|
const agentTools = createPiAgentTools(
|
|
@@ -13991,18 +13842,13 @@ async function wireAgentTools(args) {
|
|
|
13991
13842
|
try {
|
|
13992
13843
|
await mcpToolManager.close();
|
|
13993
13844
|
} catch (closeError) {
|
|
13994
|
-
logWarn(
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
14001
|
-
args.conversationPrivacy
|
|
14002
|
-
)
|
|
14003
|
-
},
|
|
14004
|
-
"Failed to close MCP tool manager"
|
|
14005
|
-
);
|
|
13845
|
+
logWarn("mcp.tool_manager.close.failed", {
|
|
13846
|
+
...getMcpProviderErrorAttributes(closeError),
|
|
13847
|
+
"exception.message": getMcpAwareTelemetryMessage(
|
|
13848
|
+
closeError,
|
|
13849
|
+
args.conversationPrivacy
|
|
13850
|
+
)
|
|
13851
|
+
});
|
|
14006
13852
|
}
|
|
14007
13853
|
},
|
|
14008
13854
|
toolGuidance,
|
|
@@ -14035,7 +13881,6 @@ function createResumeState(args) {
|
|
|
14035
13881
|
source: args.runSource,
|
|
14036
13882
|
sessionId: args.turnId,
|
|
14037
13883
|
loadedSkillNames: args.getLoadedSkillNames(),
|
|
14038
|
-
logContext: args.logContext,
|
|
14039
13884
|
modelId: args.getModelId(),
|
|
14040
13885
|
...args.getReasoningLevel() ? { reasoningLevel: args.getReasoningLevel() } : {},
|
|
14041
13886
|
actor: args.actor,
|
|
@@ -14216,6 +14061,7 @@ function createResumeState(args) {
|
|
|
14216
14061
|
}
|
|
14217
14062
|
|
|
14218
14063
|
// src/chat/services/context-compaction.ts
|
|
14064
|
+
import { estimateContextTokens } from "@earendil-works/pi-agent-core";
|
|
14219
14065
|
var RETAINED_USER_MESSAGE_TOKENS = 2e4;
|
|
14220
14066
|
var MAX_SUMMARY_INPUT_CHARS = 8e4;
|
|
14221
14067
|
var MAX_VISIBLE_CONTEXT_CHARS = 2e4;
|
|
@@ -14409,10 +14255,7 @@ async function summarizeContext(args, deps) {
|
|
|
14409
14255
|
return summary.slice(0, MAX_SUMMARY_CHARS);
|
|
14410
14256
|
}
|
|
14411
14257
|
function estimateHistoryTokens(messages) {
|
|
14412
|
-
return messages.
|
|
14413
|
-
(total, message) => total + estimateTextTokens(JSON.stringify(message) ?? ""),
|
|
14414
|
-
0
|
|
14415
|
-
);
|
|
14258
|
+
return estimateContextTokens(messages).tokens;
|
|
14416
14259
|
}
|
|
14417
14260
|
function buildReplacementProvenance(args) {
|
|
14418
14261
|
return [
|
|
@@ -14469,21 +14312,9 @@ async function maybeCompactWithDeps(args, deps) {
|
|
|
14469
14312
|
deps
|
|
14470
14313
|
);
|
|
14471
14314
|
} catch (error) {
|
|
14472
|
-
logWarn(
|
|
14473
|
-
"
|
|
14474
|
-
|
|
14475
|
-
messageConversationId: args.metadata?.threadId,
|
|
14476
|
-
userId: args.metadata?.actorId,
|
|
14477
|
-
destinationName: args.metadata?.channelId,
|
|
14478
|
-
runId: args.metadata?.runId,
|
|
14479
|
-
assistantUserName: botConfig.userName,
|
|
14480
|
-
modelId: botConfig.fastModelId
|
|
14481
|
-
},
|
|
14482
|
-
{
|
|
14483
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14484
|
-
},
|
|
14485
|
-
"Context compaction failed; continuing with prior history"
|
|
14486
|
-
);
|
|
14315
|
+
logWarn("context_compaction.summary.failed", {
|
|
14316
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14317
|
+
});
|
|
14487
14318
|
return { compacted: false, reason: "summary_failed" };
|
|
14488
14319
|
}
|
|
14489
14320
|
return await writeCompactedThreadContext(args, source.messages, summary, {
|
|
@@ -14623,23 +14454,11 @@ async function compactActiveContextIfNeeded(args, deps) {
|
|
|
14623
14454
|
inputLimitTokens
|
|
14624
14455
|
);
|
|
14625
14456
|
}
|
|
14626
|
-
logWarn(
|
|
14627
|
-
"
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
destinationName: args.metadata?.channelId,
|
|
14632
|
-
runId: args.metadata?.runId,
|
|
14633
|
-
assistantUserName: botConfig.userName,
|
|
14634
|
-
modelId: args.modelId
|
|
14635
|
-
},
|
|
14636
|
-
{
|
|
14637
|
-
"app.context_input_limit_tokens": inputLimitTokens,
|
|
14638
|
-
"app.context_tokens_estimated": source.estimatedTokens,
|
|
14639
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14640
|
-
},
|
|
14641
|
-
"Active context compaction failed below the hard input limit"
|
|
14642
|
-
);
|
|
14457
|
+
logWarn("context_compaction.active.summary.failed", {
|
|
14458
|
+
"app.context_input_limit_tokens": inputLimitTokens,
|
|
14459
|
+
"app.context_tokens_estimated": source.estimatedTokens,
|
|
14460
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14461
|
+
});
|
|
14643
14462
|
return { compacted: false, reason: "summary_failed" };
|
|
14644
14463
|
}
|
|
14645
14464
|
const summaryMessage = userMessage(
|
|
@@ -14741,7 +14560,7 @@ function waitForAbortSettlement(promise, timeoutMs) {
|
|
|
14741
14560
|
);
|
|
14742
14561
|
});
|
|
14743
14562
|
}
|
|
14744
|
-
async function executeAgentRun(request) {
|
|
14563
|
+
async function executeAgentRun(request, streamFn) {
|
|
14745
14564
|
if (!request.routing.destination) {
|
|
14746
14565
|
throw new TypeError("Assistant reply generation requires a destination");
|
|
14747
14566
|
}
|
|
@@ -14776,12 +14595,13 @@ async function executeAgentRun(request) {
|
|
|
14776
14595
|
() => executeAgentRunInPrivacyContext(
|
|
14777
14596
|
request,
|
|
14778
14597
|
conversationPrivacy,
|
|
14779
|
-
runLogContext
|
|
14598
|
+
runLogContext,
|
|
14599
|
+
streamFn
|
|
14780
14600
|
)
|
|
14781
14601
|
)
|
|
14782
14602
|
);
|
|
14783
14603
|
}
|
|
14784
|
-
async function executeAgentRunInPrivacyContext(request, conversationPrivacy, runLogContext) {
|
|
14604
|
+
async function executeAgentRunInPrivacyContext(request, conversationPrivacy, runLogContext, streamFn) {
|
|
14785
14605
|
const { conversationId, input, routing, runId, turnId } = request;
|
|
14786
14606
|
const policy = request.policy ?? {};
|
|
14787
14607
|
const signal = policy.signal;
|
|
@@ -14819,19 +14639,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14819
14639
|
const slackDestination = routing.destination.platform === "slack" ? routing.destination : void 0;
|
|
14820
14640
|
const slackActor = actor?.platform === "slack" ? actor : void 0;
|
|
14821
14641
|
const userInput = input.messageText;
|
|
14822
|
-
const credentialActor = routing.credentialContext?.actor;
|
|
14823
|
-
const credentialActorLogContext = credentialActor ? {
|
|
14824
|
-
actorType: "type" in credentialActor ? credentialActor.type : "system",
|
|
14825
|
-
actorId: "type" in credentialActor ? credentialActor.userId : credentialActor.name
|
|
14826
|
-
} : {};
|
|
14827
|
-
const sessionRecordLogContext = {
|
|
14828
|
-
threadId: slackSource ? conversationId : void 0,
|
|
14829
|
-
actorId: slackActor?.userId,
|
|
14830
|
-
channelId: slackDestination?.channelId,
|
|
14831
|
-
runId,
|
|
14832
|
-
...credentialActorLogContext,
|
|
14833
|
-
assistantUserName: botConfig.userName
|
|
14834
|
-
};
|
|
14835
14642
|
const recordConnectedMcpProvider = async (provider) => {
|
|
14836
14643
|
if (connectedMcpProviders.has(provider)) {
|
|
14837
14644
|
return;
|
|
@@ -14858,27 +14665,21 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14858
14665
|
const shouldTrace = shouldEmitDevAgentTrace();
|
|
14859
14666
|
const spanContext = { modelId: activeModelId };
|
|
14860
14667
|
const availableSkills = await discoverRunSkills({
|
|
14861
|
-
skillDirs: policy.skillDirs
|
|
14862
|
-
spanContext
|
|
14668
|
+
skillDirs: policy.skillDirs
|
|
14863
14669
|
});
|
|
14864
14670
|
if (shouldTrace) {
|
|
14865
14671
|
const inboundAttachmentCount = input.inboundAttachmentCount ?? 0;
|
|
14866
14672
|
const promptAttachmentCount = input.userAttachments?.length ?? 0;
|
|
14867
|
-
logInfo(
|
|
14868
|
-
"
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
"app.message.prompt_attachment_count": promptAttachmentCount,
|
|
14878
|
-
"messaging.message.id": slackSource?.messageTs ?? ""
|
|
14879
|
-
},
|
|
14880
|
-
"Agent message received"
|
|
14881
|
-
);
|
|
14673
|
+
logInfo("agent.message.received", {
|
|
14674
|
+
"app.message.kind": "user_inbound",
|
|
14675
|
+
"app.message.length": userInput.length,
|
|
14676
|
+
"app.message.input": summarizeMessageText(userInput),
|
|
14677
|
+
// Log both counts so image uploads filtered by vision/config do not
|
|
14678
|
+
// look indistinguishable from Slack ingress dropping attachments.
|
|
14679
|
+
"app.message.attachment_count": inboundAttachmentCount,
|
|
14680
|
+
"app.message.prompt_attachment_count": promptAttachmentCount,
|
|
14681
|
+
"messaging.message.id": slackSource?.messageTs ?? ""
|
|
14682
|
+
});
|
|
14882
14683
|
}
|
|
14883
14684
|
const skillInvocation = parseSkillInvocation(userInput, availableSkills);
|
|
14884
14685
|
const invokedSkill = skillInvocation ? findSkillByName(skillInvocation.skillName, availableSkills) : null;
|
|
@@ -14910,7 +14711,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14910
14711
|
durability,
|
|
14911
14712
|
getLoadedSkillNames: () => loadedSkillNamesForResume,
|
|
14912
14713
|
getReasoningLevel: () => turnRoute?.reasoningLevel,
|
|
14913
|
-
logContext: sessionRecordLogContext,
|
|
14914
14714
|
getModelId: () => activeModelId,
|
|
14915
14715
|
recordActiveMcpProviders,
|
|
14916
14716
|
actor,
|
|
@@ -14930,15 +14730,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14930
14730
|
toolName: event.toolName
|
|
14931
14731
|
});
|
|
14932
14732
|
} catch (error) {
|
|
14933
|
-
logException(
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
spanContext,
|
|
14937
|
-
{
|
|
14938
|
-
"gen_ai.tool.name": event.toolName
|
|
14939
|
-
},
|
|
14940
|
-
"Failed to record host-only tool execution start"
|
|
14941
|
-
);
|
|
14733
|
+
logException(error, "agent.turn.session_log_append.failed", {
|
|
14734
|
+
"gen_ai.tool.name": event.toolName
|
|
14735
|
+
});
|
|
14942
14736
|
}
|
|
14943
14737
|
};
|
|
14944
14738
|
const persistedConfigurationValues = policy.channelConfiguration ? await policy.channelConfiguration.resolveValues() : {};
|
|
@@ -15073,14 +14867,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15073
14867
|
void (async () => {
|
|
15074
14868
|
await observers.onStatus?.({ text: "Switching models" });
|
|
15075
14869
|
})().catch((error) => {
|
|
15076
|
-
logWarn(
|
|
15077
|
-
"
|
|
15078
|
-
|
|
15079
|
-
{
|
|
15080
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15081
|
-
},
|
|
15082
|
-
"Failed to report assistant status"
|
|
15083
|
-
);
|
|
14870
|
+
logWarn("assistant.status.observer.failed", {
|
|
14871
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14872
|
+
});
|
|
15084
14873
|
});
|
|
15085
14874
|
const handoffMessages = await compactContextForHandoff(
|
|
15086
14875
|
{
|
|
@@ -15306,12 +15095,12 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15306
15095
|
};
|
|
15307
15096
|
let assistantMessageDeliveryError;
|
|
15308
15097
|
const deliverAssistantMessage = async (message) => {
|
|
15309
|
-
const
|
|
15310
|
-
if (
|
|
15098
|
+
const decision = decideReply(message);
|
|
15099
|
+
if (decision.kind !== "deliver" || !delivery) {
|
|
15311
15100
|
return;
|
|
15312
15101
|
}
|
|
15313
15102
|
try {
|
|
15314
|
-
await delivery
|
|
15103
|
+
await delivery(message);
|
|
15315
15104
|
} catch (error) {
|
|
15316
15105
|
assistantMessageDeliveryError = new AssistantMessageDeliveryError(
|
|
15317
15106
|
error
|
|
@@ -15350,27 +15139,17 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15350
15139
|
steeredMessageCount += piMessages.length;
|
|
15351
15140
|
});
|
|
15352
15141
|
if (steeredMessageCount > 0) {
|
|
15353
|
-
logInfo(
|
|
15354
|
-
"
|
|
15355
|
-
|
|
15356
|
-
{
|
|
15357
|
-
"app.ai.steering_message_count": steeredMessageCount
|
|
15358
|
-
},
|
|
15359
|
-
"Agent turn steering messages accepted"
|
|
15360
|
-
);
|
|
15142
|
+
logInfo("agent.turn.steering_messages.accepted", {
|
|
15143
|
+
"app.ai.steering_message_count": steeredMessageCount
|
|
15144
|
+
});
|
|
15361
15145
|
}
|
|
15362
15146
|
} catch (error) {
|
|
15363
15147
|
if (isTurnInputCommitLostError(error)) {
|
|
15364
15148
|
throw error;
|
|
15365
15149
|
}
|
|
15366
|
-
logWarn(
|
|
15367
|
-
"
|
|
15368
|
-
|
|
15369
|
-
{
|
|
15370
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15371
|
-
},
|
|
15372
|
-
"Agent turn steering message drain failed"
|
|
15373
|
-
);
|
|
15150
|
+
logWarn("agent.turn.steering_messages_drain.failed", {
|
|
15151
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15152
|
+
});
|
|
15374
15153
|
}
|
|
15375
15154
|
return acceptedMessages;
|
|
15376
15155
|
};
|
|
@@ -15378,7 +15157,10 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15378
15157
|
let pendingPiHookError;
|
|
15379
15158
|
agent = new Agent({
|
|
15380
15159
|
...apiKeyOverride ? { getApiKey: () => apiKeyOverride } : {},
|
|
15381
|
-
streamFn: createTracedStreamFn({
|
|
15160
|
+
streamFn: createTracedStreamFn({
|
|
15161
|
+
conversationPrivacy,
|
|
15162
|
+
...streamFn ? { base: streamFn } : {}
|
|
15163
|
+
}),
|
|
15382
15164
|
steeringMode: "all",
|
|
15383
15165
|
beforeToolCall: async ({ assistantMessage }) => {
|
|
15384
15166
|
const toolCalls2 = assistantMessage.content.filter(
|
|
@@ -15522,37 +15304,27 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15522
15304
|
);
|
|
15523
15305
|
} catch (error) {
|
|
15524
15306
|
if (runResume.timedOut) {
|
|
15525
|
-
logWarn(
|
|
15526
|
-
"
|
|
15527
|
-
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
"gen_ai.
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
turnDeadlineAtMs - Date.now()
|
|
15539
|
-
)
|
|
15540
|
-
},
|
|
15541
|
-
"Agent turn timed out and was aborted"
|
|
15542
|
-
);
|
|
15307
|
+
logWarn("agent.turn.timed_out", {
|
|
15308
|
+
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
15309
|
+
"gen_ai.operation.name": "invoke_agent",
|
|
15310
|
+
"gen_ai.request.model": activeModelId,
|
|
15311
|
+
...turnRoute ? {
|
|
15312
|
+
"gen_ai.request.reasoning.level": turnRoute.reasoningLevel
|
|
15313
|
+
} : {},
|
|
15314
|
+
"app.ai.turn_timeout_ms": turnTimeoutBudgetMs,
|
|
15315
|
+
"app.ai.turn_deadline_remaining_ms": Math.max(
|
|
15316
|
+
0,
|
|
15317
|
+
turnDeadlineAtMs - Date.now()
|
|
15318
|
+
)
|
|
15319
|
+
});
|
|
15543
15320
|
const settled = await waitForAbortSettlement(
|
|
15544
15321
|
run2,
|
|
15545
15322
|
AGENT_ABORT_SETTLE_GRACE_MS
|
|
15546
15323
|
);
|
|
15547
15324
|
if (!settled) {
|
|
15548
|
-
logWarn(
|
|
15549
|
-
"
|
|
15550
|
-
|
|
15551
|
-
{
|
|
15552
|
-
"app.ai.abort_settle_grace_ms": AGENT_ABORT_SETTLE_GRACE_MS
|
|
15553
|
-
},
|
|
15554
|
-
"Timed-out agent run did not settle after abort before resume snapshot"
|
|
15555
|
-
);
|
|
15325
|
+
logWarn("agent.turn.abort_settle.timed_out", {
|
|
15326
|
+
"app.ai.abort_settle_grace_ms": AGENT_ABORT_SETTLE_GRACE_MS
|
|
15327
|
+
});
|
|
15556
15328
|
}
|
|
15557
15329
|
runResume.captureResumeSnapshot(
|
|
15558
15330
|
runResume.getResumeSnapshot(currentAgentMessages())
|
|
@@ -15616,9 +15388,20 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15616
15388
|
]);
|
|
15617
15389
|
}
|
|
15618
15390
|
run = shouldPromptAgent && !capacityUpdate ? agent.prompt(freshPromptMessage) : agent.continue();
|
|
15619
|
-
let
|
|
15391
|
+
let discardedRetryUsage;
|
|
15392
|
+
let providerRetryAttempt = 0;
|
|
15393
|
+
let emptyOutputAttempt = 0;
|
|
15394
|
+
const prepareRetry = async (messages) => {
|
|
15395
|
+
discardedRetryUsage = addAgentTurnUsage(
|
|
15396
|
+
discardedRetryUsage,
|
|
15397
|
+
getDiscardedRetryUsage(agent.state.messages, messages)
|
|
15398
|
+
);
|
|
15399
|
+
agent.state.messages = messages;
|
|
15400
|
+
await runResume.persistSafeBoundary(messages);
|
|
15401
|
+
signal?.throwIfAborted();
|
|
15402
|
+
};
|
|
15620
15403
|
try {
|
|
15621
|
-
for (
|
|
15404
|
+
for (; ; ) {
|
|
15622
15405
|
await runAgentStep(run);
|
|
15623
15406
|
if (assistantMessageDeliveryError) {
|
|
15624
15407
|
throw assistantMessageDeliveryError;
|
|
@@ -15635,7 +15418,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15635
15418
|
const usageSummary = extractGenAiUsageSummary(...outputMessages);
|
|
15636
15419
|
const currentUsage = hasAgentTurnUsage(usageSummary) ? usageSummary : void 0;
|
|
15637
15420
|
const currentPhaseUsage = addAgentTurnUsage(
|
|
15638
|
-
|
|
15421
|
+
discardedRetryUsage,
|
|
15639
15422
|
currentUsage
|
|
15640
15423
|
);
|
|
15641
15424
|
turnUsage = addAgentTurnUsage(priorPhaseUsage, currentPhaseUsage);
|
|
@@ -15650,7 +15433,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15650
15433
|
normalizeGenAiFinishReason(lastAssistant.stopReason)
|
|
15651
15434
|
]
|
|
15652
15435
|
} : {},
|
|
15653
|
-
...extractGenAiUsageAttributes(
|
|
15436
|
+
...extractGenAiUsageAttributes(currentPhaseUsage)
|
|
15654
15437
|
});
|
|
15655
15438
|
const pendingAuthPause = getPendingAuthPause();
|
|
15656
15439
|
if (pendingAuthPause) {
|
|
@@ -15659,25 +15442,37 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15659
15442
|
);
|
|
15660
15443
|
throw pendingAuthPause;
|
|
15661
15444
|
}
|
|
15445
|
+
const emptyOutputContinuation = nextEmptyOutputContinuation({
|
|
15446
|
+
attempt: emptyOutputAttempt,
|
|
15447
|
+
lastAssistant,
|
|
15448
|
+
messages: agent.state.messages
|
|
15449
|
+
});
|
|
15450
|
+
if (emptyOutputContinuation.kind === "retry") {
|
|
15451
|
+
emptyOutputAttempt += 1;
|
|
15452
|
+
await prepareRetry(emptyOutputContinuation.messages);
|
|
15453
|
+
logWarn("agent.turn.empty_output.retrying", {
|
|
15454
|
+
"app.ai.empty_output.attempt": emptyOutputAttempt
|
|
15455
|
+
});
|
|
15456
|
+
run = agent.continue();
|
|
15457
|
+
continue;
|
|
15458
|
+
}
|
|
15459
|
+
if (emptyOutputContinuation.kind === "exhausted") {
|
|
15460
|
+
logWarn("agent.turn.empty_output.exhausted", {
|
|
15461
|
+
"app.ai.empty_output.attempt": emptyOutputAttempt
|
|
15462
|
+
});
|
|
15463
|
+
}
|
|
15662
15464
|
const providerRetry = nextProviderRetry({
|
|
15663
|
-
attempt,
|
|
15465
|
+
attempt: providerRetryAttempt,
|
|
15664
15466
|
failure: lastAssistant,
|
|
15665
15467
|
messages: agent.state.messages
|
|
15666
15468
|
});
|
|
15667
15469
|
if (!providerRetry) {
|
|
15668
15470
|
break;
|
|
15669
15471
|
}
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
15673
|
-
logWarn(
|
|
15674
|
-
"agent_turn_provider_retry",
|
|
15675
|
-
spanContext,
|
|
15676
|
-
{},
|
|
15677
|
-
"Retrying transient provider failure"
|
|
15678
|
-
);
|
|
15472
|
+
providerRetryAttempt += 1;
|
|
15473
|
+
await prepareRetry(providerRetry.messages);
|
|
15474
|
+
logWarn("agent.turn.provider.retrying");
|
|
15679
15475
|
await sleep(providerRetry.delayMs, signal);
|
|
15680
|
-
signal?.throwIfAborted();
|
|
15681
15476
|
run = agent.continue();
|
|
15682
15477
|
}
|
|
15683
15478
|
} catch (error) {
|
|
@@ -15722,7 +15517,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15722
15517
|
durationMs: Date.now() - replyStartedAtMs,
|
|
15723
15518
|
generatedFileCount: generatedFiles.length,
|
|
15724
15519
|
shouldTrace,
|
|
15725
|
-
spanContext,
|
|
15726
15520
|
usage: turnUsage,
|
|
15727
15521
|
executionProfile: turnRoute,
|
|
15728
15522
|
assistantUserName: botConfig.userName,
|
|
@@ -15770,13 +15564,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15770
15564
|
if (durability.onInputCommitted && !resume?.inputCommitted) {
|
|
15771
15565
|
throw error;
|
|
15772
15566
|
}
|
|
15773
|
-
logException(
|
|
15774
|
-
error,
|
|
15775
|
-
"assistant_reply_generation_failed",
|
|
15776
|
-
{ modelId: activeModelId },
|
|
15777
|
-
{},
|
|
15778
|
-
"executeAgentRun failed"
|
|
15779
|
-
);
|
|
15567
|
+
logException(error, "assistant.reply.generation.failed");
|
|
15780
15568
|
const message = error instanceof Error ? error.message : String(error);
|
|
15781
15569
|
return {
|
|
15782
15570
|
status: "completed",
|