@sentry/junior 0.67.0 → 0.67.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts +7 -0
- package/dist/app.js +321 -191
- package/dist/chat/config.d.ts +10 -0
- package/dist/chat/services/message-actor-identity.d.ts +8 -0
- package/dist/chat/services/requester-identity.d.ts +19 -0
- package/dist/chat/slack/user.d.ts +3 -0
- package/dist/chat/task-execution/slack-work.d.ts +2 -0
- package/dist/{chunk-NWU2Z6SM.js → chunk-EBVQXCD2.js} +57 -6
- package/dist/{chunk-6QWWMZCK.js → chunk-OIIXZOOC.js} +101 -6
- package/dist/{chunk-KWEE2436.js → chunk-PIVOJIUD.js} +2 -2
- package/dist/{chunk-HFMZE67J.js → chunk-PLJTW7IB.js} +8 -6
- package/dist/{chunk-YL5G5YC4.js → chunk-V47RLIO2.js} +1 -1
- package/dist/cli/check.js +2 -2
- package/dist/cli/snapshot-warmup.js +3 -3
- package/dist/reporting.js +4 -4
- package/package.json +3 -3
package/dist/app.js
CHANGED
|
@@ -47,13 +47,13 @@ import {
|
|
|
47
47
|
validateAgentPlugins,
|
|
48
48
|
verifySlackDirectCredentialSubject,
|
|
49
49
|
withSlackRetries
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-PLJTW7IB.js";
|
|
51
51
|
import {
|
|
52
52
|
discoverSkills,
|
|
53
53
|
findSkillByName,
|
|
54
54
|
loadSkillsByName,
|
|
55
55
|
parseSkillInvocation
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-V47RLIO2.js";
|
|
57
57
|
import {
|
|
58
58
|
buildNonInteractiveShellScript,
|
|
59
59
|
createSandboxInstance,
|
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
isSnapshotMissingError,
|
|
63
63
|
resolveRuntimeDependencySnapshot,
|
|
64
64
|
runNonInteractiveCommand
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-PIVOJIUD.js";
|
|
66
66
|
import {
|
|
67
67
|
ACTIVE_LOCK_TTL_MS,
|
|
68
68
|
FUNCTION_TIMEOUT_BUFFER_SECONDS,
|
|
@@ -83,8 +83,10 @@ import {
|
|
|
83
83
|
getSlackBotToken,
|
|
84
84
|
getSlackClientId,
|
|
85
85
|
getSlackClientSecret,
|
|
86
|
+
getSlackReactionConfig,
|
|
86
87
|
getSlackSigningSecret,
|
|
87
88
|
getStateAdapter,
|
|
89
|
+
normalizeSlackEmojiName,
|
|
88
90
|
parseSlackThreadId,
|
|
89
91
|
resolveConversationPrivacy,
|
|
90
92
|
resolveGatewayModel,
|
|
@@ -92,14 +94,16 @@ import {
|
|
|
92
94
|
resolveSlackChannelIdFromThreadId,
|
|
93
95
|
sandboxSkillDir,
|
|
94
96
|
sandboxSkillFile,
|
|
97
|
+
setSlackReactionConfig,
|
|
95
98
|
toGenAiMessageMetadata,
|
|
96
99
|
toGenAiMessagesTraceAttributes,
|
|
97
100
|
toGenAiPayloadMetadata,
|
|
98
101
|
toGenAiPayloadTraceAttributes,
|
|
99
102
|
toGenAiTextMetadata
|
|
100
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-EBVQXCD2.js";
|
|
101
104
|
import {
|
|
102
105
|
CredentialUnavailableError,
|
|
106
|
+
buildActorIdentity,
|
|
103
107
|
buildOAuthTokenRequest,
|
|
104
108
|
buildTurnFailureResponse,
|
|
105
109
|
createChatSdkLogger,
|
|
@@ -116,6 +120,7 @@ import {
|
|
|
116
120
|
getPluginOAuthConfig,
|
|
117
121
|
getPluginProviders,
|
|
118
122
|
hasRequiredOAuthScope,
|
|
123
|
+
isActorUserId,
|
|
119
124
|
isPluginConfigKey,
|
|
120
125
|
isPluginProvider,
|
|
121
126
|
isRecord,
|
|
@@ -124,6 +129,7 @@ import {
|
|
|
124
129
|
logInfo,
|
|
125
130
|
logWarn,
|
|
126
131
|
normalizeGenAiFinishReason,
|
|
132
|
+
parseActorUserId,
|
|
127
133
|
parseCredentialContext,
|
|
128
134
|
parseOAuthTokenResponse,
|
|
129
135
|
resolveAuthTokenPlaceholder,
|
|
@@ -134,11 +140,12 @@ import {
|
|
|
134
140
|
setSpanAttributes,
|
|
135
141
|
setSpanStatus,
|
|
136
142
|
setTags,
|
|
143
|
+
slackActorIdentity,
|
|
137
144
|
toOptionalNumber,
|
|
138
145
|
toOptionalString,
|
|
139
146
|
withContext,
|
|
140
147
|
withSpan
|
|
141
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-OIIXZOOC.js";
|
|
142
149
|
import {
|
|
143
150
|
sentry_exports
|
|
144
151
|
} from "./chunk-Z3YD6NHK.js";
|
|
@@ -3335,17 +3342,6 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
3335
3342
|
// src/chat/tools/slack/channel-post-message.ts
|
|
3336
3343
|
import { Type as Type14 } from "@sinclair/typebox";
|
|
3337
3344
|
|
|
3338
|
-
// src/chat/slack/emoji.ts
|
|
3339
|
-
var SLACK_EMOJI_NAME_RE = /^(?:[a-z0-9_+-]+)(?:::(?:skin-tone-[2-6]))?$/;
|
|
3340
|
-
function normalizeSlackEmojiName(value) {
|
|
3341
|
-
const trimmed = value.trim().toLowerCase();
|
|
3342
|
-
if (!trimmed) {
|
|
3343
|
-
return null;
|
|
3344
|
-
}
|
|
3345
|
-
const normalized = trimmed.startsWith(":") && trimmed.endsWith(":") ? trimmed.slice(1, -1) : trimmed;
|
|
3346
|
-
return SLACK_EMOJI_NAME_RE.test(normalized) ? normalized : null;
|
|
3347
|
-
}
|
|
3348
|
-
|
|
3349
3345
|
// src/chat/slack/outbound.ts
|
|
3350
3346
|
var MAX_SLACK_MESSAGE_TEXT_CHARS = 4e4;
|
|
3351
3347
|
function requireSlackConversationId(channelId, action) {
|
|
@@ -3453,7 +3449,7 @@ async function postSlackEphemeralMessage(input) {
|
|
|
3453
3449
|
input.channelId,
|
|
3454
3450
|
"Slack ephemeral message posting"
|
|
3455
3451
|
);
|
|
3456
|
-
const userId = input.userId
|
|
3452
|
+
const userId = parseActorUserId(input.userId);
|
|
3457
3453
|
if (!userId) {
|
|
3458
3454
|
throw new Error("Slack ephemeral message posting requires a user ID");
|
|
3459
3455
|
}
|
|
@@ -11224,13 +11220,17 @@ function extractSliceUsage(messages, beforeMessageCount) {
|
|
|
11224
11220
|
return hasAgentTurnUsage(usage) ? usage : void 0;
|
|
11225
11221
|
}
|
|
11226
11222
|
function requesterFromContext(requester, requesterId) {
|
|
11227
|
-
const identity =
|
|
11228
|
-
|
|
11229
|
-
...
|
|
11230
|
-
...
|
|
11231
|
-
...
|
|
11223
|
+
const identity = actorRequesterFromContext(requester, requesterId);
|
|
11224
|
+
const agentRequester = {
|
|
11225
|
+
...identity?.email ? { email: identity.email } : {},
|
|
11226
|
+
...identity?.fullName ? { fullName: identity.fullName } : {},
|
|
11227
|
+
...identity?.userId ? { slackUserId: identity.userId } : {},
|
|
11228
|
+
...identity?.userName ? { slackUserName: identity.userName } : {}
|
|
11232
11229
|
};
|
|
11233
|
-
return Object.keys(
|
|
11230
|
+
return Object.keys(agentRequester).length > 0 ? agentRequester : void 0;
|
|
11231
|
+
}
|
|
11232
|
+
function actorRequesterFromContext(requester, requesterId) {
|
|
11233
|
+
return buildActorIdentity(requester, requesterId);
|
|
11234
11234
|
}
|
|
11235
11235
|
function surfaceFromContext(context) {
|
|
11236
11236
|
if (context.surface) {
|
|
@@ -11364,6 +11364,10 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11364
11364
|
context.requester,
|
|
11365
11365
|
context.correlation?.requesterId
|
|
11366
11366
|
);
|
|
11367
|
+
const actorRequester = actorRequesterFromContext(
|
|
11368
|
+
context.requester,
|
|
11369
|
+
context.correlation?.requesterId
|
|
11370
|
+
);
|
|
11367
11371
|
const surface = surfaceFromContext(context);
|
|
11368
11372
|
const credentialActor = context.credentialContext?.actor;
|
|
11369
11373
|
const credentialActorLogContext = credentialActor ? {
|
|
@@ -11493,7 +11497,7 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11493
11497
|
const authRequesterId = context.credentialContext?.actor.type === "user" ? context.credentialContext.actor.userId : void 0;
|
|
11494
11498
|
const userTokenStore = createUserTokenStore();
|
|
11495
11499
|
const agentPluginHooks = createAgentPluginHookRunner({
|
|
11496
|
-
requester:
|
|
11500
|
+
requester: actorRequester
|
|
11497
11501
|
});
|
|
11498
11502
|
sandboxExecutor = createSandboxExecutor({
|
|
11499
11503
|
sandboxId: context.sandbox?.sandboxId,
|
|
@@ -11510,7 +11514,7 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11510
11514
|
const result = await maybeExecuteJrRpcCustomCommand(command, {
|
|
11511
11515
|
activeSkill: skillSandbox.getActiveSkill(),
|
|
11512
11516
|
channelConfiguration: context.channelConfiguration,
|
|
11513
|
-
requesterId:
|
|
11517
|
+
requesterId: actorRequester?.userId,
|
|
11514
11518
|
onConfigurationValueChanged: (key, value) => {
|
|
11515
11519
|
if (value === void 0) {
|
|
11516
11520
|
delete configurationValues[key];
|
|
@@ -11746,7 +11750,7 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11746
11750
|
{
|
|
11747
11751
|
channelId: toolChannelId,
|
|
11748
11752
|
channelCapabilities,
|
|
11749
|
-
requester:
|
|
11753
|
+
requester: actorRequester,
|
|
11750
11754
|
teamId: context.correlation?.teamId,
|
|
11751
11755
|
messageTs: context.correlation?.messageTs,
|
|
11752
11756
|
threadTs: context.correlation?.threadTs,
|
|
@@ -11809,7 +11813,7 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11809
11813
|
slackConversation: context.slackConversation
|
|
11810
11814
|
},
|
|
11811
11815
|
invocation: skillInvocation,
|
|
11812
|
-
requester:
|
|
11816
|
+
requester: actorRequester,
|
|
11813
11817
|
artifactState: context.artifactState,
|
|
11814
11818
|
configuration: configurationValues
|
|
11815
11819
|
}) : null;
|
|
@@ -12445,6 +12449,7 @@ var CONTEXT_MIN_LIVE_MESSAGES = 12;
|
|
|
12445
12449
|
var CONTEXT_COMPACTION_BATCH_SIZE = 24;
|
|
12446
12450
|
var CONTEXT_MAX_COMPACTIONS = 16;
|
|
12447
12451
|
var CONTEXT_MAX_MESSAGE_CHARS = 3200;
|
|
12452
|
+
var SLACK_USER_ID_DISPLAY_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
12448
12453
|
function generateConversationId(prefix) {
|
|
12449
12454
|
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
12450
12455
|
}
|
|
@@ -12464,7 +12469,7 @@ function buildImageContextSuffix(message, conversation) {
|
|
|
12464
12469
|
return ` [image context: ${summaries.join(" | ")}]`;
|
|
12465
12470
|
}
|
|
12466
12471
|
function renderConversationMessageLine(message, conversation) {
|
|
12467
|
-
const displayName =
|
|
12472
|
+
const displayName = conversationAuthorDisplayName(message);
|
|
12468
12473
|
const markers = [];
|
|
12469
12474
|
if (message.meta?.replied === false) {
|
|
12470
12475
|
markers.push(
|
|
@@ -12478,6 +12483,18 @@ function renderConversationMessageLine(message, conversation) {
|
|
|
12478
12483
|
const imageContext = buildImageContextSuffix(message, conversation);
|
|
12479
12484
|
return `[${message.role}] ${displayName}: ${message.text}${imageContext}${markerSuffix}`;
|
|
12480
12485
|
}
|
|
12486
|
+
function conversationAuthorDisplayName(message) {
|
|
12487
|
+
const author = message.author;
|
|
12488
|
+
const fullName = authorDisplayField(author?.fullName, author?.userId);
|
|
12489
|
+
const userName = authorDisplayField(author?.userName, author?.userId);
|
|
12490
|
+
return fullName ?? userName ?? (message.role === "assistant" ? botConfig.userName : message.role);
|
|
12491
|
+
}
|
|
12492
|
+
function authorDisplayField(value, userId) {
|
|
12493
|
+
if (!value || value === userId || SLACK_USER_ID_DISPLAY_PATTERN.test(value)) {
|
|
12494
|
+
return void 0;
|
|
12495
|
+
}
|
|
12496
|
+
return value;
|
|
12497
|
+
}
|
|
12481
12498
|
function updateConversationStats(conversation) {
|
|
12482
12499
|
const contextText = buildConversationContext(conversation);
|
|
12483
12500
|
conversation.stats.estimatedContextTokens = estimateTextTokens(
|
|
@@ -12547,11 +12564,12 @@ function buildConversationContext(conversation, options = {}) {
|
|
|
12547
12564
|
}
|
|
12548
12565
|
lines.push("<thread-transcript>");
|
|
12549
12566
|
for (const [index, message] of messages.entries()) {
|
|
12550
|
-
const author = escapeXml(message
|
|
12567
|
+
const author = escapeXml(conversationAuthorDisplayName(message));
|
|
12568
|
+
const actorIdAttr = message.author?.userId ? ` actor_id="${escapeXml(message.author.userId)}"` : "";
|
|
12551
12569
|
const ts = new Date(message.createdAtMs).toISOString();
|
|
12552
12570
|
const slackTsAttr = message.meta?.slackTs ? ` slack_ts="${escapeXml(message.meta.slackTs)}"` : "";
|
|
12553
12571
|
lines.push(
|
|
12554
|
-
` <message index="${index + 1}" ts="${ts}" role="${message.role}" author="${author}"${slackTsAttr}>`,
|
|
12572
|
+
` <message index="${index + 1}" ts="${ts}" role="${message.role}" author="${author}"${actorIdAttr}${slackTsAttr}>`,
|
|
12555
12573
|
renderConversationMessageLine(message, conversation),
|
|
12556
12574
|
" </message>"
|
|
12557
12575
|
);
|
|
@@ -14511,7 +14529,7 @@ function validateDispatchOptions(options) {
|
|
|
14511
14529
|
if (options.credentialSubject.type !== "user") {
|
|
14512
14530
|
throw new Error("Dispatch credentialSubject type must be user");
|
|
14513
14531
|
}
|
|
14514
|
-
if (!options.credentialSubject.userId
|
|
14532
|
+
if (!isActorUserId(options.credentialSubject.userId)) {
|
|
14515
14533
|
throw new Error("Dispatch credentialSubject userId is required");
|
|
14516
14534
|
}
|
|
14517
14535
|
if (options.credentialSubject.allowedWhen !== "private-direct-conversation") {
|
|
@@ -15464,15 +15482,13 @@ function getTeamId(message) {
|
|
|
15464
15482
|
}
|
|
15465
15483
|
|
|
15466
15484
|
// src/chat/runtime/processing-reaction.ts
|
|
15467
|
-
var PROCESSING_REACTION_EMOJI = "eyes";
|
|
15468
|
-
var COMPLETED_REACTION_EMOJI = "white_check_mark";
|
|
15469
15485
|
var noProcessingReaction = {
|
|
15470
15486
|
complete: async () => void 0,
|
|
15471
15487
|
keep: () => void 0,
|
|
15472
15488
|
stop: async () => void 0
|
|
15473
15489
|
};
|
|
15474
15490
|
function isProcessingReactionEmoji(value) {
|
|
15475
|
-
return typeof value === "string" && normalizeSlackEmojiName(value) ===
|
|
15491
|
+
return typeof value === "string" && normalizeSlackEmojiName(value) === getChatConfig().slack.processingReactionEmoji;
|
|
15476
15492
|
}
|
|
15477
15493
|
function shouldKeepProcessingReactionForToolInvocation(input) {
|
|
15478
15494
|
return input.toolName === "slackMessageAddReaction" && isProcessingReactionEmoji(input.params.emoji);
|
|
@@ -15498,7 +15514,7 @@ async function startSlackProcessingReactionForMessage(args) {
|
|
|
15498
15514
|
await addReactionToMessage({
|
|
15499
15515
|
channelId: args.channelId,
|
|
15500
15516
|
timestamp: args.timestamp,
|
|
15501
|
-
emoji:
|
|
15517
|
+
emoji: getChatConfig().slack.processingReactionEmoji
|
|
15502
15518
|
});
|
|
15503
15519
|
} catch (error) {
|
|
15504
15520
|
args.logException(
|
|
@@ -15523,7 +15539,7 @@ async function startSlackProcessingReactionForMessage(args) {
|
|
|
15523
15539
|
await removeReactionFromMessage({
|
|
15524
15540
|
channelId: args.channelId,
|
|
15525
15541
|
timestamp: args.timestamp,
|
|
15526
|
-
emoji:
|
|
15542
|
+
emoji: getChatConfig().slack.processingReactionEmoji
|
|
15527
15543
|
});
|
|
15528
15544
|
return true;
|
|
15529
15545
|
} catch (error) {
|
|
@@ -15550,7 +15566,7 @@ async function startSlackProcessingReactionForMessage(args) {
|
|
|
15550
15566
|
await addReactionToMessage({
|
|
15551
15567
|
channelId: args.channelId,
|
|
15552
15568
|
timestamp: args.timestamp,
|
|
15553
|
-
emoji:
|
|
15569
|
+
emoji: getChatConfig().slack.completedReactionEmoji
|
|
15554
15570
|
});
|
|
15555
15571
|
} catch (error) {
|
|
15556
15572
|
args.logException(
|
|
@@ -15997,6 +16013,87 @@ function htmlCallbackResponse(title, message, status) {
|
|
|
15997
16013
|
});
|
|
15998
16014
|
}
|
|
15999
16015
|
|
|
16016
|
+
// src/chat/slack/user.ts
|
|
16017
|
+
var USER_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
16018
|
+
var userCache = /* @__PURE__ */ new Map();
|
|
16019
|
+
function readFromCache(userId) {
|
|
16020
|
+
const hit = userCache.get(userId);
|
|
16021
|
+
if (!hit) return null;
|
|
16022
|
+
if (hit.expiresAt < Date.now()) {
|
|
16023
|
+
userCache.delete(userId);
|
|
16024
|
+
return null;
|
|
16025
|
+
}
|
|
16026
|
+
return hit.value;
|
|
16027
|
+
}
|
|
16028
|
+
function writeToCache(userId, value) {
|
|
16029
|
+
userCache.set(userId, {
|
|
16030
|
+
value,
|
|
16031
|
+
expiresAt: Date.now() + USER_CACHE_TTL_MS
|
|
16032
|
+
});
|
|
16033
|
+
}
|
|
16034
|
+
async function lookupSlackUser(userId) {
|
|
16035
|
+
if (!userId) {
|
|
16036
|
+
return null;
|
|
16037
|
+
}
|
|
16038
|
+
const cached = readFromCache(userId);
|
|
16039
|
+
if (cached) {
|
|
16040
|
+
return cached;
|
|
16041
|
+
}
|
|
16042
|
+
const token = getSlackBotToken();
|
|
16043
|
+
if (!token) {
|
|
16044
|
+
return null;
|
|
16045
|
+
}
|
|
16046
|
+
try {
|
|
16047
|
+
const response = await fetch(
|
|
16048
|
+
`https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`,
|
|
16049
|
+
{
|
|
16050
|
+
headers: {
|
|
16051
|
+
authorization: `Bearer ${token}`
|
|
16052
|
+
}
|
|
16053
|
+
}
|
|
16054
|
+
);
|
|
16055
|
+
if (!response.ok) {
|
|
16056
|
+
logWarn(
|
|
16057
|
+
"slack_user_lookup_failed",
|
|
16058
|
+
{},
|
|
16059
|
+
{
|
|
16060
|
+
"enduser.id": userId,
|
|
16061
|
+
"http.response.status_code": response.status
|
|
16062
|
+
},
|
|
16063
|
+
"Slack user lookup request failed"
|
|
16064
|
+
);
|
|
16065
|
+
return null;
|
|
16066
|
+
}
|
|
16067
|
+
const payload = await response.json();
|
|
16068
|
+
if (!payload.ok || !payload.user) {
|
|
16069
|
+
return null;
|
|
16070
|
+
}
|
|
16071
|
+
const userName = payload.user.name?.trim() || void 0;
|
|
16072
|
+
const fullName = payload.user.profile?.display_name?.trim() || payload.user.profile?.real_name?.trim() || payload.user.real_name?.trim() || void 0;
|
|
16073
|
+
const result = {
|
|
16074
|
+
userName,
|
|
16075
|
+
fullName,
|
|
16076
|
+
email: payload.user.profile?.email?.trim() || void 0
|
|
16077
|
+
};
|
|
16078
|
+
writeToCache(userId, result);
|
|
16079
|
+
return result;
|
|
16080
|
+
} catch (error) {
|
|
16081
|
+
logWarn(
|
|
16082
|
+
"slack_user_lookup_failed",
|
|
16083
|
+
{},
|
|
16084
|
+
{
|
|
16085
|
+
"enduser.id": userId,
|
|
16086
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
16087
|
+
},
|
|
16088
|
+
"Slack user lookup failed with exception"
|
|
16089
|
+
);
|
|
16090
|
+
return null;
|
|
16091
|
+
}
|
|
16092
|
+
}
|
|
16093
|
+
async function lookupSlackActorIdentity(userId) {
|
|
16094
|
+
return slackActorIdentity(userId, await lookupSlackUser(userId));
|
|
16095
|
+
}
|
|
16096
|
+
|
|
16000
16097
|
// src/handlers/mcp-oauth-callback.ts
|
|
16001
16098
|
var CALLBACK_PAGES = {
|
|
16002
16099
|
missing_state: {
|
|
@@ -16197,6 +16294,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
16197
16294
|
}),
|
|
16198
16295
|
ttlMs: THREAD_STATE_TTL_MS4
|
|
16199
16296
|
});
|
|
16297
|
+
const requester = await lookupSlackActorIdentity(authSession.userId);
|
|
16200
16298
|
return {
|
|
16201
16299
|
messageText: lockedUserMessage.text,
|
|
16202
16300
|
messageTs: getTurnUserSlackMessageTs(lockedUserMessage),
|
|
@@ -16204,11 +16302,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
16204
16302
|
credentialContext: {
|
|
16205
16303
|
actor: { type: "user", userId: authSession.userId }
|
|
16206
16304
|
},
|
|
16207
|
-
requester
|
|
16208
|
-
userId: authSession.userId,
|
|
16209
|
-
userName: lockedUserMessage.author?.userName,
|
|
16210
|
-
fullName: lockedUserMessage.author?.fullName
|
|
16211
|
-
},
|
|
16305
|
+
requester,
|
|
16212
16306
|
correlation: {
|
|
16213
16307
|
conversationId: authSession.conversationId,
|
|
16214
16308
|
turnId: lockedSessionId,
|
|
@@ -16691,6 +16785,9 @@ async function resumeOAuthSessionRecordTurn(stored) {
|
|
|
16691
16785
|
}),
|
|
16692
16786
|
ttlMs: THREAD_STATE_TTL_MS5
|
|
16693
16787
|
});
|
|
16788
|
+
const requester = await lookupSlackActorIdentity(
|
|
16789
|
+
lockedUserMessage.author.userId
|
|
16790
|
+
);
|
|
16694
16791
|
return {
|
|
16695
16792
|
messageText: stored.pendingMessage ?? lockedUserMessage.text,
|
|
16696
16793
|
messageTs: getTurnUserSlackMessageTs(lockedUserMessage),
|
|
@@ -16701,11 +16798,7 @@ async function resumeOAuthSessionRecordTurn(stored) {
|
|
|
16701
16798
|
userId: lockedUserMessage.author.userId
|
|
16702
16799
|
}
|
|
16703
16800
|
},
|
|
16704
|
-
requester
|
|
16705
|
-
userId: lockedUserMessage.author.userId,
|
|
16706
|
-
userName: lockedUserMessage.author.userName,
|
|
16707
|
-
fullName: lockedUserMessage.author.fullName
|
|
16708
|
-
},
|
|
16801
|
+
requester,
|
|
16709
16802
|
correlation: {
|
|
16710
16803
|
conversationId: stored.resumeConversationId,
|
|
16711
16804
|
turnId: lockedSessionId,
|
|
@@ -16801,6 +16894,7 @@ async function resumePendingOAuthMessage(stored) {
|
|
|
16801
16894
|
const conversationContext = buildConversationContext(conversation, {
|
|
16802
16895
|
excludeMessageId: latestUserMessage?.id
|
|
16803
16896
|
});
|
|
16897
|
+
const requester = await lookupSlackActorIdentity(stored.userId);
|
|
16804
16898
|
await resumeAuthorizedRequest({
|
|
16805
16899
|
messageText: stored.pendingMessage,
|
|
16806
16900
|
channelId: stored.channelId,
|
|
@@ -16811,7 +16905,7 @@ async function resumePendingOAuthMessage(stored) {
|
|
|
16811
16905
|
credentialContext: {
|
|
16812
16906
|
actor: { type: "user", userId: stored.userId }
|
|
16813
16907
|
},
|
|
16814
|
-
requester
|
|
16908
|
+
requester,
|
|
16815
16909
|
conversationContext,
|
|
16816
16910
|
piMessages: conversation.piMessages,
|
|
16817
16911
|
configuration: stored.configuration
|
|
@@ -17690,6 +17784,9 @@ async function resumeTimedOutTurn(payload, options = {}) {
|
|
|
17690
17784
|
excludeMessageId: userMessage2.id
|
|
17691
17785
|
});
|
|
17692
17786
|
const sandbox = getPersistedSandboxState(currentState);
|
|
17787
|
+
const requester = await lookupSlackActorIdentity(
|
|
17788
|
+
userMessage2.author.userId
|
|
17789
|
+
);
|
|
17693
17790
|
return {
|
|
17694
17791
|
messageText: userMessage2.text,
|
|
17695
17792
|
messageTs: getTurnUserSlackMessageTs(userMessage2),
|
|
@@ -17700,11 +17797,7 @@ async function resumeTimedOutTurn(payload, options = {}) {
|
|
|
17700
17797
|
userId: userMessage2.author.userId
|
|
17701
17798
|
}
|
|
17702
17799
|
},
|
|
17703
|
-
requester
|
|
17704
|
-
userId: userMessage2.author.userId,
|
|
17705
|
-
userName: userMessage2.author.userName,
|
|
17706
|
-
fullName: userMessage2.author.fullName
|
|
17707
|
-
},
|
|
17800
|
+
requester,
|
|
17708
17801
|
correlation: {
|
|
17709
17802
|
conversationId: payload.conversationId,
|
|
17710
17803
|
turnId: payload.sessionId,
|
|
@@ -18194,6 +18287,60 @@ function combineTurnText(queuedMessages, latestText) {
|
|
|
18194
18287
|
};
|
|
18195
18288
|
}
|
|
18196
18289
|
|
|
18290
|
+
// src/chat/services/message-actor-identity.ts
|
|
18291
|
+
var messageActors = /* @__PURE__ */ new WeakMap();
|
|
18292
|
+
function canonicalUserId(author, identity) {
|
|
18293
|
+
const authorUserId = parseActorUserId(author.userId);
|
|
18294
|
+
const identityUserId = parseActorUserId(identity.userId);
|
|
18295
|
+
if (authorUserId && identityUserId && authorUserId !== identityUserId) {
|
|
18296
|
+
throw new Error("Message actor identity user id mismatch");
|
|
18297
|
+
}
|
|
18298
|
+
const userId = authorUserId ?? identityUserId;
|
|
18299
|
+
if (!userId) {
|
|
18300
|
+
throw new Error("Message actor identity requires a user id");
|
|
18301
|
+
}
|
|
18302
|
+
return userId;
|
|
18303
|
+
}
|
|
18304
|
+
function actorIdentityFromAuthor(author) {
|
|
18305
|
+
const userId = parseActorUserId(author.userId);
|
|
18306
|
+
return userId ? { userId } : void 0;
|
|
18307
|
+
}
|
|
18308
|
+
function applyIdentityToAuthor(author, identity) {
|
|
18309
|
+
if (!isActorUserId(identity.userId)) {
|
|
18310
|
+
throw new Error("Message actor identity requires a user id");
|
|
18311
|
+
}
|
|
18312
|
+
author.userId = identity.userId;
|
|
18313
|
+
author.userName = identity.userName ?? "";
|
|
18314
|
+
author.fullName = identity.fullName ?? "";
|
|
18315
|
+
}
|
|
18316
|
+
function bindMessageActorIdentity(message, identity) {
|
|
18317
|
+
const userId = canonicalUserId(message.author, identity);
|
|
18318
|
+
const actorIdentity = buildActorIdentity(identity, userId);
|
|
18319
|
+
if (!actorIdentity?.userId) {
|
|
18320
|
+
throw new Error("Message actor identity requires a user id");
|
|
18321
|
+
}
|
|
18322
|
+
messageActors.set(message, actorIdentity);
|
|
18323
|
+
applyIdentityToAuthor(message.author, actorIdentity);
|
|
18324
|
+
return actorIdentity;
|
|
18325
|
+
}
|
|
18326
|
+
function getMessageActorIdentity(message) {
|
|
18327
|
+
return messageActors.get(message) ?? actorIdentityFromAuthor(message.author);
|
|
18328
|
+
}
|
|
18329
|
+
async function ensureSlackMessageActorIdentity(message, lookupSlackUser2) {
|
|
18330
|
+
const existing = messageActors.get(message);
|
|
18331
|
+
if (existing) {
|
|
18332
|
+
return existing;
|
|
18333
|
+
}
|
|
18334
|
+
const userId = parseActorUserId(message.author.userId);
|
|
18335
|
+
if (!userId) {
|
|
18336
|
+
throw new Error("Slack message actor identity requires a user id");
|
|
18337
|
+
}
|
|
18338
|
+
return bindMessageActorIdentity(
|
|
18339
|
+
message,
|
|
18340
|
+
slackActorIdentity(userId, await lookupSlackUser2(userId))
|
|
18341
|
+
);
|
|
18342
|
+
}
|
|
18343
|
+
|
|
18197
18344
|
// src/chat/runtime/slack-runtime.ts
|
|
18198
18345
|
var THREAD_OPTOUT_ACK = "Understood. I'll stay out of this thread unless someone @mentions me again.";
|
|
18199
18346
|
async function maybeHandleThreadOptOutDecision(args) {
|
|
@@ -18253,6 +18400,9 @@ function buildLogContext(deps, args) {
|
|
|
18253
18400
|
modelId: deps.modelId
|
|
18254
18401
|
};
|
|
18255
18402
|
}
|
|
18403
|
+
function requesterUserName(message) {
|
|
18404
|
+
return getMessageActorIdentity(message)?.userName;
|
|
18405
|
+
}
|
|
18256
18406
|
function createSlackTurnRuntime(deps) {
|
|
18257
18407
|
const logContext = (args) => buildLogContext(deps, args);
|
|
18258
18408
|
const createToolInvocationHook = (processingReaction, hooks) => {
|
|
@@ -18326,7 +18476,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18326
18476
|
logContext({
|
|
18327
18477
|
threadId: args.context.threadId,
|
|
18328
18478
|
requesterId: args.context.requesterId,
|
|
18329
|
-
requesterUserName: args.message
|
|
18479
|
+
requesterUserName: requesterUserName(args.message),
|
|
18330
18480
|
channelId: args.context.channelId,
|
|
18331
18481
|
runId: args.context.runId
|
|
18332
18482
|
}),
|
|
@@ -18368,7 +18518,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18368
18518
|
threadId,
|
|
18369
18519
|
channelId,
|
|
18370
18520
|
requesterId: message.author.userId,
|
|
18371
|
-
requesterUserName: message
|
|
18521
|
+
requesterUserName: requesterUserName(message),
|
|
18372
18522
|
runId
|
|
18373
18523
|
});
|
|
18374
18524
|
processingReaction = await processingReactions.start(context, message);
|
|
@@ -18428,7 +18578,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18428
18578
|
const errorContext = logContext({
|
|
18429
18579
|
threadId: deps.getThreadId(thread, message),
|
|
18430
18580
|
requesterId: message.author.userId,
|
|
18431
|
-
requesterUserName: message
|
|
18581
|
+
requesterUserName: requesterUserName(message),
|
|
18432
18582
|
channelId: deps.getChannelId(thread, message),
|
|
18433
18583
|
runId: deps.getRunId(thread, message)
|
|
18434
18584
|
});
|
|
@@ -18484,7 +18634,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18484
18634
|
const turnContext = logContext({
|
|
18485
18635
|
threadId,
|
|
18486
18636
|
requesterId: message.author.userId,
|
|
18487
|
-
requesterUserName: message
|
|
18637
|
+
requesterUserName: requesterUserName(message),
|
|
18488
18638
|
channelId,
|
|
18489
18639
|
runId
|
|
18490
18640
|
});
|
|
@@ -18634,7 +18784,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18634
18784
|
const errorContext = logContext({
|
|
18635
18785
|
threadId: deps.getThreadId(thread, message),
|
|
18636
18786
|
requesterId: message.author.userId,
|
|
18637
|
-
requesterUserName: message
|
|
18787
|
+
requesterUserName: requesterUserName(message),
|
|
18638
18788
|
channelId: deps.getChannelId(thread, message),
|
|
18639
18789
|
runId: deps.getRunId(thread, message)
|
|
18640
18790
|
});
|
|
@@ -18992,84 +19142,6 @@ function createContextCompactor(deps) {
|
|
|
18992
19142
|
};
|
|
18993
19143
|
}
|
|
18994
19144
|
|
|
18995
|
-
// src/chat/slack/user.ts
|
|
18996
|
-
var USER_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
18997
|
-
var userCache = /* @__PURE__ */ new Map();
|
|
18998
|
-
function readFromCache(userId) {
|
|
18999
|
-
const hit = userCache.get(userId);
|
|
19000
|
-
if (!hit) return null;
|
|
19001
|
-
if (hit.expiresAt < Date.now()) {
|
|
19002
|
-
userCache.delete(userId);
|
|
19003
|
-
return null;
|
|
19004
|
-
}
|
|
19005
|
-
return hit.value;
|
|
19006
|
-
}
|
|
19007
|
-
function writeToCache(userId, value) {
|
|
19008
|
-
userCache.set(userId, {
|
|
19009
|
-
value,
|
|
19010
|
-
expiresAt: Date.now() + USER_CACHE_TTL_MS
|
|
19011
|
-
});
|
|
19012
|
-
}
|
|
19013
|
-
async function lookupSlackUser(userId) {
|
|
19014
|
-
if (!userId) {
|
|
19015
|
-
return null;
|
|
19016
|
-
}
|
|
19017
|
-
const cached = readFromCache(userId);
|
|
19018
|
-
if (cached) {
|
|
19019
|
-
return cached;
|
|
19020
|
-
}
|
|
19021
|
-
const token = getSlackBotToken();
|
|
19022
|
-
if (!token) {
|
|
19023
|
-
return null;
|
|
19024
|
-
}
|
|
19025
|
-
try {
|
|
19026
|
-
const response = await fetch(
|
|
19027
|
-
`https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`,
|
|
19028
|
-
{
|
|
19029
|
-
headers: {
|
|
19030
|
-
authorization: `Bearer ${token}`
|
|
19031
|
-
}
|
|
19032
|
-
}
|
|
19033
|
-
);
|
|
19034
|
-
if (!response.ok) {
|
|
19035
|
-
logWarn(
|
|
19036
|
-
"slack_user_lookup_failed",
|
|
19037
|
-
{},
|
|
19038
|
-
{
|
|
19039
|
-
"enduser.id": userId,
|
|
19040
|
-
"http.response.status_code": response.status
|
|
19041
|
-
},
|
|
19042
|
-
"Slack user lookup request failed"
|
|
19043
|
-
);
|
|
19044
|
-
return null;
|
|
19045
|
-
}
|
|
19046
|
-
const payload = await response.json();
|
|
19047
|
-
if (!payload.ok || !payload.user) {
|
|
19048
|
-
return null;
|
|
19049
|
-
}
|
|
19050
|
-
const userName = payload.user.name?.trim() || void 0;
|
|
19051
|
-
const fullName = payload.user.profile?.display_name?.trim() || payload.user.profile?.real_name?.trim() || payload.user.real_name?.trim() || void 0;
|
|
19052
|
-
const result = {
|
|
19053
|
-
userName,
|
|
19054
|
-
fullName,
|
|
19055
|
-
email: payload.user.profile?.email?.trim() || void 0
|
|
19056
|
-
};
|
|
19057
|
-
writeToCache(userId, result);
|
|
19058
|
-
return result;
|
|
19059
|
-
} catch (error) {
|
|
19060
|
-
logWarn(
|
|
19061
|
-
"slack_user_lookup_failed",
|
|
19062
|
-
{},
|
|
19063
|
-
{
|
|
19064
|
-
"enduser.id": userId,
|
|
19065
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
19066
|
-
},
|
|
19067
|
-
"Slack user lookup failed with exception"
|
|
19068
|
-
);
|
|
19069
|
-
return null;
|
|
19070
|
-
}
|
|
19071
|
-
}
|
|
19072
|
-
|
|
19073
19145
|
// src/chat/services/subscribed-reply-policy.ts
|
|
19074
19146
|
function createSubscribedReplyPolicy(deps) {
|
|
19075
19147
|
return async (args) => {
|
|
@@ -19793,14 +19865,14 @@ function collectCanvasUrls(artifacts) {
|
|
|
19793
19865
|
].filter((url) => typeof url === "string" && url !== "")
|
|
19794
19866
|
);
|
|
19795
19867
|
}
|
|
19796
|
-
function turnRequester(
|
|
19868
|
+
function turnRequester(identity) {
|
|
19797
19869
|
const requester = {
|
|
19798
|
-
...
|
|
19799
|
-
...
|
|
19800
|
-
...
|
|
19801
|
-
...
|
|
19870
|
+
...identity.email ? { email: identity.email } : {},
|
|
19871
|
+
...identity.fullName ? { fullName: identity.fullName } : {},
|
|
19872
|
+
...identity.userId ? { slackUserId: identity.userId } : {},
|
|
19873
|
+
...identity.userName ? { slackUserName: identity.userName } : {}
|
|
19802
19874
|
};
|
|
19803
|
-
return
|
|
19875
|
+
return requester;
|
|
19804
19876
|
}
|
|
19805
19877
|
async function resolveChannelName(thread) {
|
|
19806
19878
|
const existingName = thread.channel.name?.trim();
|
|
@@ -19909,6 +19981,19 @@ function createReplyToThread(deps) {
|
|
|
19909
19981
|
options.queuedMessages ?? [],
|
|
19910
19982
|
currentText
|
|
19911
19983
|
).userText;
|
|
19984
|
+
await Promise.all(
|
|
19985
|
+
(options.queuedMessages ?? []).map(
|
|
19986
|
+
(queued) => ensureSlackMessageActorIdentity(
|
|
19987
|
+
queued.message,
|
|
19988
|
+
deps.services.lookupSlackUser
|
|
19989
|
+
)
|
|
19990
|
+
)
|
|
19991
|
+
);
|
|
19992
|
+
const requesterIdentity = await ensureSlackMessageActorIdentity(
|
|
19993
|
+
message,
|
|
19994
|
+
deps.services.lookupSlackUser
|
|
19995
|
+
);
|
|
19996
|
+
const requester = turnRequester(requesterIdentity);
|
|
19912
19997
|
const preparedState = options.preparedState ?? await deps.prepareTurnState({
|
|
19913
19998
|
thread,
|
|
19914
19999
|
message,
|
|
@@ -19926,15 +20011,6 @@ function createReplyToThread(deps) {
|
|
|
19926
20011
|
});
|
|
19927
20012
|
const slackMessageTs = getSlackMessageTs(message);
|
|
19928
20013
|
const turnId = buildDeterministicTurnId(message.id);
|
|
19929
|
-
const fallbackIdentity = await deps.services.lookupSlackUser(
|
|
19930
|
-
message.author.userId
|
|
19931
|
-
);
|
|
19932
|
-
const requester = turnRequester({
|
|
19933
|
-
email: fallbackIdentity?.email,
|
|
19934
|
-
fullName: message.author.fullName ?? fallbackIdentity?.fullName,
|
|
19935
|
-
userId: message.author.userId,
|
|
19936
|
-
userName: message.author.userName ?? fallbackIdentity?.userName
|
|
19937
|
-
});
|
|
19938
20014
|
const turnTraceContext = {
|
|
19939
20015
|
conversationId,
|
|
19940
20016
|
slackThreadId: threadId,
|
|
@@ -20122,16 +20198,15 @@ function createReplyToThread(deps) {
|
|
|
20122
20198
|
conversation: preparedState.conversation
|
|
20123
20199
|
});
|
|
20124
20200
|
await options.onTurnStatePersisted?.();
|
|
20125
|
-
const resolvedUserName = message.author.userName ?? fallbackIdentity?.userName;
|
|
20126
20201
|
if (message.author.userId) {
|
|
20127
20202
|
setSentryUser({
|
|
20128
20203
|
id: message.author.userId,
|
|
20129
|
-
...
|
|
20130
|
-
...
|
|
20204
|
+
...requesterIdentity.userName ? { username: requesterIdentity.userName } : {},
|
|
20205
|
+
...requesterIdentity.email ? { email: requesterIdentity.email } : {}
|
|
20131
20206
|
});
|
|
20132
20207
|
}
|
|
20133
|
-
if (
|
|
20134
|
-
setTags({ slackUserName:
|
|
20208
|
+
if (requesterIdentity.userName) {
|
|
20209
|
+
setTags({ slackUserName: requesterIdentity.userName });
|
|
20135
20210
|
}
|
|
20136
20211
|
const turnAttachments = collectTurnAttachments(
|
|
20137
20212
|
message,
|
|
@@ -20261,12 +20336,7 @@ function createReplyToThread(deps) {
|
|
|
20261
20336
|
credentialContext: {
|
|
20262
20337
|
actor: { type: "user", userId: message.author.userId }
|
|
20263
20338
|
},
|
|
20264
|
-
requester:
|
|
20265
|
-
userId: message.author.userId,
|
|
20266
|
-
userName: message.author.userName ?? fallbackIdentity?.userName,
|
|
20267
|
-
fullName: message.author.fullName ?? fallbackIdentity?.fullName,
|
|
20268
|
-
email: fallbackIdentity?.email
|
|
20269
|
-
},
|
|
20339
|
+
requester: requesterIdentity,
|
|
20270
20340
|
conversationContext: preparedState.conversationContext,
|
|
20271
20341
|
artifactState: preparedState.artifacts,
|
|
20272
20342
|
piMessages,
|
|
@@ -20673,6 +20743,7 @@ function resolveMessageText(args) {
|
|
|
20673
20743
|
return text || NON_TEXT_MESSAGE_TEXT;
|
|
20674
20744
|
}
|
|
20675
20745
|
function toConversationMessage(args) {
|
|
20746
|
+
const actor = getMessageActorIdentity(args.entry);
|
|
20676
20747
|
const messageHasPotentialImageAttachment = hasPotentialImageAttachment(
|
|
20677
20748
|
args.entry.attachments
|
|
20678
20749
|
);
|
|
@@ -20683,9 +20754,9 @@ function toConversationMessage(args) {
|
|
|
20683
20754
|
text: resolveMessageText(args),
|
|
20684
20755
|
createdAtMs: args.entry.metadata.dateSent.getTime(),
|
|
20685
20756
|
author: {
|
|
20686
|
-
userId:
|
|
20687
|
-
userName:
|
|
20688
|
-
fullName:
|
|
20757
|
+
...actor?.userId ? { userId: actor.userId } : {},
|
|
20758
|
+
...actor?.userName ? { userName: actor.userName } : {},
|
|
20759
|
+
...actor?.fullName ? { fullName: actor.fullName } : {},
|
|
20689
20760
|
isBot: typeof args.entry.author.isBot === "boolean" ? args.entry.author.isBot : void 0
|
|
20690
20761
|
},
|
|
20691
20762
|
meta: {
|
|
@@ -21102,6 +21173,13 @@ async function runWithSlackInstallation(args) {
|
|
|
21102
21173
|
}
|
|
21103
21174
|
|
|
21104
21175
|
// src/chat/task-execution/slack-work.ts
|
|
21176
|
+
function requireSlackAuthorId(message) {
|
|
21177
|
+
const authorId = parseActorUserId(message.author.userId);
|
|
21178
|
+
if (!authorId) {
|
|
21179
|
+
throw new Error("Slack message requires an actor user id");
|
|
21180
|
+
}
|
|
21181
|
+
return authorId;
|
|
21182
|
+
}
|
|
21105
21183
|
function getConnectedState3(stateAdapter) {
|
|
21106
21184
|
return stateAdapter ?? getStateAdapter();
|
|
21107
21185
|
}
|
|
@@ -21126,6 +21204,23 @@ function restoreMessage(args) {
|
|
|
21126
21204
|
rehydrateAttachmentFetchers(message);
|
|
21127
21205
|
return message;
|
|
21128
21206
|
}
|
|
21207
|
+
async function bindSlackActorIdentities(args) {
|
|
21208
|
+
const byAuthorId = /* @__PURE__ */ new Map();
|
|
21209
|
+
for (const message of args.messages) {
|
|
21210
|
+
const authorId = requireSlackAuthorId(message);
|
|
21211
|
+
byAuthorId.set(authorId, [...byAuthorId.get(authorId) ?? [], message]);
|
|
21212
|
+
}
|
|
21213
|
+
await Promise.all(
|
|
21214
|
+
[...byAuthorId].map(async ([authorId, messages]) => {
|
|
21215
|
+
const profile = await args.lookupSlackUser(authorId);
|
|
21216
|
+
await Promise.all(
|
|
21217
|
+
messages.map(
|
|
21218
|
+
(message) => ensureSlackMessageActorIdentity(message, async () => profile)
|
|
21219
|
+
)
|
|
21220
|
+
);
|
|
21221
|
+
})
|
|
21222
|
+
);
|
|
21223
|
+
}
|
|
21129
21224
|
function restoreThread(args) {
|
|
21130
21225
|
const threadId = normalizeIncomingSlackThreadId(
|
|
21131
21226
|
args.threadJson.id,
|
|
@@ -21205,6 +21300,7 @@ function getPendingRecords(work) {
|
|
|
21205
21300
|
function createSlackConversationWorker(options) {
|
|
21206
21301
|
return async (context) => {
|
|
21207
21302
|
const adapter = options.getSlackAdapter();
|
|
21303
|
+
const actorLookup = options.lookupSlackUser ?? lookupSlackUser;
|
|
21208
21304
|
const state = getConnectedState3(options.state);
|
|
21209
21305
|
await state.connect();
|
|
21210
21306
|
const resumeContinuation = options.resumeAwaitingContinuation ?? resumeAwaitingContinuation;
|
|
@@ -21242,6 +21338,10 @@ function createSlackConversationWorker(options) {
|
|
|
21242
21338
|
const messages = records.map(
|
|
21243
21339
|
(record) => restoreMessage({ adapter, record })
|
|
21244
21340
|
);
|
|
21341
|
+
await bindSlackActorIdentities({
|
|
21342
|
+
lookupSlackUser: actorLookup,
|
|
21343
|
+
messages
|
|
21344
|
+
});
|
|
21245
21345
|
const latestMessage = messages[messages.length - 1];
|
|
21246
21346
|
if (!latestMessage) {
|
|
21247
21347
|
return;
|
|
@@ -21328,6 +21428,7 @@ function createSlackConversationWorker(options) {
|
|
|
21328
21428
|
};
|
|
21329
21429
|
}
|
|
21330
21430
|
function buildSlackInboundMessage(args) {
|
|
21431
|
+
const authorId = requireSlackAuthorId(args.message);
|
|
21331
21432
|
return {
|
|
21332
21433
|
conversationId: args.conversationId,
|
|
21333
21434
|
inboundMessageId: [
|
|
@@ -21341,7 +21442,7 @@ function buildSlackInboundMessage(args) {
|
|
|
21341
21442
|
receivedAtMs: args.receivedAtMs,
|
|
21342
21443
|
input: {
|
|
21343
21444
|
text: args.message.text || " ",
|
|
21344
|
-
authorId
|
|
21445
|
+
authorId,
|
|
21345
21446
|
attachments: args.message.attachments,
|
|
21346
21447
|
metadata: {
|
|
21347
21448
|
platform: "slack",
|
|
@@ -21460,7 +21561,8 @@ function extractMessageChangedMention(body, botUserId, adapter) {
|
|
|
21460
21561
|
const channelId = event.channel;
|
|
21461
21562
|
const messageTs = event.message.ts;
|
|
21462
21563
|
const threadTs = event.message.thread_ts ?? messageTs;
|
|
21463
|
-
const userId = event.message.user
|
|
21564
|
+
const userId = parseActorUserId(event.message.user);
|
|
21565
|
+
if (!userId) return null;
|
|
21464
21566
|
const threadId = `slack:${channelId}:${threadTs}`;
|
|
21465
21567
|
const teamId = typeof body.team_id === "string" ? body.team_id : void 0;
|
|
21466
21568
|
const userTeam = typeof event.message.user_team === "string" ? event.message.user_team : void 0;
|
|
@@ -21485,8 +21587,9 @@ function extractMessageChangedMention(body, botUserId, adapter) {
|
|
|
21485
21587
|
raw,
|
|
21486
21588
|
author: {
|
|
21487
21589
|
userId,
|
|
21488
|
-
|
|
21489
|
-
|
|
21590
|
+
// Raw message_changed payloads do not include profile fields.
|
|
21591
|
+
userName: "",
|
|
21592
|
+
fullName: "",
|
|
21490
21593
|
isBot: false,
|
|
21491
21594
|
isMe: false
|
|
21492
21595
|
}
|
|
@@ -21516,10 +21619,17 @@ function isExternalSlackUser(raw) {
|
|
|
21516
21619
|
async function postEphemeral(event, text) {
|
|
21517
21620
|
await event.channel.postEphemeral(event.user, text, { fallbackToDM: false });
|
|
21518
21621
|
}
|
|
21622
|
+
function requireRequesterId(event) {
|
|
21623
|
+
const userId = parseActorUserId(event.user.userId);
|
|
21624
|
+
if (!userId) {
|
|
21625
|
+
throw new Error("Slack slash command requires a requester user id");
|
|
21626
|
+
}
|
|
21627
|
+
return userId;
|
|
21628
|
+
}
|
|
21519
21629
|
function getCommandName() {
|
|
21520
21630
|
return getChatConfig().slack.slashCommand;
|
|
21521
21631
|
}
|
|
21522
|
-
async function handleLink(event, provider) {
|
|
21632
|
+
async function handleLink(event, requesterId, provider) {
|
|
21523
21633
|
if (!isPluginProvider(provider)) {
|
|
21524
21634
|
await postEphemeral(event, `Unknown provider: \`${provider}\``);
|
|
21525
21635
|
return;
|
|
@@ -21533,7 +21643,7 @@ async function handleLink(event, provider) {
|
|
|
21533
21643
|
}
|
|
21534
21644
|
const raw = event.raw;
|
|
21535
21645
|
const result = await startOAuthFlow(provider, {
|
|
21536
|
-
requesterId
|
|
21646
|
+
requesterId,
|
|
21537
21647
|
channelId: raw.channel_id
|
|
21538
21648
|
});
|
|
21539
21649
|
if (!result.ok) {
|
|
@@ -21552,7 +21662,7 @@ async function handleLink(event, provider) {
|
|
|
21552
21662
|
);
|
|
21553
21663
|
}
|
|
21554
21664
|
}
|
|
21555
|
-
async function handleUnlink(event, provider) {
|
|
21665
|
+
async function handleUnlink(event, requesterId, provider) {
|
|
21556
21666
|
if (!isPluginProvider(provider)) {
|
|
21557
21667
|
await postEphemeral(event, `Unknown provider: \`${provider}\``);
|
|
21558
21668
|
return;
|
|
@@ -21565,10 +21675,10 @@ async function handleUnlink(event, provider) {
|
|
|
21565
21675
|
return;
|
|
21566
21676
|
}
|
|
21567
21677
|
const tokenStore = createUserTokenStore();
|
|
21568
|
-
await tokenStore.delete(
|
|
21678
|
+
await tokenStore.delete(requesterId, provider);
|
|
21569
21679
|
logInfo(
|
|
21570
21680
|
"slash_command_unlink",
|
|
21571
|
-
{ slackUserId:
|
|
21681
|
+
{ slackUserId: requesterId },
|
|
21572
21682
|
{ "app.credential.provider": provider },
|
|
21573
21683
|
`Unlinked ${formatProviderLabel(provider)} account via ${getCommandName()} slash command`
|
|
21574
21684
|
);
|
|
@@ -21594,10 +21704,11 @@ async function handleSlashCommand(event) {
|
|
|
21594
21704
|
return;
|
|
21595
21705
|
}
|
|
21596
21706
|
const normalized = provider.toLowerCase();
|
|
21707
|
+
const requesterId = requireRequesterId(event);
|
|
21597
21708
|
if (subcommand === "link") {
|
|
21598
|
-
await handleLink(event, normalized);
|
|
21709
|
+
await handleLink(event, requesterId, normalized);
|
|
21599
21710
|
} else {
|
|
21600
|
-
await handleUnlink(event, normalized);
|
|
21711
|
+
await handleUnlink(event, requesterId, normalized);
|
|
21601
21712
|
}
|
|
21602
21713
|
}
|
|
21603
21714
|
|
|
@@ -21837,15 +21948,12 @@ async function handleSlackEvent(args) {
|
|
|
21837
21948
|
})
|
|
21838
21949
|
);
|
|
21839
21950
|
}
|
|
21840
|
-
function
|
|
21841
|
-
const userId =
|
|
21842
|
-
|
|
21843
|
-
|
|
21844
|
-
|
|
21845
|
-
|
|
21846
|
-
isBot: false,
|
|
21847
|
-
isMe: false
|
|
21848
|
-
};
|
|
21951
|
+
function requireSlackPayloadUserId(value, source) {
|
|
21952
|
+
const userId = parseActorUserId(value);
|
|
21953
|
+
if (!userId) {
|
|
21954
|
+
throw new Error(`${source} is missing a Slack user id`);
|
|
21955
|
+
}
|
|
21956
|
+
return userId;
|
|
21849
21957
|
}
|
|
21850
21958
|
async function handleSlashCommandForm(args) {
|
|
21851
21959
|
const raw = Object.fromEntries(args.params);
|
|
@@ -21855,7 +21963,21 @@ async function handleSlashCommandForm(args) {
|
|
|
21855
21963
|
adapter: args.adapter,
|
|
21856
21964
|
stateAdapter: args.state
|
|
21857
21965
|
});
|
|
21858
|
-
const userId =
|
|
21966
|
+
const userId = requireSlackPayloadUserId(
|
|
21967
|
+
args.params.get("user_id"),
|
|
21968
|
+
"Slack slash command payload"
|
|
21969
|
+
);
|
|
21970
|
+
const userIdentity = buildActorIdentity(
|
|
21971
|
+
{
|
|
21972
|
+
userId,
|
|
21973
|
+
userName: args.params.get("user_name") ?? void 0,
|
|
21974
|
+
fullName: args.params.get("user_name") ?? void 0
|
|
21975
|
+
},
|
|
21976
|
+
userId
|
|
21977
|
+
);
|
|
21978
|
+
if (!userIdentity?.userId) {
|
|
21979
|
+
throw new Error("Slack slash command payload actor identity is invalid");
|
|
21980
|
+
}
|
|
21859
21981
|
await withSpan(
|
|
21860
21982
|
"chat.slash_command",
|
|
21861
21983
|
"chat.slash_command",
|
|
@@ -21870,8 +21992,8 @@ async function handleSlashCommandForm(args) {
|
|
|
21870
21992
|
raw,
|
|
21871
21993
|
user: {
|
|
21872
21994
|
userId,
|
|
21873
|
-
userName:
|
|
21874
|
-
fullName:
|
|
21995
|
+
userName: userIdentity.userName ?? "",
|
|
21996
|
+
fullName: userIdentity.fullName ?? "",
|
|
21875
21997
|
isBot: false,
|
|
21876
21998
|
isMe: false
|
|
21877
21999
|
},
|
|
@@ -21888,10 +22010,13 @@ async function handleInteractivePayload(args) {
|
|
|
21888
22010
|
(candidate) => candidate.action_id === "app_home_disconnect"
|
|
21889
22011
|
);
|
|
21890
22012
|
const provider = action?.selected_option?.value ?? action?.value;
|
|
21891
|
-
|
|
21892
|
-
if (!provider || !userId) {
|
|
22013
|
+
if (!provider) {
|
|
21893
22014
|
return;
|
|
21894
22015
|
}
|
|
22016
|
+
const userId = requireSlackPayloadUserId(
|
|
22017
|
+
args.payload.user?.id,
|
|
22018
|
+
"Slack app home disconnect payload"
|
|
22019
|
+
);
|
|
21895
22020
|
await withSpan(
|
|
21896
22021
|
"chat.app_home_disconnect",
|
|
21897
22022
|
"chat.app_home_disconnect",
|
|
@@ -21986,7 +22111,7 @@ async function handleSlackForm(args) {
|
|
|
21986
22111
|
})
|
|
21987
22112
|
).catch((error) => {
|
|
21988
22113
|
logException(error, "slack_interactive_payload_failed", {
|
|
21989
|
-
slackUserId:
|
|
22114
|
+
slackUserId: payload.user?.id?.trim() || void 0
|
|
21990
22115
|
});
|
|
21991
22116
|
})
|
|
21992
22117
|
);
|
|
@@ -22720,9 +22845,13 @@ async function createApp(options) {
|
|
|
22720
22845
|
const previousPluginCatalogConfig = setPluginCatalogConfig(pluginConfig);
|
|
22721
22846
|
const previousAgentPlugins = setAgentPlugins(agentPlugins);
|
|
22722
22847
|
const previousConfigDefaults = getConfigDefaults();
|
|
22848
|
+
const previousSlackReactionConfig = getSlackReactionConfig();
|
|
22723
22849
|
let agentPluginRoutes = [];
|
|
22724
22850
|
try {
|
|
22725
22851
|
setConfigDefaults(options?.configDefaults);
|
|
22852
|
+
if (options?.slack) {
|
|
22853
|
+
setSlackReactionConfig(options.slack);
|
|
22854
|
+
}
|
|
22726
22855
|
if (shouldValidatePluginCatalog) {
|
|
22727
22856
|
getPluginCatalogSignature();
|
|
22728
22857
|
validatePluginRegistrations(configuredPlugins?.registrations ?? []);
|
|
@@ -22732,6 +22861,7 @@ async function createApp(options) {
|
|
|
22732
22861
|
setPluginCatalogConfig(previousPluginCatalogConfig);
|
|
22733
22862
|
setAgentPlugins(previousAgentPlugins);
|
|
22734
22863
|
setConfigDefaults(previousConfigDefaults);
|
|
22864
|
+
setSlackReactionConfig(previousSlackReactionConfig);
|
|
22735
22865
|
throw error;
|
|
22736
22866
|
}
|
|
22737
22867
|
const waitUntil = options?.waitUntil ?? await defaultWaitUntil();
|