@sentry/junior 0.11.1 → 0.12.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/README.md +1 -8
- package/dist/app.js +252 -317
- package/dist/{chunk-WELSSJJU.js → chunk-IH4T747D.js} +26 -34
- package/dist/{chunk-IRE2LOEJ.js → chunk-SCG4PCEG.js} +1 -1
- package/dist/{chunk-ZYB3U7Q4.js → chunk-Y2LVMCQ3.js} +611 -42
- package/dist/chunk-ZLVM4R7R.js +25 -0
- package/dist/cli/check.js +2 -3
- package/dist/cli/init.js +14 -31
- package/dist/cli/snapshot-warmup.js +2 -3
- package/dist/vercel.d.ts +13 -0
- package/dist/vercel.js +9 -0
- package/package.json +2 -2
- package/dist/chunk-XH7TV4JS.js +0 -560
- package/dist/nitro.d.ts +0 -27
- package/dist/nitro.js +0 -62
package/dist/app.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
logCapabilityCatalogLoadedOnce,
|
|
8
8
|
parseSkillInvocation,
|
|
9
9
|
stripFrontmatter
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-IH4T747D.js";
|
|
11
11
|
import {
|
|
12
12
|
SANDBOX_SKILLS_ROOT,
|
|
13
13
|
SANDBOX_WORKSPACE_ROOT,
|
|
@@ -26,18 +26,22 @@ import {
|
|
|
26
26
|
runNonInteractiveCommand,
|
|
27
27
|
sandboxSkillDir,
|
|
28
28
|
toOptionalTrimmed
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-SCG4PCEG.js";
|
|
30
30
|
import {
|
|
31
31
|
CredentialUnavailableError,
|
|
32
|
+
aboutPathCandidates,
|
|
32
33
|
buildOAuthTokenRequest,
|
|
33
34
|
createPluginBroker,
|
|
34
35
|
createRequestContext,
|
|
36
|
+
discoverInstalledPluginPackageContent,
|
|
35
37
|
extractGenAiUsageAttributes,
|
|
36
38
|
getPluginDefinition,
|
|
37
39
|
getPluginMcpProviders,
|
|
38
40
|
getPluginOAuthConfig,
|
|
39
41
|
getPluginProviders,
|
|
42
|
+
homeDir,
|
|
40
43
|
isPluginProvider,
|
|
44
|
+
isRecord,
|
|
41
45
|
logError,
|
|
42
46
|
logException,
|
|
43
47
|
logInfo,
|
|
@@ -46,21 +50,17 @@ import {
|
|
|
46
50
|
resolveAuthTokenPlaceholder,
|
|
47
51
|
resolveErrorReference,
|
|
48
52
|
serializeGenAiAttribute,
|
|
53
|
+
setPluginPackages,
|
|
49
54
|
setSpanAttributes,
|
|
50
55
|
setSpanStatus,
|
|
51
56
|
setTags,
|
|
57
|
+
soulPathCandidates,
|
|
58
|
+
toOptionalNumber,
|
|
52
59
|
toOptionalString,
|
|
53
60
|
withContext,
|
|
54
61
|
withSpan
|
|
55
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-Y2LVMCQ3.js";
|
|
56
63
|
import "./chunk-Z3YD6NHK.js";
|
|
57
|
-
import {
|
|
58
|
-
aboutPathCandidates,
|
|
59
|
-
discoverInstalledPluginPackageContent,
|
|
60
|
-
homeDir,
|
|
61
|
-
setPluginPackages,
|
|
62
|
-
soulPathCandidates
|
|
63
|
-
} from "./chunk-XH7TV4JS.js";
|
|
64
64
|
import "./chunk-2KG3PWR4.js";
|
|
65
65
|
|
|
66
66
|
// src/app.ts
|
|
@@ -106,24 +106,15 @@ function GET2() {
|
|
|
106
106
|
import { Buffer as Buffer2 } from "buffer";
|
|
107
107
|
|
|
108
108
|
// src/chat/state/conversation.ts
|
|
109
|
-
function isRecord(value) {
|
|
110
|
-
return Boolean(value) && typeof value === "object";
|
|
111
|
-
}
|
|
112
|
-
function toOptionalString2(value) {
|
|
113
|
-
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
114
|
-
}
|
|
115
|
-
function toOptionalNumber(value) {
|
|
116
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
117
|
-
}
|
|
118
109
|
function coerceRole(value) {
|
|
119
110
|
return value === "assistant" || value === "system" || value === "user" ? value : "user";
|
|
120
111
|
}
|
|
121
112
|
function coerceAuthor(value) {
|
|
122
113
|
if (!isRecord(value)) return void 0;
|
|
123
114
|
const author = {
|
|
124
|
-
fullName:
|
|
125
|
-
userId:
|
|
126
|
-
userName:
|
|
115
|
+
fullName: toOptionalString(value.fullName),
|
|
116
|
+
userId: toOptionalString(value.userId),
|
|
117
|
+
userName: toOptionalString(value.userName)
|
|
127
118
|
};
|
|
128
119
|
if (typeof value.isBot === "boolean") {
|
|
129
120
|
author.isBot = value.isBot;
|
|
@@ -194,8 +185,8 @@ function coerceThreadConversationState(value) {
|
|
|
194
185
|
const messages = [];
|
|
195
186
|
for (const item of rawMessages) {
|
|
196
187
|
if (!isRecord(item)) continue;
|
|
197
|
-
const id =
|
|
198
|
-
const text =
|
|
188
|
+
const id = toOptionalString(item.id);
|
|
189
|
+
const text = toOptionalString(item.text);
|
|
199
190
|
const createdAtMs = toOptionalNumber(item.createdAtMs);
|
|
200
191
|
if (!id || !text || !createdAtMs) continue;
|
|
201
192
|
messages.push({
|
|
@@ -211,8 +202,8 @@ function coerceThreadConversationState(value) {
|
|
|
211
202
|
const compactions = [];
|
|
212
203
|
for (const item of rawCompactions) {
|
|
213
204
|
if (!isRecord(item)) continue;
|
|
214
|
-
const id =
|
|
215
|
-
const summary =
|
|
205
|
+
const id = toOptionalString(item.id);
|
|
206
|
+
const summary = toOptionalString(item.summary);
|
|
216
207
|
const createdAtMs = toOptionalNumber(item.createdAtMs);
|
|
217
208
|
if (!id || !summary || !createdAtMs) continue;
|
|
218
209
|
const coveredMessageIds = Array.isArray(item.coveredMessageIds) ? item.coveredMessageIds.filter(
|
|
@@ -232,7 +223,7 @@ function coerceThreadConversationState(value) {
|
|
|
232
223
|
};
|
|
233
224
|
const rawProcessing = isRecord(rawConversation.processing) ? rawConversation.processing : {};
|
|
234
225
|
const processing = {
|
|
235
|
-
activeTurnId:
|
|
226
|
+
activeTurnId: toOptionalString(rawProcessing.activeTurnId),
|
|
236
227
|
lastCompletedAtMs: toOptionalNumber(rawProcessing.lastCompletedAtMs)
|
|
237
228
|
};
|
|
238
229
|
const rawStats = isRecord(rawConversation.stats) ? rawConversation.stats : {};
|
|
@@ -248,7 +239,7 @@ function coerceThreadConversationState(value) {
|
|
|
248
239
|
for (const [fileId, value2] of Object.entries(rawVisionByFileId)) {
|
|
249
240
|
if (typeof fileId !== "string" || fileId.trim().length === 0) continue;
|
|
250
241
|
if (!isRecord(value2)) continue;
|
|
251
|
-
const summary =
|
|
242
|
+
const summary = toOptionalString(value2.summary);
|
|
252
243
|
const analyzedAtMs = toOptionalNumber(value2.analyzedAtMs);
|
|
253
244
|
if (!summary || !analyzedAtMs) continue;
|
|
254
245
|
byFileId[fileId] = {
|
|
@@ -303,9 +294,6 @@ function sessionIndexKey(userId, provider) {
|
|
|
303
294
|
function serverSessionKey(userId, provider) {
|
|
304
295
|
return `${MCP_SERVER_SESSION_PREFIX}:${userId}:${provider}`;
|
|
305
296
|
}
|
|
306
|
-
function isRecord2(value) {
|
|
307
|
-
return typeof value === "object" && value !== null;
|
|
308
|
-
}
|
|
309
297
|
function parseSessionIndex(value) {
|
|
310
298
|
if (typeof value !== "string") {
|
|
311
299
|
return [];
|
|
@@ -328,7 +316,7 @@ function parseMcpAuthSession(value) {
|
|
|
328
316
|
}
|
|
329
317
|
try {
|
|
330
318
|
const parsed = JSON.parse(value);
|
|
331
|
-
if (!
|
|
319
|
+
if (!isRecord(parsed)) {
|
|
332
320
|
return void 0;
|
|
333
321
|
}
|
|
334
322
|
if (typeof parsed.authSessionId !== "string" || typeof parsed.provider !== "string" || typeof parsed.userId !== "string" || typeof parsed.conversationId !== "string" || typeof parsed.sessionId !== "string" || typeof parsed.userMessage !== "string" || typeof parsed.createdAtMs !== "number" || typeof parsed.updatedAtMs !== "number") {
|
|
@@ -346,8 +334,8 @@ function parseMcpAuthSession(value) {
|
|
|
346
334
|
...typeof parsed.channelId === "string" ? { channelId: parsed.channelId } : {},
|
|
347
335
|
...typeof parsed.threadTs === "string" ? { threadTs: parsed.threadTs } : {},
|
|
348
336
|
...typeof parsed.toolChannelId === "string" ? { toolChannelId: parsed.toolChannelId } : {},
|
|
349
|
-
...
|
|
350
|
-
...
|
|
337
|
+
...isRecord(parsed.configuration) ? { configuration: parsed.configuration } : {},
|
|
338
|
+
...isRecord(parsed.artifactState) ? { artifactState: parsed.artifactState } : {},
|
|
351
339
|
...typeof parsed.authorizationUrl === "string" ? { authorizationUrl: parsed.authorizationUrl } : {},
|
|
352
340
|
...typeof parsed.codeVerifier === "string" ? { codeVerifier: parsed.codeVerifier } : {}
|
|
353
341
|
};
|
|
@@ -361,7 +349,7 @@ function parseServerSession(value) {
|
|
|
361
349
|
}
|
|
362
350
|
try {
|
|
363
351
|
const parsed = JSON.parse(value);
|
|
364
|
-
if (!
|
|
352
|
+
if (!isRecord(parsed) || typeof parsed.sessionId !== "string" || typeof parsed.updatedAtMs !== "number") {
|
|
365
353
|
return void 0;
|
|
366
354
|
}
|
|
367
355
|
return {
|
|
@@ -378,17 +366,17 @@ function parseStoredCredentials(value) {
|
|
|
378
366
|
}
|
|
379
367
|
try {
|
|
380
368
|
const parsed = JSON.parse(value);
|
|
381
|
-
if (!
|
|
369
|
+
if (!isRecord(parsed)) {
|
|
382
370
|
return void 0;
|
|
383
371
|
}
|
|
384
372
|
return {
|
|
385
|
-
...
|
|
373
|
+
...isRecord(parsed.clientInformation) ? {
|
|
386
374
|
clientInformation: parsed.clientInformation
|
|
387
375
|
} : {},
|
|
388
|
-
...
|
|
376
|
+
...isRecord(parsed.discoveryState) ? {
|
|
389
377
|
discoveryState: parsed.discoveryState
|
|
390
378
|
} : {},
|
|
391
|
-
...
|
|
379
|
+
...isRecord(parsed.tokens) ? { tokens: parsed.tokens } : {}
|
|
392
380
|
};
|
|
393
381
|
} catch {
|
|
394
382
|
return void 0;
|
|
@@ -887,6 +875,204 @@ async function downloadPrivateSlackFile(url) {
|
|
|
887
875
|
return Buffer.from(await response.arrayBuffer());
|
|
888
876
|
}
|
|
889
877
|
|
|
878
|
+
// src/chat/respond-helpers.ts
|
|
879
|
+
var MAX_INLINE_ATTACHMENT_BASE64_CHARS = 12e4;
|
|
880
|
+
function getSessionIdentifiers(context) {
|
|
881
|
+
return {
|
|
882
|
+
conversationId: context.correlation?.conversationId ?? context.correlation?.threadId ?? context.correlation?.runId,
|
|
883
|
+
sessionId: context.correlation?.turnId
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
function isExecutionDeferralResponse(text) {
|
|
887
|
+
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(
|
|
888
|
+
text
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
function isToolAccessDisclaimerResponse(text) {
|
|
892
|
+
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(
|
|
893
|
+
text
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
function isExecutionEscapeResponse(text) {
|
|
897
|
+
const trimmed = text.trim();
|
|
898
|
+
if (!trimmed) return false;
|
|
899
|
+
return isExecutionDeferralResponse(trimmed) || isToolAccessDisclaimerResponse(trimmed);
|
|
900
|
+
}
|
|
901
|
+
function parseJsonCandidate(text) {
|
|
902
|
+
const trimmed = text.trim();
|
|
903
|
+
if (!trimmed) return void 0;
|
|
904
|
+
try {
|
|
905
|
+
return JSON.parse(trimmed);
|
|
906
|
+
} catch {
|
|
907
|
+
const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
908
|
+
if (!fenced) return void 0;
|
|
909
|
+
try {
|
|
910
|
+
return JSON.parse(fenced[1]);
|
|
911
|
+
} catch {
|
|
912
|
+
return void 0;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
function isToolPayloadShape(payload) {
|
|
917
|
+
if (!payload || typeof payload !== "object") return false;
|
|
918
|
+
const record = payload;
|
|
919
|
+
const type = typeof record.type === "string" ? record.type.toLowerCase() : "";
|
|
920
|
+
if (type.startsWith("tool-")) return true;
|
|
921
|
+
if (type === "tool_use" || type === "tool_call" || type === "tool_result" || type === "tool_error")
|
|
922
|
+
return true;
|
|
923
|
+
const hasToolName = typeof record.toolName === "string" || typeof record.name === "string";
|
|
924
|
+
const hasToolInput = Object.prototype.hasOwnProperty.call(record, "input") || Object.prototype.hasOwnProperty.call(record, "args");
|
|
925
|
+
if (hasToolName && hasToolInput) return true;
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
function isRawToolPayloadResponse(text) {
|
|
929
|
+
const parsed = parseJsonCandidate(text);
|
|
930
|
+
if (Array.isArray(parsed)) {
|
|
931
|
+
return parsed.some((entry) => isToolPayloadShape(entry));
|
|
932
|
+
}
|
|
933
|
+
if (isToolPayloadShape(parsed)) {
|
|
934
|
+
return true;
|
|
935
|
+
}
|
|
936
|
+
const compact = text.replace(/\s+/g, " ");
|
|
937
|
+
return /"type"\s*:\s*"tool[-_](use|call|result|error)"/i.test(compact);
|
|
938
|
+
}
|
|
939
|
+
function toObservablePromptPart(part) {
|
|
940
|
+
if (part.type === "text") {
|
|
941
|
+
return {
|
|
942
|
+
type: "text",
|
|
943
|
+
text: part.text
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
return {
|
|
947
|
+
type: "image",
|
|
948
|
+
mimeType: part.mimeType,
|
|
949
|
+
data: `[omitted:${part.data.length}]`
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
function summarizeMessageText(text) {
|
|
953
|
+
const normalized = text.trim().replace(/\s+/g, " ");
|
|
954
|
+
if (!normalized) {
|
|
955
|
+
return "[empty]";
|
|
956
|
+
}
|
|
957
|
+
return normalized.length > 1200 ? `${normalized.slice(0, 1200)}...` : normalized;
|
|
958
|
+
}
|
|
959
|
+
function buildUserTurnText(userInput, conversationContext) {
|
|
960
|
+
const trimmedContext = conversationContext?.trim();
|
|
961
|
+
if (!trimmedContext) {
|
|
962
|
+
return userInput;
|
|
963
|
+
}
|
|
964
|
+
return [
|
|
965
|
+
"<current-message>",
|
|
966
|
+
userInput,
|
|
967
|
+
"</current-message>",
|
|
968
|
+
"",
|
|
969
|
+
"<thread-conversation-context>",
|
|
970
|
+
"Use this context for continuity across prior thread turns.",
|
|
971
|
+
trimmedContext,
|
|
972
|
+
"</thread-conversation-context>"
|
|
973
|
+
].join("\n");
|
|
974
|
+
}
|
|
975
|
+
function encodeNonImageAttachmentForPrompt(attachment) {
|
|
976
|
+
const base64 = attachment.data.toString("base64");
|
|
977
|
+
const wasTruncated = base64.length > MAX_INLINE_ATTACHMENT_BASE64_CHARS;
|
|
978
|
+
const encodedPayload = wasTruncated ? `${base64.slice(0, MAX_INLINE_ATTACHMENT_BASE64_CHARS)}...` : base64;
|
|
979
|
+
return [
|
|
980
|
+
"<attachment>",
|
|
981
|
+
`filename: ${attachment.filename ?? "unnamed"}`,
|
|
982
|
+
`media_type: ${attachment.mediaType}`,
|
|
983
|
+
"encoding: base64",
|
|
984
|
+
`truncated: ${wasTruncated ? "true" : "false"}`,
|
|
985
|
+
"<data_base64>",
|
|
986
|
+
encodedPayload,
|
|
987
|
+
"</data_base64>",
|
|
988
|
+
"</attachment>"
|
|
989
|
+
].join("\n");
|
|
990
|
+
}
|
|
991
|
+
function buildExecutionFailureMessage(toolErrorCount) {
|
|
992
|
+
if (toolErrorCount > 0) {
|
|
993
|
+
return "I couldn't complete this because one or more required tools failed in this turn. I've logged the failure details.";
|
|
994
|
+
}
|
|
995
|
+
return "I couldn't complete this request in this turn due to an execution failure. I've logged the details for debugging.";
|
|
996
|
+
}
|
|
997
|
+
function isToolResultMessage(value) {
|
|
998
|
+
return typeof value === "object" && value !== null && value.role === "toolResult";
|
|
999
|
+
}
|
|
1000
|
+
function normalizeToolNameFromResult(result) {
|
|
1001
|
+
if (!result || typeof result !== "object") return void 0;
|
|
1002
|
+
const record = result;
|
|
1003
|
+
if (typeof record.toolName === "string" && record.toolName.length > 0) {
|
|
1004
|
+
return record.toolName;
|
|
1005
|
+
}
|
|
1006
|
+
if (typeof record.name === "string" && record.name.length > 0) {
|
|
1007
|
+
return record.name;
|
|
1008
|
+
}
|
|
1009
|
+
return void 0;
|
|
1010
|
+
}
|
|
1011
|
+
function isToolResultError(result) {
|
|
1012
|
+
if (!result || typeof result !== "object") return false;
|
|
1013
|
+
return Boolean(result.isError);
|
|
1014
|
+
}
|
|
1015
|
+
function isAssistantMessage(value) {
|
|
1016
|
+
return typeof value === "object" && value !== null && value.role === "assistant";
|
|
1017
|
+
}
|
|
1018
|
+
function getPiMessageRole(value) {
|
|
1019
|
+
if (!value || typeof value !== "object") {
|
|
1020
|
+
return void 0;
|
|
1021
|
+
}
|
|
1022
|
+
const role = value.role;
|
|
1023
|
+
return typeof role === "string" ? role : void 0;
|
|
1024
|
+
}
|
|
1025
|
+
function extractAssistantText(message) {
|
|
1026
|
+
const content = message.content ?? [];
|
|
1027
|
+
return content.filter(
|
|
1028
|
+
(part) => part.type === "text" && typeof part.text === "string"
|
|
1029
|
+
).map((part) => part.text).join("\n");
|
|
1030
|
+
}
|
|
1031
|
+
function hasCompletedAssistantTurn(messages) {
|
|
1032
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
1033
|
+
const message = messages[index];
|
|
1034
|
+
if (!isAssistantMessage(message)) {
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
const stopReason = message.stopReason;
|
|
1038
|
+
return typeof stopReason === "string" && stopReason !== "error";
|
|
1039
|
+
}
|
|
1040
|
+
return false;
|
|
1041
|
+
}
|
|
1042
|
+
function upsertActiveSkill(activeSkills, next) {
|
|
1043
|
+
const existing = activeSkills.find((skill) => skill.name === next.name);
|
|
1044
|
+
if (existing) {
|
|
1045
|
+
existing.body = next.body;
|
|
1046
|
+
existing.description = next.description;
|
|
1047
|
+
existing.skillPath = next.skillPath;
|
|
1048
|
+
existing.allowedTools = next.allowedTools;
|
|
1049
|
+
existing.requiresCapabilities = next.requiresCapabilities;
|
|
1050
|
+
existing.usesConfig = next.usesConfig;
|
|
1051
|
+
existing.pluginProvider = next.pluginProvider;
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
activeSkills.push(next);
|
|
1055
|
+
}
|
|
1056
|
+
function collectRelevantConfigurationKeys(activeSkills, explicitSkill) {
|
|
1057
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1058
|
+
for (const skill of [
|
|
1059
|
+
...activeSkills,
|
|
1060
|
+
...explicitSkill ? [explicitSkill] : []
|
|
1061
|
+
]) {
|
|
1062
|
+
for (const key of skill.usesConfig ?? []) {
|
|
1063
|
+
keys.add(key);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
return [...keys].sort((a, b) => a.localeCompare(b));
|
|
1067
|
+
}
|
|
1068
|
+
function trimTrailingAssistantMessages(messages) {
|
|
1069
|
+
let end = messages.length;
|
|
1070
|
+
while (end > 0 && getPiMessageRole(messages[end - 1]) === "assistant") {
|
|
1071
|
+
end -= 1;
|
|
1072
|
+
}
|
|
1073
|
+
return end === messages.length ? [...messages] : messages.slice(0, end);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
890
1076
|
// src/chat/oauth-flow.ts
|
|
891
1077
|
var OAUTH_STATE_TTL_MS = 10 * 60 * 1e3;
|
|
892
1078
|
function formatProviderLabel(provider) {
|
|
@@ -1037,36 +1223,6 @@ async function startOAuthFlow(provider, input) {
|
|
|
1037
1223
|
})
|
|
1038
1224
|
};
|
|
1039
1225
|
}
|
|
1040
|
-
function parseJsonCandidate(text) {
|
|
1041
|
-
const trimmed = text.trim();
|
|
1042
|
-
if (!trimmed) return void 0;
|
|
1043
|
-
try {
|
|
1044
|
-
return JSON.parse(trimmed);
|
|
1045
|
-
} catch {
|
|
1046
|
-
const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
1047
|
-
if (!fenced) return void 0;
|
|
1048
|
-
try {
|
|
1049
|
-
return JSON.parse(fenced[1]);
|
|
1050
|
-
} catch {
|
|
1051
|
-
return void 0;
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
function normalizeToolNameFromResult(result) {
|
|
1056
|
-
if (!result || typeof result !== "object") return void 0;
|
|
1057
|
-
const record = result;
|
|
1058
|
-
if (typeof record.toolName === "string" && record.toolName.length > 0) {
|
|
1059
|
-
return record.toolName;
|
|
1060
|
-
}
|
|
1061
|
-
if (typeof record.name === "string" && record.name.length > 0) {
|
|
1062
|
-
return record.name;
|
|
1063
|
-
}
|
|
1064
|
-
return void 0;
|
|
1065
|
-
}
|
|
1066
|
-
function isToolResultError(result) {
|
|
1067
|
-
if (!result || typeof result !== "object") return false;
|
|
1068
|
-
return Boolean(result.isError);
|
|
1069
|
-
}
|
|
1070
1226
|
function extractOAuthStartedPayload(value) {
|
|
1071
1227
|
if (typeof value === "string") {
|
|
1072
1228
|
const parsed = parseJsonCandidate(value);
|
|
@@ -1441,12 +1597,6 @@ function validateConfigValue(value) {
|
|
|
1441
1597
|
}
|
|
1442
1598
|
|
|
1443
1599
|
// src/chat/configuration/service.ts
|
|
1444
|
-
function isRecord3(value) {
|
|
1445
|
-
return Boolean(value) && typeof value === "object";
|
|
1446
|
-
}
|
|
1447
|
-
function toOptionalString3(value) {
|
|
1448
|
-
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1449
|
-
}
|
|
1450
1600
|
function defaultState() {
|
|
1451
1601
|
return {
|
|
1452
1602
|
schemaVersion: 1,
|
|
@@ -1454,17 +1604,17 @@ function defaultState() {
|
|
|
1454
1604
|
};
|
|
1455
1605
|
}
|
|
1456
1606
|
function sanitizeEntry(value) {
|
|
1457
|
-
if (!
|
|
1607
|
+
if (!isRecord(value)) {
|
|
1458
1608
|
return void 0;
|
|
1459
1609
|
}
|
|
1460
|
-
const key =
|
|
1610
|
+
const key = toOptionalString(value.key);
|
|
1461
1611
|
if (!key) {
|
|
1462
1612
|
return void 0;
|
|
1463
1613
|
}
|
|
1464
1614
|
if (validateConfigKey(key)) {
|
|
1465
1615
|
return void 0;
|
|
1466
1616
|
}
|
|
1467
|
-
const updatedAt =
|
|
1617
|
+
const updatedAt = toOptionalString(value.updatedAt);
|
|
1468
1618
|
if (!updatedAt) {
|
|
1469
1619
|
return void 0;
|
|
1470
1620
|
}
|
|
@@ -1477,17 +1627,17 @@ function sanitizeEntry(value) {
|
|
|
1477
1627
|
value: value.value,
|
|
1478
1628
|
scope,
|
|
1479
1629
|
updatedAt,
|
|
1480
|
-
updatedBy:
|
|
1481
|
-
source:
|
|
1482
|
-
expiresAt:
|
|
1630
|
+
updatedBy: toOptionalString(value.updatedBy),
|
|
1631
|
+
source: toOptionalString(value.source),
|
|
1632
|
+
expiresAt: toOptionalString(value.expiresAt)
|
|
1483
1633
|
};
|
|
1484
1634
|
}
|
|
1485
1635
|
function coerceState(raw) {
|
|
1486
|
-
if (!
|
|
1636
|
+
if (!isRecord(raw)) {
|
|
1487
1637
|
return defaultState();
|
|
1488
1638
|
}
|
|
1489
|
-
const rawConfig =
|
|
1490
|
-
const rawEntries =
|
|
1639
|
+
const rawConfig = isRecord(raw.configuration) ? raw.configuration : {};
|
|
1640
|
+
const rawEntries = isRecord(rawConfig.entries) ? rawConfig.entries : {};
|
|
1491
1641
|
const entries = {};
|
|
1492
1642
|
for (const [key, value] of Object.entries(rawEntries)) {
|
|
1493
1643
|
const entry = sanitizeEntry(value);
|
|
@@ -1533,9 +1683,9 @@ function createChannelConfigurationService(storage) {
|
|
|
1533
1683
|
value: input.value,
|
|
1534
1684
|
scope: "conversation",
|
|
1535
1685
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1536
|
-
updatedBy:
|
|
1537
|
-
source:
|
|
1538
|
-
expiresAt:
|
|
1686
|
+
updatedBy: toOptionalString(input.updatedBy),
|
|
1687
|
+
source: toOptionalString(input.source),
|
|
1688
|
+
expiresAt: toOptionalString(input.expiresAt)
|
|
1539
1689
|
};
|
|
1540
1690
|
state.entries[normalizedKey] = nextEntry;
|
|
1541
1691
|
await saveState(state);
|
|
@@ -1709,6 +1859,7 @@ import {
|
|
|
1709
1859
|
getEnvApiKey,
|
|
1710
1860
|
getModels
|
|
1711
1861
|
} from "@mariozechner/pi-ai";
|
|
1862
|
+
import "@mariozechner/pi-ai/anthropic";
|
|
1712
1863
|
var GATEWAY_PROVIDER = "vercel-ai-gateway";
|
|
1713
1864
|
var GEN_AI_PROVIDER_NAME = GATEWAY_PROVIDER;
|
|
1714
1865
|
var GEN_AI_OPERATION_CHAT = "chat";
|
|
@@ -7825,16 +7976,13 @@ var AGENT_TURN_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
|
7825
7976
|
function agentTurnSessionKey(conversationId, sessionId) {
|
|
7826
7977
|
return `${AGENT_TURN_SESSION_PREFIX}:${conversationId}:${sessionId}`;
|
|
7827
7978
|
}
|
|
7828
|
-
function isRecord4(value) {
|
|
7829
|
-
return typeof value === "object" && value !== null;
|
|
7830
|
-
}
|
|
7831
7979
|
function parseAgentTurnSessionCheckpoint(value) {
|
|
7832
7980
|
if (typeof value !== "string") {
|
|
7833
7981
|
return void 0;
|
|
7834
7982
|
}
|
|
7835
7983
|
try {
|
|
7836
7984
|
const parsed = JSON.parse(value);
|
|
7837
|
-
if (!
|
|
7985
|
+
if (!isRecord(parsed)) {
|
|
7838
7986
|
return void 0;
|
|
7839
7987
|
}
|
|
7840
7988
|
const status = parsed.state;
|
|
@@ -8458,14 +8606,7 @@ Note: No file was attached in this turn. I need to attach the file before claimi
|
|
|
8458
8606
|
}
|
|
8459
8607
|
|
|
8460
8608
|
// src/chat/respond.ts
|
|
8461
|
-
var MAX_INLINE_ATTACHMENT_BASE64_CHARS = 12e4;
|
|
8462
8609
|
var startupDiscoveryLogged = false;
|
|
8463
|
-
function getSessionIdentifiers(context) {
|
|
8464
|
-
return {
|
|
8465
|
-
conversationId: context.correlation?.conversationId ?? context.correlation?.threadId ?? context.correlation?.runId,
|
|
8466
|
-
sessionId: context.correlation?.turnId
|
|
8467
|
-
};
|
|
8468
|
-
}
|
|
8469
8610
|
var McpAuthorizationPauseError = class extends Error {
|
|
8470
8611
|
provider;
|
|
8471
8612
|
constructor(provider) {
|
|
@@ -8489,195 +8630,6 @@ async function runAgentContinuation(agent) {
|
|
|
8489
8630
|
}
|
|
8490
8631
|
return await resumable.continue();
|
|
8491
8632
|
}
|
|
8492
|
-
function trimTrailingAssistantMessages(messages) {
|
|
8493
|
-
let end = messages.length;
|
|
8494
|
-
while (end > 0 && getPiMessageRole(messages[end - 1]) === "assistant") {
|
|
8495
|
-
end -= 1;
|
|
8496
|
-
}
|
|
8497
|
-
return end === messages.length ? [...messages] : messages.slice(0, end);
|
|
8498
|
-
}
|
|
8499
|
-
function isExecutionDeferralResponse(text) {
|
|
8500
|
-
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(
|
|
8501
|
-
text
|
|
8502
|
-
);
|
|
8503
|
-
}
|
|
8504
|
-
function isToolAccessDisclaimerResponse(text) {
|
|
8505
|
-
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(
|
|
8506
|
-
text
|
|
8507
|
-
);
|
|
8508
|
-
}
|
|
8509
|
-
function isExecutionEscapeResponse(text) {
|
|
8510
|
-
const trimmed = text.trim();
|
|
8511
|
-
if (!trimmed) return false;
|
|
8512
|
-
return isExecutionDeferralResponse(trimmed) || isToolAccessDisclaimerResponse(trimmed);
|
|
8513
|
-
}
|
|
8514
|
-
function parseJsonCandidate3(text) {
|
|
8515
|
-
const trimmed = text.trim();
|
|
8516
|
-
if (!trimmed) return void 0;
|
|
8517
|
-
try {
|
|
8518
|
-
return JSON.parse(trimmed);
|
|
8519
|
-
} catch {
|
|
8520
|
-
const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
8521
|
-
if (!fenced) return void 0;
|
|
8522
|
-
try {
|
|
8523
|
-
return JSON.parse(fenced[1]);
|
|
8524
|
-
} catch {
|
|
8525
|
-
return void 0;
|
|
8526
|
-
}
|
|
8527
|
-
}
|
|
8528
|
-
}
|
|
8529
|
-
function isToolPayloadShape(payload) {
|
|
8530
|
-
if (!payload || typeof payload !== "object") return false;
|
|
8531
|
-
const record = payload;
|
|
8532
|
-
const type = typeof record.type === "string" ? record.type.toLowerCase() : "";
|
|
8533
|
-
if (type.startsWith("tool-")) return true;
|
|
8534
|
-
if (type === "tool_use" || type === "tool_call" || type === "tool_result" || type === "tool_error")
|
|
8535
|
-
return true;
|
|
8536
|
-
const hasToolName = typeof record.toolName === "string" || typeof record.name === "string";
|
|
8537
|
-
const hasToolInput = Object.prototype.hasOwnProperty.call(record, "input") || Object.prototype.hasOwnProperty.call(record, "args");
|
|
8538
|
-
if (hasToolName && hasToolInput) return true;
|
|
8539
|
-
return false;
|
|
8540
|
-
}
|
|
8541
|
-
function isRawToolPayloadResponse(text) {
|
|
8542
|
-
const parsed = parseJsonCandidate3(text);
|
|
8543
|
-
if (Array.isArray(parsed)) {
|
|
8544
|
-
return parsed.some((entry) => isToolPayloadShape(entry));
|
|
8545
|
-
}
|
|
8546
|
-
if (isToolPayloadShape(parsed)) {
|
|
8547
|
-
return true;
|
|
8548
|
-
}
|
|
8549
|
-
const compact = text.replace(/\s+/g, " ");
|
|
8550
|
-
return /"type"\s*:\s*"tool[-_](use|call|result|error)"/i.test(compact);
|
|
8551
|
-
}
|
|
8552
|
-
function toObservablePromptPart(part) {
|
|
8553
|
-
if (part.type === "text") {
|
|
8554
|
-
return {
|
|
8555
|
-
type: "text",
|
|
8556
|
-
text: part.text
|
|
8557
|
-
};
|
|
8558
|
-
}
|
|
8559
|
-
return {
|
|
8560
|
-
type: "image",
|
|
8561
|
-
mimeType: part.mimeType,
|
|
8562
|
-
data: `[omitted:${part.data.length}]`
|
|
8563
|
-
};
|
|
8564
|
-
}
|
|
8565
|
-
function summarizeMessageText(text) {
|
|
8566
|
-
const normalized = text.trim().replace(/\s+/g, " ");
|
|
8567
|
-
if (!normalized) {
|
|
8568
|
-
return "[empty]";
|
|
8569
|
-
}
|
|
8570
|
-
return normalized.length > 1200 ? `${normalized.slice(0, 1200)}...` : normalized;
|
|
8571
|
-
}
|
|
8572
|
-
function buildUserTurnText(userInput, conversationContext) {
|
|
8573
|
-
const trimmedContext = conversationContext?.trim();
|
|
8574
|
-
if (!trimmedContext) {
|
|
8575
|
-
return userInput;
|
|
8576
|
-
}
|
|
8577
|
-
return [
|
|
8578
|
-
"<current-message>",
|
|
8579
|
-
userInput,
|
|
8580
|
-
"</current-message>",
|
|
8581
|
-
"",
|
|
8582
|
-
"<thread-conversation-context>",
|
|
8583
|
-
"Use this context for continuity across prior thread turns.",
|
|
8584
|
-
trimmedContext,
|
|
8585
|
-
"</thread-conversation-context>"
|
|
8586
|
-
].join("\n");
|
|
8587
|
-
}
|
|
8588
|
-
function encodeNonImageAttachmentForPrompt(attachment) {
|
|
8589
|
-
const base64 = attachment.data.toString("base64");
|
|
8590
|
-
const wasTruncated = base64.length > MAX_INLINE_ATTACHMENT_BASE64_CHARS;
|
|
8591
|
-
const encodedPayload = wasTruncated ? `${base64.slice(0, MAX_INLINE_ATTACHMENT_BASE64_CHARS)}...` : base64;
|
|
8592
|
-
return [
|
|
8593
|
-
"<attachment>",
|
|
8594
|
-
`filename: ${attachment.filename ?? "unnamed"}`,
|
|
8595
|
-
`media_type: ${attachment.mediaType}`,
|
|
8596
|
-
"encoding: base64",
|
|
8597
|
-
`truncated: ${wasTruncated ? "true" : "false"}`,
|
|
8598
|
-
"<data_base64>",
|
|
8599
|
-
encodedPayload,
|
|
8600
|
-
"</data_base64>",
|
|
8601
|
-
"</attachment>"
|
|
8602
|
-
].join("\n");
|
|
8603
|
-
}
|
|
8604
|
-
function buildExecutionFailureMessage(toolErrorCount) {
|
|
8605
|
-
if (toolErrorCount > 0) {
|
|
8606
|
-
return "I couldn\u2019t complete this because one or more required tools failed in this turn. I\u2019ve logged the failure details.";
|
|
8607
|
-
}
|
|
8608
|
-
return "I couldn\u2019t complete this request in this turn due to an execution failure. I\u2019ve logged the details for debugging.";
|
|
8609
|
-
}
|
|
8610
|
-
function isToolResultMessage(value) {
|
|
8611
|
-
return typeof value === "object" && value !== null && value.role === "toolResult";
|
|
8612
|
-
}
|
|
8613
|
-
function normalizeToolNameFromResult2(result) {
|
|
8614
|
-
if (!result || typeof result !== "object") return void 0;
|
|
8615
|
-
const record = result;
|
|
8616
|
-
if (typeof record.toolName === "string" && record.toolName.length > 0) {
|
|
8617
|
-
return record.toolName;
|
|
8618
|
-
}
|
|
8619
|
-
if (typeof record.name === "string" && record.name.length > 0) {
|
|
8620
|
-
return record.name;
|
|
8621
|
-
}
|
|
8622
|
-
return void 0;
|
|
8623
|
-
}
|
|
8624
|
-
function isToolResultError2(result) {
|
|
8625
|
-
if (!result || typeof result !== "object") return false;
|
|
8626
|
-
return Boolean(result.isError);
|
|
8627
|
-
}
|
|
8628
|
-
function isAssistantMessage(value) {
|
|
8629
|
-
return typeof value === "object" && value !== null && value.role === "assistant";
|
|
8630
|
-
}
|
|
8631
|
-
function getPiMessageRole(value) {
|
|
8632
|
-
if (!value || typeof value !== "object") {
|
|
8633
|
-
return void 0;
|
|
8634
|
-
}
|
|
8635
|
-
const role = value.role;
|
|
8636
|
-
return typeof role === "string" ? role : void 0;
|
|
8637
|
-
}
|
|
8638
|
-
function extractAssistantText(message) {
|
|
8639
|
-
const content = message.content ?? [];
|
|
8640
|
-
return content.filter(
|
|
8641
|
-
(part) => part.type === "text" && typeof part.text === "string"
|
|
8642
|
-
).map((part) => part.text).join("\n");
|
|
8643
|
-
}
|
|
8644
|
-
function hasCompletedAssistantTurn(messages) {
|
|
8645
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
8646
|
-
const message = messages[index];
|
|
8647
|
-
if (!isAssistantMessage(message)) {
|
|
8648
|
-
continue;
|
|
8649
|
-
}
|
|
8650
|
-
const stopReason = message.stopReason;
|
|
8651
|
-
return typeof stopReason === "string" && stopReason !== "error";
|
|
8652
|
-
}
|
|
8653
|
-
return false;
|
|
8654
|
-
}
|
|
8655
|
-
function upsertActiveSkill(activeSkills, next) {
|
|
8656
|
-
const existing = activeSkills.find((skill) => skill.name === next.name);
|
|
8657
|
-
if (existing) {
|
|
8658
|
-
existing.body = next.body;
|
|
8659
|
-
existing.description = next.description;
|
|
8660
|
-
existing.skillPath = next.skillPath;
|
|
8661
|
-
existing.allowedTools = next.allowedTools;
|
|
8662
|
-
existing.requiresCapabilities = next.requiresCapabilities;
|
|
8663
|
-
existing.usesConfig = next.usesConfig;
|
|
8664
|
-
existing.pluginProvider = next.pluginProvider;
|
|
8665
|
-
return;
|
|
8666
|
-
}
|
|
8667
|
-
activeSkills.push(next);
|
|
8668
|
-
}
|
|
8669
|
-
function collectRelevantConfigurationKeys(activeSkills, explicitSkill) {
|
|
8670
|
-
const keys = /* @__PURE__ */ new Set();
|
|
8671
|
-
for (const skill of [
|
|
8672
|
-
...activeSkills,
|
|
8673
|
-
...explicitSkill ? [explicitSkill] : []
|
|
8674
|
-
]) {
|
|
8675
|
-
for (const key of skill.usesConfig ?? []) {
|
|
8676
|
-
keys.add(key);
|
|
8677
|
-
}
|
|
8678
|
-
}
|
|
8679
|
-
return [...keys].sort((a, b) => a.localeCompare(b));
|
|
8680
|
-
}
|
|
8681
8633
|
async function generateAssistantReply(messageText, context = {}) {
|
|
8682
8634
|
let timeoutResumeConversationId;
|
|
8683
8635
|
let timeoutResumeSessionId;
|
|
@@ -9175,7 +9127,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9175
9127
|
).length;
|
|
9176
9128
|
const explicitChannelPostIntent = isExplicitChannelPostIntent(userInput);
|
|
9177
9129
|
const successfulToolNames = new Set(
|
|
9178
|
-
toolResults.filter((result) => !
|
|
9130
|
+
toolResults.filter((result) => !isToolResultError(result)).map((result) => normalizeToolNameFromResult(result)).filter((value) => Boolean(value))
|
|
9179
9131
|
);
|
|
9180
9132
|
const channelPostPerformed = successfulToolNames.has(
|
|
9181
9133
|
"slackChannelPostMessage"
|
|
@@ -10470,11 +10422,12 @@ async function decideSubscribedThreadReply(args) {
|
|
|
10470
10422
|
}
|
|
10471
10423
|
|
|
10472
10424
|
// src/chat/slack/context.ts
|
|
10473
|
-
function
|
|
10474
|
-
|
|
10425
|
+
function toTrimmedSlackString(value) {
|
|
10426
|
+
const normalized = toOptionalString(value);
|
|
10427
|
+
return normalized?.trim() || void 0;
|
|
10475
10428
|
}
|
|
10476
10429
|
function parseSlackThreadId(threadId) {
|
|
10477
|
-
const normalizedThreadId =
|
|
10430
|
+
const normalizedThreadId = toTrimmedSlackString(threadId);
|
|
10478
10431
|
if (!normalizedThreadId) {
|
|
10479
10432
|
return void 0;
|
|
10480
10433
|
}
|
|
@@ -10482,8 +10435,8 @@ function parseSlackThreadId(threadId) {
|
|
|
10482
10435
|
if (parts.length !== 3 || parts[0] !== "slack") {
|
|
10483
10436
|
return void 0;
|
|
10484
10437
|
}
|
|
10485
|
-
const channelId =
|
|
10486
|
-
const threadTs =
|
|
10438
|
+
const channelId = toTrimmedSlackString(parts[1]);
|
|
10439
|
+
const threadTs = toTrimmedSlackString(parts[2]);
|
|
10487
10440
|
if (!channelId || !threadTs) {
|
|
10488
10441
|
return void 0;
|
|
10489
10442
|
}
|
|
@@ -10493,7 +10446,7 @@ function resolveSlackChannelIdFromThreadId(threadId) {
|
|
|
10493
10446
|
return parseSlackThreadId(threadId)?.channelId;
|
|
10494
10447
|
}
|
|
10495
10448
|
function resolveSlackChannelIdFromMessage(message) {
|
|
10496
|
-
const messageChannelId =
|
|
10449
|
+
const messageChannelId = toTrimmedSlackString(
|
|
10497
10450
|
message.channelId
|
|
10498
10451
|
);
|
|
10499
10452
|
if (messageChannelId) {
|
|
@@ -10501,12 +10454,14 @@ function resolveSlackChannelIdFromMessage(message) {
|
|
|
10501
10454
|
}
|
|
10502
10455
|
const raw = message.raw;
|
|
10503
10456
|
if (raw && typeof raw === "object") {
|
|
10504
|
-
const rawChannel =
|
|
10457
|
+
const rawChannel = toTrimmedSlackString(
|
|
10458
|
+
raw.channel
|
|
10459
|
+
);
|
|
10505
10460
|
if (rawChannel) {
|
|
10506
10461
|
return rawChannel;
|
|
10507
10462
|
}
|
|
10508
10463
|
}
|
|
10509
|
-
const threadId =
|
|
10464
|
+
const threadId = toTrimmedSlackString(
|
|
10510
10465
|
message.threadId
|
|
10511
10466
|
);
|
|
10512
10467
|
return resolveSlackChannelIdFromThreadId(threadId);
|
|
@@ -10573,26 +10528,6 @@ function getSlackApiErrorCode(error) {
|
|
|
10573
10528
|
}
|
|
10574
10529
|
return void 0;
|
|
10575
10530
|
}
|
|
10576
|
-
function getSlackHeaderString(headers, name) {
|
|
10577
|
-
if (!headers || typeof headers !== "object") {
|
|
10578
|
-
return void 0;
|
|
10579
|
-
}
|
|
10580
|
-
const normalizedName = name.toLowerCase();
|
|
10581
|
-
const record = headers;
|
|
10582
|
-
for (const [key, value] of Object.entries(record)) {
|
|
10583
|
-
if (key.toLowerCase() !== normalizedName) {
|
|
10584
|
-
continue;
|
|
10585
|
-
}
|
|
10586
|
-
if (typeof value === "string") {
|
|
10587
|
-
return value;
|
|
10588
|
-
}
|
|
10589
|
-
if (Array.isArray(value)) {
|
|
10590
|
-
const first = value.find((entry) => typeof entry === "string");
|
|
10591
|
-
return typeof first === "string" ? first : void 0;
|
|
10592
|
-
}
|
|
10593
|
-
}
|
|
10594
|
-
return void 0;
|
|
10595
|
-
}
|
|
10596
10531
|
function getSlackErrorObservabilityAttributes(error) {
|
|
10597
10532
|
if (!error || typeof error !== "object") {
|
|
10598
10533
|
return {};
|
|
@@ -10605,7 +10540,7 @@ function getSlackErrorObservabilityAttributes(error) {
|
|
|
10605
10540
|
if (typeof candidate.data?.error === "string" && candidate.data.error.trim().length > 0) {
|
|
10606
10541
|
attributes["app.slack.api_error"] = candidate.data.error;
|
|
10607
10542
|
}
|
|
10608
|
-
const requestId =
|
|
10543
|
+
const requestId = getHeaderString(candidate.headers, "x-slack-req-id");
|
|
10609
10544
|
if (requestId) {
|
|
10610
10545
|
attributes["app.slack.request_id"] = requestId;
|
|
10611
10546
|
}
|