@sentry/junior 0.121.0 → 0.122.1
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-65WXVKKX.js} +8 -8
- package/dist/api.js +14 -14
- package/dist/app.js +604 -997
- package/dist/{catalog-runtime-AD3YNTTM.js → catalog-runtime-VNNMSKCB.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/mcp/tool-manager.d.ts +11 -0
- package/dist/chat/plugins/agent-hooks.d.ts +8 -0
- 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-VWBKDPMQ.js → chunk-3KYLHUVC.js} +487 -686
- package/dist/{chunk-JZ47AFSH.js → chunk-4JPJTFUH.js} +37 -45
- package/dist/{chunk-ET2SDCNV.js → chunk-4ZV2GNHX.js} +16 -31
- package/dist/{chunk-WUP7NWMP.js → chunk-73TQBD5S.js} +1 -1
- package/dist/{chunk-Z2XXPUZG.js → chunk-BXT63TNS.js} +2061 -2015
- package/dist/{chunk-JYDIBXFY.js → chunk-GPQLJDT5.js} +13 -19
- package/dist/{chunk-LE77HHF3.js → chunk-HGREP4UX.js} +1 -1
- package/dist/{chunk-XDRGYDED.js → chunk-IEE5CSAP.js} +1 -1
- package/dist/{chunk-D2EMOH3N.js → chunk-LZ4XXS76.js} +3 -3
- package/dist/{chunk-254MFDOF.js → chunk-M7KAZXTE.js} +2 -2
- package/dist/{chunk-ITMEXX5H.js → chunk-MSDKKTRG.js} +4 -4
- package/dist/{chunk-UXQ5XSA2.js → chunk-PXPBBOIU.js} +2 -2
- package/dist/{chunk-IK4QSS5H.js → chunk-PYS4QZAF.js} +1 -1
- package/dist/{chunk-7HYV7KFM.js → chunk-QE33ATQW.js} +83 -92
- package/dist/{chunk-HDFGNU5E.js → chunk-S7G34U75.js} +3 -1
- package/dist/{chunk-IDXLBKPS.js → chunk-TI7SYDD4.js} +11 -22
- package/dist/{chunk-3DBMANUI.js → chunk-U5PRRZMZ.js} +22 -45
- package/dist/{chunk-KLUMVJRQ.js → chunk-VLRECFIC.js} +133 -206
- package/dist/{chunk-UURFXX66.js → chunk-WFJ2EG4E.js} +1 -1
- package/dist/{chunk-TRECK7RV.js → chunk-XBYNPBPQ.js} +14 -29
- 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-36HXKAKH.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-UKOO7KKP.js} +15 -15
- package/dist/{runner-3ONPZRED.js → runner-M66KMCQ7.js} +62 -51
- package/dist/{skills-WGAYGGPA.js → skills-TTXTVFOG.js} +6 -6
- package/dist/{validation-ZIWNBG4D.js → validation-TGASRGNN.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-U5PRRZMZ.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-BXT63TNS.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-MSDKKTRG.js";
|
|
100
105
|
import {
|
|
101
106
|
incrementStat
|
|
102
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-IEE5CSAP.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-QE33ATQW.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-M7KAZXTE.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-WFJ2EG4E.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-TI7SYDD4.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-XBYNPBPQ.js";
|
|
192
197
|
import {
|
|
193
198
|
pluginCatalogRuntime
|
|
194
|
-
} from "./chunk-
|
|
199
|
+
} from "./chunk-73TQBD5S.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-4ZV2GNHX.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-4JPJTFUH.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);
|
|
@@ -6717,11 +6614,18 @@ var McpToolManager = class {
|
|
|
6717
6614
|
const providerContent = boundMcpContent(
|
|
6718
6615
|
toAgentToolContent(result)
|
|
6719
6616
|
);
|
|
6720
|
-
|
|
6617
|
+
const successResult = {
|
|
6721
6618
|
content: toModelVisibleMcpContent(result),
|
|
6722
6619
|
providerContent,
|
|
6723
6620
|
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {}
|
|
6724
6621
|
};
|
|
6622
|
+
await this.options.onToolSuccess?.({
|
|
6623
|
+
arguments: resolvedArgs,
|
|
6624
|
+
provider: plugin.manifest.name,
|
|
6625
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {},
|
|
6626
|
+
toolName: tool.name
|
|
6627
|
+
});
|
|
6628
|
+
return successResult;
|
|
6725
6629
|
} catch (error) {
|
|
6726
6630
|
if (error instanceof McpAuthorizationRequiredError && await this.handleAuthorizationRequired(
|
|
6727
6631
|
plugin.manifest.name,
|
|
@@ -6747,12 +6651,7 @@ var McpToolManager = class {
|
|
|
6747
6651
|
};
|
|
6748
6652
|
setSpanAttributes(errorAttributes);
|
|
6749
6653
|
if (error instanceof McpToolError) {
|
|
6750
|
-
logWarn(
|
|
6751
|
-
"mcp_tool_call_failed",
|
|
6752
|
-
{},
|
|
6753
|
-
errorAttributes,
|
|
6754
|
-
"MCP tool call failed"
|
|
6755
|
-
);
|
|
6654
|
+
logWarn("mcp.tool_call.failed", errorAttributes);
|
|
6756
6655
|
}
|
|
6757
6656
|
throw error;
|
|
6758
6657
|
}
|
|
@@ -6908,22 +6807,16 @@ async function enrichImagePrompt(rawPrompt) {
|
|
|
6908
6807
|
maxTokens: 1024
|
|
6909
6808
|
});
|
|
6910
6809
|
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
|
-
);
|
|
6810
|
+
logInfo("image.prompt.enriched", {
|
|
6811
|
+
"app.image.enriched_prompt_length": text.trim().length
|
|
6812
|
+
});
|
|
6917
6813
|
return text.trim();
|
|
6918
6814
|
}
|
|
6919
6815
|
return rawPrompt;
|
|
6920
6816
|
} catch (error) {
|
|
6921
|
-
logWarn(
|
|
6922
|
-
"
|
|
6923
|
-
|
|
6924
|
-
{ "exception.message": String(error) },
|
|
6925
|
-
"Image prompt enrichment failed, using raw prompt"
|
|
6926
|
-
);
|
|
6817
|
+
logWarn("image.prompt.enrichment.failed", {
|
|
6818
|
+
"exception.message": String(error)
|
|
6819
|
+
});
|
|
6927
6820
|
return rawPrompt;
|
|
6928
6821
|
}
|
|
6929
6822
|
}
|
|
@@ -9002,18 +8895,13 @@ async function grantChannelCanvasAccess(canvasId, channelId) {
|
|
|
9002
8895
|
}
|
|
9003
8896
|
}
|
|
9004
8897
|
);
|
|
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
|
-
);
|
|
8898
|
+
} catch {
|
|
8899
|
+
logWarn("slack.canvas.access_set.failed", {
|
|
8900
|
+
"app.slack.action": "canvases.access.set",
|
|
8901
|
+
"app.slack.canvas.canvas_id_prefix": canvasId.slice(0, 1),
|
|
8902
|
+
"app.slack.canvas.channel_id_prefix": channelId.slice(0, 1),
|
|
8903
|
+
"app.slack.canvas.access_level": "write"
|
|
8904
|
+
});
|
|
9017
8905
|
}
|
|
9018
8906
|
}
|
|
9019
8907
|
async function writeCanvasMarkdown(input) {
|
|
@@ -9150,16 +9038,11 @@ function createSlackCanvasCreateTool(context, state) {
|
|
|
9150
9038
|
execute: async ({ title, markdown }) => {
|
|
9151
9039
|
const targetChannelId = context.destinationChannelId;
|
|
9152
9040
|
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
|
-
);
|
|
9041
|
+
logError("slack.canvas.create.context_invalid", {
|
|
9042
|
+
"gen_ai.tool.name": "slackCanvasCreate",
|
|
9043
|
+
"messaging.destination.name": targetChannelId ?? "none",
|
|
9044
|
+
"app.slack.canvas.has_channel_context": Boolean(targetChannelId)
|
|
9045
|
+
});
|
|
9163
9046
|
throw new Error(
|
|
9164
9047
|
"Cannot create a canvas without an active assistant channel context (C/G/D)."
|
|
9165
9048
|
);
|
|
@@ -9292,15 +9175,10 @@ function createSlackCanvasEditTool(state) {
|
|
|
9292
9175
|
return response;
|
|
9293
9176
|
} catch (error) {
|
|
9294
9177
|
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
|
-
);
|
|
9178
|
+
logWarn("slack.canvas.edit.failed", {
|
|
9179
|
+
"gen_ai.tool.name": "slackCanvasEdit",
|
|
9180
|
+
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9181
|
+
});
|
|
9304
9182
|
return {
|
|
9305
9183
|
ok: false,
|
|
9306
9184
|
status: "error",
|
|
@@ -9371,15 +9249,10 @@ function createSlackCanvasReadTool() {
|
|
|
9371
9249
|
};
|
|
9372
9250
|
} catch (error) {
|
|
9373
9251
|
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
|
-
);
|
|
9252
|
+
logWarn("slack.canvas.read.failed", {
|
|
9253
|
+
"gen_ai.tool.name": "slackCanvasRead",
|
|
9254
|
+
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9255
|
+
});
|
|
9383
9256
|
return {
|
|
9384
9257
|
ok: false,
|
|
9385
9258
|
status: "error",
|
|
@@ -9438,15 +9311,10 @@ function createSlackCanvasWriteTool(state) {
|
|
|
9438
9311
|
return response;
|
|
9439
9312
|
} catch (error) {
|
|
9440
9313
|
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
|
-
);
|
|
9314
|
+
logWarn("slack.canvas.write.failed", {
|
|
9315
|
+
"gen_ai.tool.name": "slackCanvasWrite",
|
|
9316
|
+
"app.slack.canvas.canvas_id_prefix": target.canvasId.slice(0, 1)
|
|
9317
|
+
});
|
|
9450
9318
|
return {
|
|
9451
9319
|
ok: false,
|
|
9452
9320
|
status: "error",
|
|
@@ -10494,6 +10362,10 @@ function createSystemTimeTool() {
|
|
|
10494
10362
|
import { z as z37 } from "zod";
|
|
10495
10363
|
var DEFAULT_LIMIT3 = 25;
|
|
10496
10364
|
var MAX_LIMIT = 100;
|
|
10365
|
+
var MAX_EVENT_DATA_BYTES = 4e3;
|
|
10366
|
+
var MAX_EVENTS_JSON_BYTES = 2e4;
|
|
10367
|
+
var MAX_IDENTITY_CHARS = 256;
|
|
10368
|
+
var textEncoder = new TextEncoder();
|
|
10497
10369
|
var CONVERSATION_EVENTS_TOOL_SOURCE = {
|
|
10498
10370
|
id: "conversation-events",
|
|
10499
10371
|
description: "Inspect Junior's durable conversation event log for debugging runtime behavior."
|
|
@@ -10507,7 +10379,7 @@ var projectedEventSchema = z37.object({
|
|
|
10507
10379
|
created_at: z37.iso.datetime().describe("When the event was recorded."),
|
|
10508
10380
|
idempotency_key: z37.string().min(1).optional().describe("Retry-stable event identity, when one was assigned."),
|
|
10509
10381
|
data: z37.record(z37.string(), z37.unknown()).describe(
|
|
10510
|
-
"Event
|
|
10382
|
+
"Event data. Oversized payloads are replaced by identifying fields, payload_omitted, and payload_json_bytes."
|
|
10511
10383
|
)
|
|
10512
10384
|
}).strict();
|
|
10513
10385
|
var queryConversationEventsOutputSchema = juniorToolResultSchema.extend({
|
|
@@ -10518,6 +10390,9 @@ var queryConversationEventsOutputSchema = juniorToolResultSchema.extend({
|
|
|
10518
10390
|
),
|
|
10519
10391
|
has_newer: z37.boolean().describe(
|
|
10520
10392
|
"Whether matching events exist after this page; request them with after_seq set to the last returned seq."
|
|
10393
|
+
),
|
|
10394
|
+
omitted_event_count: z37.number().int().nonnegative().optional().describe(
|
|
10395
|
+
"Fetched events omitted to keep this response bounded. Continue with the pagination cursor for the omitted direction."
|
|
10521
10396
|
)
|
|
10522
10397
|
});
|
|
10523
10398
|
function createQueryConversationEventsTool(context) {
|
|
@@ -10597,14 +10472,17 @@ function createQueryConversationEventsTool(context) {
|
|
|
10597
10472
|
...beforeSeq === void 0 ? {} : { beforeSeq },
|
|
10598
10473
|
...types === void 0 ? {} : { types }
|
|
10599
10474
|
});
|
|
10600
|
-
const
|
|
10475
|
+
const newestFirst = afterSeq === void 0;
|
|
10476
|
+
const projected = projectEventsForTool(page, { newestFirst });
|
|
10601
10477
|
return {
|
|
10602
10478
|
ok: true,
|
|
10603
10479
|
status: "success",
|
|
10604
10480
|
conversation_id: conversationId,
|
|
10605
|
-
events,
|
|
10606
|
-
has_older: page.hasOlder,
|
|
10607
|
-
has_newer: page.hasNewer
|
|
10481
|
+
events: projected.events,
|
|
10482
|
+
has_older: page.hasOlder || newestFirst && projected.omittedEventCount > 0,
|
|
10483
|
+
has_newer: page.hasNewer || !newestFirst && projected.omittedEventCount > 0,
|
|
10484
|
+
truncated: projected.omittedEventCount > 0,
|
|
10485
|
+
...projected.omittedEventCount > 0 ? { omitted_event_count: projected.omittedEventCount } : {}
|
|
10608
10486
|
};
|
|
10609
10487
|
}
|
|
10610
10488
|
});
|
|
@@ -10689,11 +10567,30 @@ function assertCanQueryConversationEvents(args) {
|
|
|
10689
10567
|
`Conversation events are not accessible: ${targetConversationId}`
|
|
10690
10568
|
);
|
|
10691
10569
|
}
|
|
10692
|
-
function projectEventsForTool(page) {
|
|
10693
|
-
|
|
10570
|
+
function projectEventsForTool(page, options) {
|
|
10571
|
+
const projected = page.events.map(projectEvent);
|
|
10572
|
+
const events = [];
|
|
10573
|
+
let jsonBytes = 2;
|
|
10574
|
+
const candidates = options.newestFirst ? [...projected].reverse() : projected;
|
|
10575
|
+
for (const event of candidates) {
|
|
10576
|
+
const eventBytes = jsonByteLength(event);
|
|
10577
|
+
const separatorBytes = events.length === 0 ? 0 : 1;
|
|
10578
|
+
if (jsonBytes + separatorBytes + eventBytes > MAX_EVENTS_JSON_BYTES) {
|
|
10579
|
+
break;
|
|
10580
|
+
}
|
|
10581
|
+
events.push(event);
|
|
10582
|
+
jsonBytes += separatorBytes + eventBytes;
|
|
10583
|
+
}
|
|
10584
|
+
if (options.newestFirst) {
|
|
10585
|
+
events.reverse();
|
|
10586
|
+
}
|
|
10587
|
+
return {
|
|
10588
|
+
events,
|
|
10589
|
+
omittedEventCount: projected.length - events.length
|
|
10590
|
+
};
|
|
10694
10591
|
}
|
|
10695
10592
|
function projectEvent(event) {
|
|
10696
|
-
const data = stripReplacementHistory(event.data);
|
|
10593
|
+
const data = boundEventData(stripReplacementHistory(event.data));
|
|
10697
10594
|
return {
|
|
10698
10595
|
seq: event.seq,
|
|
10699
10596
|
history_version: event.historyVersion,
|
|
@@ -10702,6 +10599,46 @@ function projectEvent(event) {
|
|
|
10702
10599
|
data
|
|
10703
10600
|
};
|
|
10704
10601
|
}
|
|
10602
|
+
function boundEventData(data) {
|
|
10603
|
+
const payloadJsonBytes = jsonByteLength(data);
|
|
10604
|
+
if (payloadJsonBytes <= MAX_EVENT_DATA_BYTES) {
|
|
10605
|
+
return data;
|
|
10606
|
+
}
|
|
10607
|
+
return {
|
|
10608
|
+
...eventIdentity(data),
|
|
10609
|
+
payload_omitted: true,
|
|
10610
|
+
payload_json_bytes: payloadJsonBytes
|
|
10611
|
+
};
|
|
10612
|
+
}
|
|
10613
|
+
function jsonByteLength(value) {
|
|
10614
|
+
return textEncoder.encode(JSON.stringify(value)).byteLength;
|
|
10615
|
+
}
|
|
10616
|
+
function eventIdentity(data) {
|
|
10617
|
+
const identityKeys = [
|
|
10618
|
+
"type",
|
|
10619
|
+
"originalType",
|
|
10620
|
+
"messageId",
|
|
10621
|
+
"role",
|
|
10622
|
+
"turnId",
|
|
10623
|
+
"toolCallId",
|
|
10624
|
+
"toolName",
|
|
10625
|
+
"subagentInvocationId",
|
|
10626
|
+
"subagentKind",
|
|
10627
|
+
"childConversationId",
|
|
10628
|
+
"outcome",
|
|
10629
|
+
"failureCode",
|
|
10630
|
+
"provider",
|
|
10631
|
+
"kind",
|
|
10632
|
+
"modelProfile",
|
|
10633
|
+
"modelId"
|
|
10634
|
+
];
|
|
10635
|
+
return Object.fromEntries(
|
|
10636
|
+
identityKeys.flatMap((key) => {
|
|
10637
|
+
const value = data[key];
|
|
10638
|
+
return typeof value === "string" ? [[key, value.slice(0, MAX_IDENTITY_CHARS)]] : [];
|
|
10639
|
+
})
|
|
10640
|
+
);
|
|
10641
|
+
}
|
|
10705
10642
|
function stripReplacementHistory(data) {
|
|
10706
10643
|
if (data.type === "unknown") {
|
|
10707
10644
|
return {
|
|
@@ -11368,18 +11305,12 @@ function createWebSearchTool(modelId, override) {
|
|
|
11368
11305
|
const message = formatSearchFailure(error);
|
|
11369
11306
|
const timeout = /timed out/i.test(message);
|
|
11370
11307
|
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
|
-
);
|
|
11308
|
+
logException(error, "web.search.failed", {
|
|
11309
|
+
"gen_ai.tool.name": "webSearch",
|
|
11310
|
+
"app.web_search.timeout": timeout,
|
|
11311
|
+
"app.web_search.retryable": retryable,
|
|
11312
|
+
"app.web_search.query": query
|
|
11313
|
+
});
|
|
11383
11314
|
return {
|
|
11384
11315
|
ok: false,
|
|
11385
11316
|
status: "error",
|
|
@@ -12097,7 +12028,7 @@ function getToolErrorAttributes(error) {
|
|
|
12097
12028
|
...error.detailRule ? { "app.slack.detail_rule": error.detailRule } : {}
|
|
12098
12029
|
};
|
|
12099
12030
|
}
|
|
12100
|
-
function handleToolExecutionError(error, toolName, toolCallId, shouldTrace,
|
|
12031
|
+
function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, conversationPrivacy, setExecutionSpanAttributes) {
|
|
12101
12032
|
const errorType = getToolErrorType(error);
|
|
12102
12033
|
const errorMessage = getMcpAwareTelemetryMessage(error, conversationPrivacy);
|
|
12103
12034
|
const errorAttributes = {
|
|
@@ -12113,50 +12044,34 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
|
|
|
12113
12044
|
}
|
|
12114
12045
|
if (error instanceof PluginCredentialFailureError) {
|
|
12115
12046
|
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
|
-
);
|
|
12047
|
+
logInfo("plugin.credential.rejected", {
|
|
12048
|
+
"app.credential.provider": error.provider,
|
|
12049
|
+
"gen_ai.operation.name": "execute_tool",
|
|
12050
|
+
"gen_ai.tool.name": toolName,
|
|
12051
|
+
...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
|
|
12052
|
+
"error.type": errorType
|
|
12053
|
+
});
|
|
12128
12054
|
}
|
|
12129
12055
|
throw error;
|
|
12130
12056
|
}
|
|
12131
12057
|
if (shouldTrace) {
|
|
12132
|
-
logWarn(
|
|
12133
|
-
"
|
|
12134
|
-
|
|
12135
|
-
{
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
...errorAttributes,
|
|
12140
|
-
"exception.message": errorMessage
|
|
12141
|
-
},
|
|
12142
|
-
"Agent tool call failed"
|
|
12143
|
-
);
|
|
12058
|
+
logWarn("agent.tool_call.failed", {
|
|
12059
|
+
"gen_ai.operation.name": "execute_tool",
|
|
12060
|
+
"gen_ai.tool.name": toolName,
|
|
12061
|
+
...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
|
|
12062
|
+
...errorAttributes,
|
|
12063
|
+
"exception.message": errorMessage
|
|
12064
|
+
});
|
|
12144
12065
|
}
|
|
12145
12066
|
const isExpectedToolFailure = error instanceof McpToolError || error instanceof ToolInputError || isPluginToolInputError(error);
|
|
12146
12067
|
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
|
-
);
|
|
12068
|
+
logException(error, "agent.tool_call.failed", {
|
|
12069
|
+
"gen_ai.operation.name": "execute_tool",
|
|
12070
|
+
"gen_ai.tool.name": toolName,
|
|
12071
|
+
...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
|
|
12072
|
+
...errorAttributes,
|
|
12073
|
+
...getToolErrorAttributes(error)
|
|
12074
|
+
});
|
|
12160
12075
|
}
|
|
12161
12076
|
throw error;
|
|
12162
12077
|
}
|
|
@@ -12524,15 +12439,10 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
|
|
|
12524
12439
|
try {
|
|
12525
12440
|
await onToolResult?.(report);
|
|
12526
12441
|
} 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
|
-
);
|
|
12442
|
+
logWarn("tool.result.observer.failed", {
|
|
12443
|
+
"gen_ai.tool.name": report.toolName,
|
|
12444
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
12445
|
+
});
|
|
12536
12446
|
}
|
|
12537
12447
|
};
|
|
12538
12448
|
const toolResultOk = (details) => {
|
|
@@ -12591,15 +12501,10 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
|
|
|
12591
12501
|
projectedPrivateResult = toolDef.privateTraceResult(resultAttributeValue);
|
|
12592
12502
|
hasProjectedPrivateResult = projectedPrivateResult !== void 0;
|
|
12593
12503
|
} 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
|
-
);
|
|
12504
|
+
logWarn("tool.private.trace_projection.failed", {
|
|
12505
|
+
"error.type": error instanceof Error ? error.name : typeof error,
|
|
12506
|
+
"gen_ai.tool.name": toolName
|
|
12507
|
+
});
|
|
12603
12508
|
}
|
|
12604
12509
|
}
|
|
12605
12510
|
const toolResultAttribute = effectiveConversationPrivacy === "private" && toolDef.privateTraceResult && !hasProjectedPrivateResult ? void 0 : serializeToolPayload(
|
|
@@ -12713,7 +12618,6 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
|
|
|
12713
12618
|
executionToolName,
|
|
12714
12619
|
toolCallId,
|
|
12715
12620
|
shouldTrace,
|
|
12716
|
-
spanContext,
|
|
12717
12621
|
effectiveConversationPrivacy,
|
|
12718
12622
|
setSpanAttributes2
|
|
12719
12623
|
);
|
|
@@ -13186,26 +13090,21 @@ function logSandboxEgressUpstreamRequest(input) {
|
|
|
13186
13090
|
if (!shouldLogSandboxEgressInfo()) {
|
|
13187
13091
|
return;
|
|
13188
13092
|
}
|
|
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
|
-
);
|
|
13093
|
+
logInfo("sandbox.egress.upstream.requested", {
|
|
13094
|
+
...egressAttributes({
|
|
13095
|
+
egressId: input.egressId,
|
|
13096
|
+
grantAccess: input.grantAccess,
|
|
13097
|
+
grantName: input.grantName,
|
|
13098
|
+
grantReason: input.grantReason,
|
|
13099
|
+
host: input.upstreamUrl.hostname,
|
|
13100
|
+
method: input.request.method,
|
|
13101
|
+
path: input.upstreamUrl.pathname,
|
|
13102
|
+
provider: input.provider,
|
|
13103
|
+
status: input.upstream.status
|
|
13104
|
+
}),
|
|
13105
|
+
...routingAttributes(input.request, input.upstreamUrl),
|
|
13106
|
+
"app.sandbox.egress.upstream_ok": input.upstream.ok
|
|
13107
|
+
});
|
|
13209
13108
|
}
|
|
13210
13109
|
async function requestBodyBytes(request) {
|
|
13211
13110
|
if (request.method === "GET" || request.method === "HEAD" || request.body === null) {
|
|
@@ -13402,22 +13301,18 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13402
13301
|
});
|
|
13403
13302
|
} catch (error) {
|
|
13404
13303
|
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
|
-
);
|
|
13304
|
+
logWarn("sandbox.egress.policy.denied", {
|
|
13305
|
+
...egressAttributes({
|
|
13306
|
+
egressId: activeEgressId,
|
|
13307
|
+
host: upstreamUrl.hostname,
|
|
13308
|
+
method: request.method,
|
|
13309
|
+
path: upstreamUrl.pathname,
|
|
13310
|
+
provider,
|
|
13311
|
+
status: 403
|
|
13312
|
+
}),
|
|
13313
|
+
...routingAttributes(request, upstreamUrl),
|
|
13314
|
+
"app.sandbox.egress.policy.reason": error.message
|
|
13315
|
+
});
|
|
13421
13316
|
return policyDeniedResponse(error);
|
|
13422
13317
|
}
|
|
13423
13318
|
throw error;
|
|
@@ -13445,8 +13340,7 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13445
13340
|
});
|
|
13446
13341
|
const isAuthRequired = error.kind === "auth_required";
|
|
13447
13342
|
logWarn(
|
|
13448
|
-
isAuthRequired ? "
|
|
13449
|
-
{},
|
|
13343
|
+
isAuthRequired ? "sandbox.egress.credential.needed" : "sandbox.egress.credential.unavailable",
|
|
13450
13344
|
{
|
|
13451
13345
|
...egressAttributes({
|
|
13452
13346
|
egressId: activeEgressId,
|
|
@@ -13460,8 +13354,7 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13460
13354
|
status: 401
|
|
13461
13355
|
}),
|
|
13462
13356
|
...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"
|
|
13357
|
+
}
|
|
13465
13358
|
);
|
|
13466
13359
|
return authRequiredResponse({
|
|
13467
13360
|
provider: error.provider,
|
|
@@ -13481,17 +13374,12 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13481
13374
|
upstreamUrl
|
|
13482
13375
|
});
|
|
13483
13376
|
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
|
-
);
|
|
13377
|
+
logWarn("sandbox.egress.transform.missing", {
|
|
13378
|
+
...attributes(403),
|
|
13379
|
+
"app.sandbox.egress.transform_domains": lease.headerTransforms.map(
|
|
13380
|
+
(transform) => transform.domain
|
|
13381
|
+
)
|
|
13382
|
+
});
|
|
13495
13383
|
return Response.json(
|
|
13496
13384
|
{ error: "Credential lease does not cover forwarded host" },
|
|
13497
13385
|
{ status: 403 }
|
|
@@ -13545,14 +13433,9 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13545
13433
|
upstream,
|
|
13546
13434
|
upstreamUrl
|
|
13547
13435
|
});
|
|
13548
|
-
logWarn(
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
{
|
|
13552
|
-
...attributes(upstream.status, upstream)
|
|
13553
|
-
},
|
|
13554
|
-
"Sandbox egress plugin classified upstream response as permission denied"
|
|
13555
|
-
);
|
|
13436
|
+
logWarn("sandbox.egress.upstream_permission.classified", {
|
|
13437
|
+
...attributes(upstream.status, upstream)
|
|
13438
|
+
});
|
|
13556
13439
|
}
|
|
13557
13440
|
} catch (error) {
|
|
13558
13441
|
if (!isEgressAuthRequired(error)) {
|
|
@@ -13566,14 +13449,9 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13566
13449
|
authorization: error.authorization ?? lease.authorization,
|
|
13567
13450
|
message: error.message
|
|
13568
13451
|
});
|
|
13569
|
-
logWarn(
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
{
|
|
13573
|
-
...attributes(upstream.status, upstream)
|
|
13574
|
-
},
|
|
13575
|
-
"Sandbox egress plugin classified upstream response as auth required"
|
|
13576
|
-
);
|
|
13452
|
+
logWarn("sandbox.egress.upstream_auth_requirement.classified", {
|
|
13453
|
+
...attributes(upstream.status, upstream)
|
|
13454
|
+
});
|
|
13577
13455
|
await upstream.body?.cancel().catch(() => void 0);
|
|
13578
13456
|
return authRequiredResponse({
|
|
13579
13457
|
provider,
|
|
@@ -13592,28 +13470,18 @@ async function executeCredentialedEgressRequest(input) {
|
|
|
13592
13470
|
upstreamUrl
|
|
13593
13471
|
});
|
|
13594
13472
|
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
|
-
);
|
|
13473
|
+
logWarn("sandbox.egress.upstream_response.failed", {
|
|
13474
|
+
...attributes(upstream.status, upstream),
|
|
13475
|
+
"error.type": `http_${upstream.status}`
|
|
13476
|
+
});
|
|
13604
13477
|
}
|
|
13605
13478
|
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
|
-
);
|
|
13479
|
+
logWarn("sandbox.egress.upstream_auth.rejected", {
|
|
13480
|
+
...attributes(upstream.status, upstream),
|
|
13481
|
+
...upstream.status === UPSTREAM_TOKEN_REJECTION_STATUS ? {
|
|
13482
|
+
"app.sandbox.egress.www_authenticate": upstream.headers.get("www-authenticate") ?? void 0
|
|
13483
|
+
} : {}
|
|
13484
|
+
});
|
|
13617
13485
|
if (upstream.status === UPSTREAM_TOKEN_REJECTION_STATUS) {
|
|
13618
13486
|
await clearCredentialLease(provider, lease.grant, credentialContext);
|
|
13619
13487
|
await recordAuthRequired({
|
|
@@ -13712,7 +13580,7 @@ function createPluginEgress(deps) {
|
|
|
13712
13580
|
}
|
|
13713
13581
|
|
|
13714
13582
|
// src/chat/agent/tools.ts
|
|
13715
|
-
async function tryRecordSkillLoadStat(skill
|
|
13583
|
+
async function tryRecordSkillLoadStat(skill) {
|
|
13716
13584
|
if (!process.env.DATABASE_URL) return;
|
|
13717
13585
|
try {
|
|
13718
13586
|
await incrementStat({
|
|
@@ -13721,16 +13589,11 @@ async function tryRecordSkillLoadStat(skill, spanContext) {
|
|
|
13721
13589
|
name: skill.name
|
|
13722
13590
|
});
|
|
13723
13591
|
} 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
|
-
);
|
|
13592
|
+
logWarn("skill.load.stat.failed", {
|
|
13593
|
+
"app.skill.name": skill.name,
|
|
13594
|
+
"app.plugin.name": skill.pluginProvider,
|
|
13595
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
13596
|
+
});
|
|
13734
13597
|
}
|
|
13735
13598
|
}
|
|
13736
13599
|
async function wireAgentTools(args) {
|
|
@@ -13800,7 +13663,13 @@ async function wireAgentTools(args) {
|
|
|
13800
13663
|
pluginCatalogRuntime.getMcpProviders(),
|
|
13801
13664
|
{
|
|
13802
13665
|
authProviderFactory: mcpAuth.authProviderFactory,
|
|
13803
|
-
onAuthorizationRequired: mcpAuth.onAuthorizationRequired
|
|
13666
|
+
onAuthorizationRequired: mcpAuth.onAuthorizationRequired,
|
|
13667
|
+
onToolSuccess: async (input) => {
|
|
13668
|
+
await pluginHooks.afterMcpTool({
|
|
13669
|
+
...input,
|
|
13670
|
+
conversationId: args.conversationId
|
|
13671
|
+
});
|
|
13672
|
+
}
|
|
13804
13673
|
}
|
|
13805
13674
|
);
|
|
13806
13675
|
const getPendingAuthPause = () => pluginAuth.getPendingPause() ?? mcpAuth.getPendingPause();
|
|
@@ -13890,7 +13759,7 @@ async function wireAgentTools(args) {
|
|
|
13890
13759
|
if (await mcpToolManager.activateForSkill(effective)) {
|
|
13891
13760
|
await args.recordConnectedMcpProvider(effective.pluginProvider);
|
|
13892
13761
|
}
|
|
13893
|
-
await tryRecordSkillLoadStat(effective
|
|
13762
|
+
await tryRecordSkillLoadStat(effective);
|
|
13894
13763
|
if (mcpAuth.getPendingPause()) {
|
|
13895
13764
|
return void 0;
|
|
13896
13765
|
}
|
|
@@ -13956,15 +13825,10 @@ async function wireAgentTools(args) {
|
|
|
13956
13825
|
toolName
|
|
13957
13826
|
});
|
|
13958
13827
|
} 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
|
-
);
|
|
13828
|
+
logWarn("tool.invocation.observer.failed", {
|
|
13829
|
+
"gen_ai.tool.name": toolName,
|
|
13830
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
13831
|
+
});
|
|
13968
13832
|
}
|
|
13969
13833
|
};
|
|
13970
13834
|
const agentTools = createPiAgentTools(
|
|
@@ -13991,18 +13855,13 @@ async function wireAgentTools(args) {
|
|
|
13991
13855
|
try {
|
|
13992
13856
|
await mcpToolManager.close();
|
|
13993
13857
|
} catch (closeError) {
|
|
13994
|
-
logWarn(
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
14001
|
-
args.conversationPrivacy
|
|
14002
|
-
)
|
|
14003
|
-
},
|
|
14004
|
-
"Failed to close MCP tool manager"
|
|
14005
|
-
);
|
|
13858
|
+
logWarn("mcp.tool_manager.close.failed", {
|
|
13859
|
+
...getMcpProviderErrorAttributes(closeError),
|
|
13860
|
+
"exception.message": getMcpAwareTelemetryMessage(
|
|
13861
|
+
closeError,
|
|
13862
|
+
args.conversationPrivacy
|
|
13863
|
+
)
|
|
13864
|
+
});
|
|
14006
13865
|
}
|
|
14007
13866
|
},
|
|
14008
13867
|
toolGuidance,
|
|
@@ -14035,7 +13894,6 @@ function createResumeState(args) {
|
|
|
14035
13894
|
source: args.runSource,
|
|
14036
13895
|
sessionId: args.turnId,
|
|
14037
13896
|
loadedSkillNames: args.getLoadedSkillNames(),
|
|
14038
|
-
logContext: args.logContext,
|
|
14039
13897
|
modelId: args.getModelId(),
|
|
14040
13898
|
...args.getReasoningLevel() ? { reasoningLevel: args.getReasoningLevel() } : {},
|
|
14041
13899
|
actor: args.actor,
|
|
@@ -14216,6 +14074,7 @@ function createResumeState(args) {
|
|
|
14216
14074
|
}
|
|
14217
14075
|
|
|
14218
14076
|
// src/chat/services/context-compaction.ts
|
|
14077
|
+
import { estimateContextTokens } from "@earendil-works/pi-agent-core";
|
|
14219
14078
|
var RETAINED_USER_MESSAGE_TOKENS = 2e4;
|
|
14220
14079
|
var MAX_SUMMARY_INPUT_CHARS = 8e4;
|
|
14221
14080
|
var MAX_VISIBLE_CONTEXT_CHARS = 2e4;
|
|
@@ -14409,10 +14268,7 @@ async function summarizeContext(args, deps) {
|
|
|
14409
14268
|
return summary.slice(0, MAX_SUMMARY_CHARS);
|
|
14410
14269
|
}
|
|
14411
14270
|
function estimateHistoryTokens(messages) {
|
|
14412
|
-
return messages.
|
|
14413
|
-
(total, message) => total + estimateTextTokens(JSON.stringify(message) ?? ""),
|
|
14414
|
-
0
|
|
14415
|
-
);
|
|
14271
|
+
return estimateContextTokens(messages).tokens;
|
|
14416
14272
|
}
|
|
14417
14273
|
function buildReplacementProvenance(args) {
|
|
14418
14274
|
return [
|
|
@@ -14469,21 +14325,9 @@ async function maybeCompactWithDeps(args, deps) {
|
|
|
14469
14325
|
deps
|
|
14470
14326
|
);
|
|
14471
14327
|
} 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
|
-
);
|
|
14328
|
+
logWarn("context_compaction.summary.failed", {
|
|
14329
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14330
|
+
});
|
|
14487
14331
|
return { compacted: false, reason: "summary_failed" };
|
|
14488
14332
|
}
|
|
14489
14333
|
return await writeCompactedThreadContext(args, source.messages, summary, {
|
|
@@ -14623,23 +14467,11 @@ async function compactActiveContextIfNeeded(args, deps) {
|
|
|
14623
14467
|
inputLimitTokens
|
|
14624
14468
|
);
|
|
14625
14469
|
}
|
|
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
|
-
);
|
|
14470
|
+
logWarn("context_compaction.active.summary.failed", {
|
|
14471
|
+
"app.context_input_limit_tokens": inputLimitTokens,
|
|
14472
|
+
"app.context_tokens_estimated": source.estimatedTokens,
|
|
14473
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14474
|
+
});
|
|
14643
14475
|
return { compacted: false, reason: "summary_failed" };
|
|
14644
14476
|
}
|
|
14645
14477
|
const summaryMessage = userMessage(
|
|
@@ -14741,7 +14573,7 @@ function waitForAbortSettlement(promise, timeoutMs) {
|
|
|
14741
14573
|
);
|
|
14742
14574
|
});
|
|
14743
14575
|
}
|
|
14744
|
-
async function executeAgentRun(request) {
|
|
14576
|
+
async function executeAgentRun(request, streamFn) {
|
|
14745
14577
|
if (!request.routing.destination) {
|
|
14746
14578
|
throw new TypeError("Assistant reply generation requires a destination");
|
|
14747
14579
|
}
|
|
@@ -14776,12 +14608,13 @@ async function executeAgentRun(request) {
|
|
|
14776
14608
|
() => executeAgentRunInPrivacyContext(
|
|
14777
14609
|
request,
|
|
14778
14610
|
conversationPrivacy,
|
|
14779
|
-
runLogContext
|
|
14611
|
+
runLogContext,
|
|
14612
|
+
streamFn
|
|
14780
14613
|
)
|
|
14781
14614
|
)
|
|
14782
14615
|
);
|
|
14783
14616
|
}
|
|
14784
|
-
async function executeAgentRunInPrivacyContext(request, conversationPrivacy, runLogContext) {
|
|
14617
|
+
async function executeAgentRunInPrivacyContext(request, conversationPrivacy, runLogContext, streamFn) {
|
|
14785
14618
|
const { conversationId, input, routing, runId, turnId } = request;
|
|
14786
14619
|
const policy = request.policy ?? {};
|
|
14787
14620
|
const signal = policy.signal;
|
|
@@ -14819,19 +14652,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14819
14652
|
const slackDestination = routing.destination.platform === "slack" ? routing.destination : void 0;
|
|
14820
14653
|
const slackActor = actor?.platform === "slack" ? actor : void 0;
|
|
14821
14654
|
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
14655
|
const recordConnectedMcpProvider = async (provider) => {
|
|
14836
14656
|
if (connectedMcpProviders.has(provider)) {
|
|
14837
14657
|
return;
|
|
@@ -14858,27 +14678,21 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14858
14678
|
const shouldTrace = shouldEmitDevAgentTrace();
|
|
14859
14679
|
const spanContext = { modelId: activeModelId };
|
|
14860
14680
|
const availableSkills = await discoverRunSkills({
|
|
14861
|
-
skillDirs: policy.skillDirs
|
|
14862
|
-
spanContext
|
|
14681
|
+
skillDirs: policy.skillDirs
|
|
14863
14682
|
});
|
|
14864
14683
|
if (shouldTrace) {
|
|
14865
14684
|
const inboundAttachmentCount = input.inboundAttachmentCount ?? 0;
|
|
14866
14685
|
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
|
-
);
|
|
14686
|
+
logInfo("agent.message.received", {
|
|
14687
|
+
"app.message.kind": "user_inbound",
|
|
14688
|
+
"app.message.length": userInput.length,
|
|
14689
|
+
"app.message.input": summarizeMessageText(userInput),
|
|
14690
|
+
// Log both counts so image uploads filtered by vision/config do not
|
|
14691
|
+
// look indistinguishable from Slack ingress dropping attachments.
|
|
14692
|
+
"app.message.attachment_count": inboundAttachmentCount,
|
|
14693
|
+
"app.message.prompt_attachment_count": promptAttachmentCount,
|
|
14694
|
+
"messaging.message.id": slackSource?.messageTs ?? ""
|
|
14695
|
+
});
|
|
14882
14696
|
}
|
|
14883
14697
|
const skillInvocation = parseSkillInvocation(userInput, availableSkills);
|
|
14884
14698
|
const invokedSkill = skillInvocation ? findSkillByName(skillInvocation.skillName, availableSkills) : null;
|
|
@@ -14910,7 +14724,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14910
14724
|
durability,
|
|
14911
14725
|
getLoadedSkillNames: () => loadedSkillNamesForResume,
|
|
14912
14726
|
getReasoningLevel: () => turnRoute?.reasoningLevel,
|
|
14913
|
-
logContext: sessionRecordLogContext,
|
|
14914
14727
|
getModelId: () => activeModelId,
|
|
14915
14728
|
recordActiveMcpProviders,
|
|
14916
14729
|
actor,
|
|
@@ -14930,15 +14743,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14930
14743
|
toolName: event.toolName
|
|
14931
14744
|
});
|
|
14932
14745
|
} 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
|
-
);
|
|
14746
|
+
logException(error, "agent.turn.session_log_append.failed", {
|
|
14747
|
+
"gen_ai.tool.name": event.toolName
|
|
14748
|
+
});
|
|
14942
14749
|
}
|
|
14943
14750
|
};
|
|
14944
14751
|
const persistedConfigurationValues = policy.channelConfiguration ? await policy.channelConfiguration.resolveValues() : {};
|
|
@@ -15073,14 +14880,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15073
14880
|
void (async () => {
|
|
15074
14881
|
await observers.onStatus?.({ text: "Switching models" });
|
|
15075
14882
|
})().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
|
-
);
|
|
14883
|
+
logWarn("assistant.status.observer.failed", {
|
|
14884
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14885
|
+
});
|
|
15084
14886
|
});
|
|
15085
14887
|
const handoffMessages = await compactContextForHandoff(
|
|
15086
14888
|
{
|
|
@@ -15306,12 +15108,12 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15306
15108
|
};
|
|
15307
15109
|
let assistantMessageDeliveryError;
|
|
15308
15110
|
const deliverAssistantMessage = async (message) => {
|
|
15309
|
-
const
|
|
15310
|
-
if (
|
|
15111
|
+
const decision = decideReply(message);
|
|
15112
|
+
if (decision.kind !== "deliver" || !delivery) {
|
|
15311
15113
|
return;
|
|
15312
15114
|
}
|
|
15313
15115
|
try {
|
|
15314
|
-
await delivery
|
|
15116
|
+
await delivery(message);
|
|
15315
15117
|
} catch (error) {
|
|
15316
15118
|
assistantMessageDeliveryError = new AssistantMessageDeliveryError(
|
|
15317
15119
|
error
|
|
@@ -15350,27 +15152,17 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15350
15152
|
steeredMessageCount += piMessages.length;
|
|
15351
15153
|
});
|
|
15352
15154
|
if (steeredMessageCount > 0) {
|
|
15353
|
-
logInfo(
|
|
15354
|
-
"
|
|
15355
|
-
|
|
15356
|
-
{
|
|
15357
|
-
"app.ai.steering_message_count": steeredMessageCount
|
|
15358
|
-
},
|
|
15359
|
-
"Agent turn steering messages accepted"
|
|
15360
|
-
);
|
|
15155
|
+
logInfo("agent.turn.steering_messages.accepted", {
|
|
15156
|
+
"app.ai.steering_message_count": steeredMessageCount
|
|
15157
|
+
});
|
|
15361
15158
|
}
|
|
15362
15159
|
} catch (error) {
|
|
15363
15160
|
if (isTurnInputCommitLostError(error)) {
|
|
15364
15161
|
throw error;
|
|
15365
15162
|
}
|
|
15366
|
-
logWarn(
|
|
15367
|
-
"
|
|
15368
|
-
|
|
15369
|
-
{
|
|
15370
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15371
|
-
},
|
|
15372
|
-
"Agent turn steering message drain failed"
|
|
15373
|
-
);
|
|
15163
|
+
logWarn("agent.turn.steering_messages_drain.failed", {
|
|
15164
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15165
|
+
});
|
|
15374
15166
|
}
|
|
15375
15167
|
return acceptedMessages;
|
|
15376
15168
|
};
|
|
@@ -15378,7 +15170,10 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15378
15170
|
let pendingPiHookError;
|
|
15379
15171
|
agent = new Agent({
|
|
15380
15172
|
...apiKeyOverride ? { getApiKey: () => apiKeyOverride } : {},
|
|
15381
|
-
streamFn: createTracedStreamFn({
|
|
15173
|
+
streamFn: createTracedStreamFn({
|
|
15174
|
+
conversationPrivacy,
|
|
15175
|
+
...streamFn ? { base: streamFn } : {}
|
|
15176
|
+
}),
|
|
15382
15177
|
steeringMode: "all",
|
|
15383
15178
|
beforeToolCall: async ({ assistantMessage }) => {
|
|
15384
15179
|
const toolCalls2 = assistantMessage.content.filter(
|
|
@@ -15522,37 +15317,27 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15522
15317
|
);
|
|
15523
15318
|
} catch (error) {
|
|
15524
15319
|
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
|
-
);
|
|
15320
|
+
logWarn("agent.turn.timed_out", {
|
|
15321
|
+
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
15322
|
+
"gen_ai.operation.name": "invoke_agent",
|
|
15323
|
+
"gen_ai.request.model": activeModelId,
|
|
15324
|
+
...turnRoute ? {
|
|
15325
|
+
"gen_ai.request.reasoning.level": turnRoute.reasoningLevel
|
|
15326
|
+
} : {},
|
|
15327
|
+
"app.ai.turn_timeout_ms": turnTimeoutBudgetMs,
|
|
15328
|
+
"app.ai.turn_deadline_remaining_ms": Math.max(
|
|
15329
|
+
0,
|
|
15330
|
+
turnDeadlineAtMs - Date.now()
|
|
15331
|
+
)
|
|
15332
|
+
});
|
|
15543
15333
|
const settled = await waitForAbortSettlement(
|
|
15544
15334
|
run2,
|
|
15545
15335
|
AGENT_ABORT_SETTLE_GRACE_MS
|
|
15546
15336
|
);
|
|
15547
15337
|
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
|
-
);
|
|
15338
|
+
logWarn("agent.turn.abort_settle.timed_out", {
|
|
15339
|
+
"app.ai.abort_settle_grace_ms": AGENT_ABORT_SETTLE_GRACE_MS
|
|
15340
|
+
});
|
|
15556
15341
|
}
|
|
15557
15342
|
runResume.captureResumeSnapshot(
|
|
15558
15343
|
runResume.getResumeSnapshot(currentAgentMessages())
|
|
@@ -15616,9 +15401,20 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15616
15401
|
]);
|
|
15617
15402
|
}
|
|
15618
15403
|
run = shouldPromptAgent && !capacityUpdate ? agent.prompt(freshPromptMessage) : agent.continue();
|
|
15619
|
-
let
|
|
15404
|
+
let discardedRetryUsage;
|
|
15405
|
+
let providerRetryAttempt = 0;
|
|
15406
|
+
let emptyOutputAttempt = 0;
|
|
15407
|
+
const prepareRetry = async (messages) => {
|
|
15408
|
+
discardedRetryUsage = addAgentTurnUsage(
|
|
15409
|
+
discardedRetryUsage,
|
|
15410
|
+
getDiscardedRetryUsage(agent.state.messages, messages)
|
|
15411
|
+
);
|
|
15412
|
+
agent.state.messages = messages;
|
|
15413
|
+
await runResume.persistSafeBoundary(messages);
|
|
15414
|
+
signal?.throwIfAborted();
|
|
15415
|
+
};
|
|
15620
15416
|
try {
|
|
15621
|
-
for (
|
|
15417
|
+
for (; ; ) {
|
|
15622
15418
|
await runAgentStep(run);
|
|
15623
15419
|
if (assistantMessageDeliveryError) {
|
|
15624
15420
|
throw assistantMessageDeliveryError;
|
|
@@ -15635,7 +15431,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15635
15431
|
const usageSummary = extractGenAiUsageSummary(...outputMessages);
|
|
15636
15432
|
const currentUsage = hasAgentTurnUsage(usageSummary) ? usageSummary : void 0;
|
|
15637
15433
|
const currentPhaseUsage = addAgentTurnUsage(
|
|
15638
|
-
|
|
15434
|
+
discardedRetryUsage,
|
|
15639
15435
|
currentUsage
|
|
15640
15436
|
);
|
|
15641
15437
|
turnUsage = addAgentTurnUsage(priorPhaseUsage, currentPhaseUsage);
|
|
@@ -15650,7 +15446,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15650
15446
|
normalizeGenAiFinishReason(lastAssistant.stopReason)
|
|
15651
15447
|
]
|
|
15652
15448
|
} : {},
|
|
15653
|
-
...extractGenAiUsageAttributes(
|
|
15449
|
+
...extractGenAiUsageAttributes(currentPhaseUsage)
|
|
15654
15450
|
});
|
|
15655
15451
|
const pendingAuthPause = getPendingAuthPause();
|
|
15656
15452
|
if (pendingAuthPause) {
|
|
@@ -15659,25 +15455,37 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15659
15455
|
);
|
|
15660
15456
|
throw pendingAuthPause;
|
|
15661
15457
|
}
|
|
15458
|
+
const emptyOutputContinuation = nextEmptyOutputContinuation({
|
|
15459
|
+
attempt: emptyOutputAttempt,
|
|
15460
|
+
lastAssistant,
|
|
15461
|
+
messages: agent.state.messages
|
|
15462
|
+
});
|
|
15463
|
+
if (emptyOutputContinuation.kind === "retry") {
|
|
15464
|
+
emptyOutputAttempt += 1;
|
|
15465
|
+
await prepareRetry(emptyOutputContinuation.messages);
|
|
15466
|
+
logWarn("agent.turn.empty_output.retrying", {
|
|
15467
|
+
"app.ai.empty_output.attempt": emptyOutputAttempt
|
|
15468
|
+
});
|
|
15469
|
+
run = agent.continue();
|
|
15470
|
+
continue;
|
|
15471
|
+
}
|
|
15472
|
+
if (emptyOutputContinuation.kind === "exhausted") {
|
|
15473
|
+
logWarn("agent.turn.empty_output.exhausted", {
|
|
15474
|
+
"app.ai.empty_output.attempt": emptyOutputAttempt
|
|
15475
|
+
});
|
|
15476
|
+
}
|
|
15662
15477
|
const providerRetry = nextProviderRetry({
|
|
15663
|
-
attempt,
|
|
15478
|
+
attempt: providerRetryAttempt,
|
|
15664
15479
|
failure: lastAssistant,
|
|
15665
15480
|
messages: agent.state.messages
|
|
15666
15481
|
});
|
|
15667
15482
|
if (!providerRetry) {
|
|
15668
15483
|
break;
|
|
15669
15484
|
}
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
15673
|
-
logWarn(
|
|
15674
|
-
"agent_turn_provider_retry",
|
|
15675
|
-
spanContext,
|
|
15676
|
-
{},
|
|
15677
|
-
"Retrying transient provider failure"
|
|
15678
|
-
);
|
|
15485
|
+
providerRetryAttempt += 1;
|
|
15486
|
+
await prepareRetry(providerRetry.messages);
|
|
15487
|
+
logWarn("agent.turn.provider.retrying");
|
|
15679
15488
|
await sleep(providerRetry.delayMs, signal);
|
|
15680
|
-
signal?.throwIfAborted();
|
|
15681
15489
|
run = agent.continue();
|
|
15682
15490
|
}
|
|
15683
15491
|
} catch (error) {
|
|
@@ -15722,7 +15530,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15722
15530
|
durationMs: Date.now() - replyStartedAtMs,
|
|
15723
15531
|
generatedFileCount: generatedFiles.length,
|
|
15724
15532
|
shouldTrace,
|
|
15725
|
-
spanContext,
|
|
15726
15533
|
usage: turnUsage,
|
|
15727
15534
|
executionProfile: turnRoute,
|
|
15728
15535
|
assistantUserName: botConfig.userName,
|
|
@@ -15770,13 +15577,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
15770
15577
|
if (durability.onInputCommitted && !resume?.inputCommitted) {
|
|
15771
15578
|
throw error;
|
|
15772
15579
|
}
|
|
15773
|
-
logException(
|
|
15774
|
-
error,
|
|
15775
|
-
"assistant_reply_generation_failed",
|
|
15776
|
-
{ modelId: activeModelId },
|
|
15777
|
-
{},
|
|
15778
|
-
"executeAgentRun failed"
|
|
15779
|
-
);
|
|
15580
|
+
logException(error, "assistant.reply.generation.failed");
|
|
15780
15581
|
const message = error instanceof Error ? error.message : String(error);
|
|
15781
15582
|
return {
|
|
15782
15583
|
status: "completed",
|