@sentry/junior 0.67.0 → 0.67.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/app.js +314 -191
- package/dist/chat/config.d.ts +2 -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-HFMZE67J.js → chunk-5UIDU7XR.js} +8 -6
- package/dist/{chunk-NWU2Z6SM.js → chunk-MT23VNOH.js} +38 -1
- package/dist/{chunk-6QWWMZCK.js → chunk-OIIXZOOC.js} +101 -6
- package/dist/{chunk-YL5G5YC4.js → chunk-V47RLIO2.js} +1 -1
- package/dist/{chunk-KWEE2436.js → chunk-YGGH2742.js} +2 -2
- 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-5UIDU7XR.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-YGGH2742.js";
|
|
66
66
|
import {
|
|
67
67
|
ACTIVE_LOCK_TTL_MS,
|
|
68
68
|
FUNCTION_TIMEOUT_BUFFER_SECONDS,
|
|
@@ -85,6 +85,7 @@ import {
|
|
|
85
85
|
getSlackClientSecret,
|
|
86
86
|
getSlackSigningSecret,
|
|
87
87
|
getStateAdapter,
|
|
88
|
+
normalizeSlackEmojiName,
|
|
88
89
|
parseSlackThreadId,
|
|
89
90
|
resolveConversationPrivacy,
|
|
90
91
|
resolveGatewayModel,
|
|
@@ -97,9 +98,10 @@ import {
|
|
|
97
98
|
toGenAiPayloadMetadata,
|
|
98
99
|
toGenAiPayloadTraceAttributes,
|
|
99
100
|
toGenAiTextMetadata
|
|
100
|
-
} from "./chunk-
|
|
101
|
+
} from "./chunk-MT23VNOH.js";
|
|
101
102
|
import {
|
|
102
103
|
CredentialUnavailableError,
|
|
104
|
+
buildActorIdentity,
|
|
103
105
|
buildOAuthTokenRequest,
|
|
104
106
|
buildTurnFailureResponse,
|
|
105
107
|
createChatSdkLogger,
|
|
@@ -116,6 +118,7 @@ import {
|
|
|
116
118
|
getPluginOAuthConfig,
|
|
117
119
|
getPluginProviders,
|
|
118
120
|
hasRequiredOAuthScope,
|
|
121
|
+
isActorUserId,
|
|
119
122
|
isPluginConfigKey,
|
|
120
123
|
isPluginProvider,
|
|
121
124
|
isRecord,
|
|
@@ -124,6 +127,7 @@ import {
|
|
|
124
127
|
logInfo,
|
|
125
128
|
logWarn,
|
|
126
129
|
normalizeGenAiFinishReason,
|
|
130
|
+
parseActorUserId,
|
|
127
131
|
parseCredentialContext,
|
|
128
132
|
parseOAuthTokenResponse,
|
|
129
133
|
resolveAuthTokenPlaceholder,
|
|
@@ -134,11 +138,12 @@ import {
|
|
|
134
138
|
setSpanAttributes,
|
|
135
139
|
setSpanStatus,
|
|
136
140
|
setTags,
|
|
141
|
+
slackActorIdentity,
|
|
137
142
|
toOptionalNumber,
|
|
138
143
|
toOptionalString,
|
|
139
144
|
withContext,
|
|
140
145
|
withSpan
|
|
141
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-OIIXZOOC.js";
|
|
142
147
|
import {
|
|
143
148
|
sentry_exports
|
|
144
149
|
} from "./chunk-Z3YD6NHK.js";
|
|
@@ -3335,17 +3340,6 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
3335
3340
|
// src/chat/tools/slack/channel-post-message.ts
|
|
3336
3341
|
import { Type as Type14 } from "@sinclair/typebox";
|
|
3337
3342
|
|
|
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
3343
|
// src/chat/slack/outbound.ts
|
|
3350
3344
|
var MAX_SLACK_MESSAGE_TEXT_CHARS = 4e4;
|
|
3351
3345
|
function requireSlackConversationId(channelId, action) {
|
|
@@ -3453,7 +3447,7 @@ async function postSlackEphemeralMessage(input) {
|
|
|
3453
3447
|
input.channelId,
|
|
3454
3448
|
"Slack ephemeral message posting"
|
|
3455
3449
|
);
|
|
3456
|
-
const userId = input.userId
|
|
3450
|
+
const userId = parseActorUserId(input.userId);
|
|
3457
3451
|
if (!userId) {
|
|
3458
3452
|
throw new Error("Slack ephemeral message posting requires a user ID");
|
|
3459
3453
|
}
|
|
@@ -11224,13 +11218,17 @@ function extractSliceUsage(messages, beforeMessageCount) {
|
|
|
11224
11218
|
return hasAgentTurnUsage(usage) ? usage : void 0;
|
|
11225
11219
|
}
|
|
11226
11220
|
function requesterFromContext(requester, requesterId) {
|
|
11227
|
-
const identity =
|
|
11228
|
-
|
|
11229
|
-
...
|
|
11230
|
-
...
|
|
11231
|
-
...
|
|
11221
|
+
const identity = actorRequesterFromContext(requester, requesterId);
|
|
11222
|
+
const agentRequester = {
|
|
11223
|
+
...identity?.email ? { email: identity.email } : {},
|
|
11224
|
+
...identity?.fullName ? { fullName: identity.fullName } : {},
|
|
11225
|
+
...identity?.userId ? { slackUserId: identity.userId } : {},
|
|
11226
|
+
...identity?.userName ? { slackUserName: identity.userName } : {}
|
|
11232
11227
|
};
|
|
11233
|
-
return Object.keys(
|
|
11228
|
+
return Object.keys(agentRequester).length > 0 ? agentRequester : void 0;
|
|
11229
|
+
}
|
|
11230
|
+
function actorRequesterFromContext(requester, requesterId) {
|
|
11231
|
+
return buildActorIdentity(requester, requesterId);
|
|
11234
11232
|
}
|
|
11235
11233
|
function surfaceFromContext(context) {
|
|
11236
11234
|
if (context.surface) {
|
|
@@ -11364,6 +11362,10 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11364
11362
|
context.requester,
|
|
11365
11363
|
context.correlation?.requesterId
|
|
11366
11364
|
);
|
|
11365
|
+
const actorRequester = actorRequesterFromContext(
|
|
11366
|
+
context.requester,
|
|
11367
|
+
context.correlation?.requesterId
|
|
11368
|
+
);
|
|
11367
11369
|
const surface = surfaceFromContext(context);
|
|
11368
11370
|
const credentialActor = context.credentialContext?.actor;
|
|
11369
11371
|
const credentialActorLogContext = credentialActor ? {
|
|
@@ -11493,7 +11495,7 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11493
11495
|
const authRequesterId = context.credentialContext?.actor.type === "user" ? context.credentialContext.actor.userId : void 0;
|
|
11494
11496
|
const userTokenStore = createUserTokenStore();
|
|
11495
11497
|
const agentPluginHooks = createAgentPluginHookRunner({
|
|
11496
|
-
requester:
|
|
11498
|
+
requester: actorRequester
|
|
11497
11499
|
});
|
|
11498
11500
|
sandboxExecutor = createSandboxExecutor({
|
|
11499
11501
|
sandboxId: context.sandbox?.sandboxId,
|
|
@@ -11510,7 +11512,7 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11510
11512
|
const result = await maybeExecuteJrRpcCustomCommand(command, {
|
|
11511
11513
|
activeSkill: skillSandbox.getActiveSkill(),
|
|
11512
11514
|
channelConfiguration: context.channelConfiguration,
|
|
11513
|
-
requesterId:
|
|
11515
|
+
requesterId: actorRequester?.userId,
|
|
11514
11516
|
onConfigurationValueChanged: (key, value) => {
|
|
11515
11517
|
if (value === void 0) {
|
|
11516
11518
|
delete configurationValues[key];
|
|
@@ -11746,7 +11748,7 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11746
11748
|
{
|
|
11747
11749
|
channelId: toolChannelId,
|
|
11748
11750
|
channelCapabilities,
|
|
11749
|
-
requester:
|
|
11751
|
+
requester: actorRequester,
|
|
11750
11752
|
teamId: context.correlation?.teamId,
|
|
11751
11753
|
messageTs: context.correlation?.messageTs,
|
|
11752
11754
|
threadTs: context.correlation?.threadTs,
|
|
@@ -11809,7 +11811,7 @@ async function generateAssistantReply(messageText2, context = {}) {
|
|
|
11809
11811
|
slackConversation: context.slackConversation
|
|
11810
11812
|
},
|
|
11811
11813
|
invocation: skillInvocation,
|
|
11812
|
-
requester:
|
|
11814
|
+
requester: actorRequester,
|
|
11813
11815
|
artifactState: context.artifactState,
|
|
11814
11816
|
configuration: configurationValues
|
|
11815
11817
|
}) : null;
|
|
@@ -12445,6 +12447,7 @@ var CONTEXT_MIN_LIVE_MESSAGES = 12;
|
|
|
12445
12447
|
var CONTEXT_COMPACTION_BATCH_SIZE = 24;
|
|
12446
12448
|
var CONTEXT_MAX_COMPACTIONS = 16;
|
|
12447
12449
|
var CONTEXT_MAX_MESSAGE_CHARS = 3200;
|
|
12450
|
+
var SLACK_USER_ID_DISPLAY_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
12448
12451
|
function generateConversationId(prefix) {
|
|
12449
12452
|
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
12450
12453
|
}
|
|
@@ -12464,7 +12467,7 @@ function buildImageContextSuffix(message, conversation) {
|
|
|
12464
12467
|
return ` [image context: ${summaries.join(" | ")}]`;
|
|
12465
12468
|
}
|
|
12466
12469
|
function renderConversationMessageLine(message, conversation) {
|
|
12467
|
-
const displayName =
|
|
12470
|
+
const displayName = conversationAuthorDisplayName(message);
|
|
12468
12471
|
const markers = [];
|
|
12469
12472
|
if (message.meta?.replied === false) {
|
|
12470
12473
|
markers.push(
|
|
@@ -12478,6 +12481,18 @@ function renderConversationMessageLine(message, conversation) {
|
|
|
12478
12481
|
const imageContext = buildImageContextSuffix(message, conversation);
|
|
12479
12482
|
return `[${message.role}] ${displayName}: ${message.text}${imageContext}${markerSuffix}`;
|
|
12480
12483
|
}
|
|
12484
|
+
function conversationAuthorDisplayName(message) {
|
|
12485
|
+
const author = message.author;
|
|
12486
|
+
const fullName = authorDisplayField(author?.fullName, author?.userId);
|
|
12487
|
+
const userName = authorDisplayField(author?.userName, author?.userId);
|
|
12488
|
+
return fullName ?? userName ?? (message.role === "assistant" ? botConfig.userName : message.role);
|
|
12489
|
+
}
|
|
12490
|
+
function authorDisplayField(value, userId) {
|
|
12491
|
+
if (!value || value === userId || SLACK_USER_ID_DISPLAY_PATTERN.test(value)) {
|
|
12492
|
+
return void 0;
|
|
12493
|
+
}
|
|
12494
|
+
return value;
|
|
12495
|
+
}
|
|
12481
12496
|
function updateConversationStats(conversation) {
|
|
12482
12497
|
const contextText = buildConversationContext(conversation);
|
|
12483
12498
|
conversation.stats.estimatedContextTokens = estimateTextTokens(
|
|
@@ -12547,11 +12562,12 @@ function buildConversationContext(conversation, options = {}) {
|
|
|
12547
12562
|
}
|
|
12548
12563
|
lines.push("<thread-transcript>");
|
|
12549
12564
|
for (const [index, message] of messages.entries()) {
|
|
12550
|
-
const author = escapeXml(message
|
|
12565
|
+
const author = escapeXml(conversationAuthorDisplayName(message));
|
|
12566
|
+
const actorIdAttr = message.author?.userId ? ` actor_id="${escapeXml(message.author.userId)}"` : "";
|
|
12551
12567
|
const ts = new Date(message.createdAtMs).toISOString();
|
|
12552
12568
|
const slackTsAttr = message.meta?.slackTs ? ` slack_ts="${escapeXml(message.meta.slackTs)}"` : "";
|
|
12553
12569
|
lines.push(
|
|
12554
|
-
` <message index="${index + 1}" ts="${ts}" role="${message.role}" author="${author}"${slackTsAttr}>`,
|
|
12570
|
+
` <message index="${index + 1}" ts="${ts}" role="${message.role}" author="${author}"${actorIdAttr}${slackTsAttr}>`,
|
|
12555
12571
|
renderConversationMessageLine(message, conversation),
|
|
12556
12572
|
" </message>"
|
|
12557
12573
|
);
|
|
@@ -14511,7 +14527,7 @@ function validateDispatchOptions(options) {
|
|
|
14511
14527
|
if (options.credentialSubject.type !== "user") {
|
|
14512
14528
|
throw new Error("Dispatch credentialSubject type must be user");
|
|
14513
14529
|
}
|
|
14514
|
-
if (!options.credentialSubject.userId
|
|
14530
|
+
if (!isActorUserId(options.credentialSubject.userId)) {
|
|
14515
14531
|
throw new Error("Dispatch credentialSubject userId is required");
|
|
14516
14532
|
}
|
|
14517
14533
|
if (options.credentialSubject.allowedWhen !== "private-direct-conversation") {
|
|
@@ -15464,15 +15480,13 @@ function getTeamId(message) {
|
|
|
15464
15480
|
}
|
|
15465
15481
|
|
|
15466
15482
|
// src/chat/runtime/processing-reaction.ts
|
|
15467
|
-
var PROCESSING_REACTION_EMOJI = "eyes";
|
|
15468
|
-
var COMPLETED_REACTION_EMOJI = "white_check_mark";
|
|
15469
15483
|
var noProcessingReaction = {
|
|
15470
15484
|
complete: async () => void 0,
|
|
15471
15485
|
keep: () => void 0,
|
|
15472
15486
|
stop: async () => void 0
|
|
15473
15487
|
};
|
|
15474
15488
|
function isProcessingReactionEmoji(value) {
|
|
15475
|
-
return typeof value === "string" && normalizeSlackEmojiName(value) ===
|
|
15489
|
+
return typeof value === "string" && normalizeSlackEmojiName(value) === botConfig.processingReactionEmoji;
|
|
15476
15490
|
}
|
|
15477
15491
|
function shouldKeepProcessingReactionForToolInvocation(input) {
|
|
15478
15492
|
return input.toolName === "slackMessageAddReaction" && isProcessingReactionEmoji(input.params.emoji);
|
|
@@ -15498,7 +15512,7 @@ async function startSlackProcessingReactionForMessage(args) {
|
|
|
15498
15512
|
await addReactionToMessage({
|
|
15499
15513
|
channelId: args.channelId,
|
|
15500
15514
|
timestamp: args.timestamp,
|
|
15501
|
-
emoji:
|
|
15515
|
+
emoji: botConfig.processingReactionEmoji
|
|
15502
15516
|
});
|
|
15503
15517
|
} catch (error) {
|
|
15504
15518
|
args.logException(
|
|
@@ -15523,7 +15537,7 @@ async function startSlackProcessingReactionForMessage(args) {
|
|
|
15523
15537
|
await removeReactionFromMessage({
|
|
15524
15538
|
channelId: args.channelId,
|
|
15525
15539
|
timestamp: args.timestamp,
|
|
15526
|
-
emoji:
|
|
15540
|
+
emoji: botConfig.processingReactionEmoji
|
|
15527
15541
|
});
|
|
15528
15542
|
return true;
|
|
15529
15543
|
} catch (error) {
|
|
@@ -15550,7 +15564,7 @@ async function startSlackProcessingReactionForMessage(args) {
|
|
|
15550
15564
|
await addReactionToMessage({
|
|
15551
15565
|
channelId: args.channelId,
|
|
15552
15566
|
timestamp: args.timestamp,
|
|
15553
|
-
emoji:
|
|
15567
|
+
emoji: botConfig.completedReactionEmoji
|
|
15554
15568
|
});
|
|
15555
15569
|
} catch (error) {
|
|
15556
15570
|
args.logException(
|
|
@@ -15997,6 +16011,87 @@ function htmlCallbackResponse(title, message, status) {
|
|
|
15997
16011
|
});
|
|
15998
16012
|
}
|
|
15999
16013
|
|
|
16014
|
+
// src/chat/slack/user.ts
|
|
16015
|
+
var USER_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
16016
|
+
var userCache = /* @__PURE__ */ new Map();
|
|
16017
|
+
function readFromCache(userId) {
|
|
16018
|
+
const hit = userCache.get(userId);
|
|
16019
|
+
if (!hit) return null;
|
|
16020
|
+
if (hit.expiresAt < Date.now()) {
|
|
16021
|
+
userCache.delete(userId);
|
|
16022
|
+
return null;
|
|
16023
|
+
}
|
|
16024
|
+
return hit.value;
|
|
16025
|
+
}
|
|
16026
|
+
function writeToCache(userId, value) {
|
|
16027
|
+
userCache.set(userId, {
|
|
16028
|
+
value,
|
|
16029
|
+
expiresAt: Date.now() + USER_CACHE_TTL_MS
|
|
16030
|
+
});
|
|
16031
|
+
}
|
|
16032
|
+
async function lookupSlackUser(userId) {
|
|
16033
|
+
if (!userId) {
|
|
16034
|
+
return null;
|
|
16035
|
+
}
|
|
16036
|
+
const cached = readFromCache(userId);
|
|
16037
|
+
if (cached) {
|
|
16038
|
+
return cached;
|
|
16039
|
+
}
|
|
16040
|
+
const token = getSlackBotToken();
|
|
16041
|
+
if (!token) {
|
|
16042
|
+
return null;
|
|
16043
|
+
}
|
|
16044
|
+
try {
|
|
16045
|
+
const response = await fetch(
|
|
16046
|
+
`https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`,
|
|
16047
|
+
{
|
|
16048
|
+
headers: {
|
|
16049
|
+
authorization: `Bearer ${token}`
|
|
16050
|
+
}
|
|
16051
|
+
}
|
|
16052
|
+
);
|
|
16053
|
+
if (!response.ok) {
|
|
16054
|
+
logWarn(
|
|
16055
|
+
"slack_user_lookup_failed",
|
|
16056
|
+
{},
|
|
16057
|
+
{
|
|
16058
|
+
"enduser.id": userId,
|
|
16059
|
+
"http.response.status_code": response.status
|
|
16060
|
+
},
|
|
16061
|
+
"Slack user lookup request failed"
|
|
16062
|
+
);
|
|
16063
|
+
return null;
|
|
16064
|
+
}
|
|
16065
|
+
const payload = await response.json();
|
|
16066
|
+
if (!payload.ok || !payload.user) {
|
|
16067
|
+
return null;
|
|
16068
|
+
}
|
|
16069
|
+
const userName = payload.user.name?.trim() || void 0;
|
|
16070
|
+
const fullName = payload.user.profile?.display_name?.trim() || payload.user.profile?.real_name?.trim() || payload.user.real_name?.trim() || void 0;
|
|
16071
|
+
const result = {
|
|
16072
|
+
userName,
|
|
16073
|
+
fullName,
|
|
16074
|
+
email: payload.user.profile?.email?.trim() || void 0
|
|
16075
|
+
};
|
|
16076
|
+
writeToCache(userId, result);
|
|
16077
|
+
return result;
|
|
16078
|
+
} catch (error) {
|
|
16079
|
+
logWarn(
|
|
16080
|
+
"slack_user_lookup_failed",
|
|
16081
|
+
{},
|
|
16082
|
+
{
|
|
16083
|
+
"enduser.id": userId,
|
|
16084
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
16085
|
+
},
|
|
16086
|
+
"Slack user lookup failed with exception"
|
|
16087
|
+
);
|
|
16088
|
+
return null;
|
|
16089
|
+
}
|
|
16090
|
+
}
|
|
16091
|
+
async function lookupSlackActorIdentity(userId) {
|
|
16092
|
+
return slackActorIdentity(userId, await lookupSlackUser(userId));
|
|
16093
|
+
}
|
|
16094
|
+
|
|
16000
16095
|
// src/handlers/mcp-oauth-callback.ts
|
|
16001
16096
|
var CALLBACK_PAGES = {
|
|
16002
16097
|
missing_state: {
|
|
@@ -16197,6 +16292,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
16197
16292
|
}),
|
|
16198
16293
|
ttlMs: THREAD_STATE_TTL_MS4
|
|
16199
16294
|
});
|
|
16295
|
+
const requester = await lookupSlackActorIdentity(authSession.userId);
|
|
16200
16296
|
return {
|
|
16201
16297
|
messageText: lockedUserMessage.text,
|
|
16202
16298
|
messageTs: getTurnUserSlackMessageTs(lockedUserMessage),
|
|
@@ -16204,11 +16300,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
16204
16300
|
credentialContext: {
|
|
16205
16301
|
actor: { type: "user", userId: authSession.userId }
|
|
16206
16302
|
},
|
|
16207
|
-
requester
|
|
16208
|
-
userId: authSession.userId,
|
|
16209
|
-
userName: lockedUserMessage.author?.userName,
|
|
16210
|
-
fullName: lockedUserMessage.author?.fullName
|
|
16211
|
-
},
|
|
16303
|
+
requester,
|
|
16212
16304
|
correlation: {
|
|
16213
16305
|
conversationId: authSession.conversationId,
|
|
16214
16306
|
turnId: lockedSessionId,
|
|
@@ -16691,6 +16783,9 @@ async function resumeOAuthSessionRecordTurn(stored) {
|
|
|
16691
16783
|
}),
|
|
16692
16784
|
ttlMs: THREAD_STATE_TTL_MS5
|
|
16693
16785
|
});
|
|
16786
|
+
const requester = await lookupSlackActorIdentity(
|
|
16787
|
+
lockedUserMessage.author.userId
|
|
16788
|
+
);
|
|
16694
16789
|
return {
|
|
16695
16790
|
messageText: stored.pendingMessage ?? lockedUserMessage.text,
|
|
16696
16791
|
messageTs: getTurnUserSlackMessageTs(lockedUserMessage),
|
|
@@ -16701,11 +16796,7 @@ async function resumeOAuthSessionRecordTurn(stored) {
|
|
|
16701
16796
|
userId: lockedUserMessage.author.userId
|
|
16702
16797
|
}
|
|
16703
16798
|
},
|
|
16704
|
-
requester
|
|
16705
|
-
userId: lockedUserMessage.author.userId,
|
|
16706
|
-
userName: lockedUserMessage.author.userName,
|
|
16707
|
-
fullName: lockedUserMessage.author.fullName
|
|
16708
|
-
},
|
|
16799
|
+
requester,
|
|
16709
16800
|
correlation: {
|
|
16710
16801
|
conversationId: stored.resumeConversationId,
|
|
16711
16802
|
turnId: lockedSessionId,
|
|
@@ -16801,6 +16892,7 @@ async function resumePendingOAuthMessage(stored) {
|
|
|
16801
16892
|
const conversationContext = buildConversationContext(conversation, {
|
|
16802
16893
|
excludeMessageId: latestUserMessage?.id
|
|
16803
16894
|
});
|
|
16895
|
+
const requester = await lookupSlackActorIdentity(stored.userId);
|
|
16804
16896
|
await resumeAuthorizedRequest({
|
|
16805
16897
|
messageText: stored.pendingMessage,
|
|
16806
16898
|
channelId: stored.channelId,
|
|
@@ -16811,7 +16903,7 @@ async function resumePendingOAuthMessage(stored) {
|
|
|
16811
16903
|
credentialContext: {
|
|
16812
16904
|
actor: { type: "user", userId: stored.userId }
|
|
16813
16905
|
},
|
|
16814
|
-
requester
|
|
16906
|
+
requester,
|
|
16815
16907
|
conversationContext,
|
|
16816
16908
|
piMessages: conversation.piMessages,
|
|
16817
16909
|
configuration: stored.configuration
|
|
@@ -17690,6 +17782,9 @@ async function resumeTimedOutTurn(payload, options = {}) {
|
|
|
17690
17782
|
excludeMessageId: userMessage2.id
|
|
17691
17783
|
});
|
|
17692
17784
|
const sandbox = getPersistedSandboxState(currentState);
|
|
17785
|
+
const requester = await lookupSlackActorIdentity(
|
|
17786
|
+
userMessage2.author.userId
|
|
17787
|
+
);
|
|
17693
17788
|
return {
|
|
17694
17789
|
messageText: userMessage2.text,
|
|
17695
17790
|
messageTs: getTurnUserSlackMessageTs(userMessage2),
|
|
@@ -17700,11 +17795,7 @@ async function resumeTimedOutTurn(payload, options = {}) {
|
|
|
17700
17795
|
userId: userMessage2.author.userId
|
|
17701
17796
|
}
|
|
17702
17797
|
},
|
|
17703
|
-
requester
|
|
17704
|
-
userId: userMessage2.author.userId,
|
|
17705
|
-
userName: userMessage2.author.userName,
|
|
17706
|
-
fullName: userMessage2.author.fullName
|
|
17707
|
-
},
|
|
17798
|
+
requester,
|
|
17708
17799
|
correlation: {
|
|
17709
17800
|
conversationId: payload.conversationId,
|
|
17710
17801
|
turnId: payload.sessionId,
|
|
@@ -18194,6 +18285,60 @@ function combineTurnText(queuedMessages, latestText) {
|
|
|
18194
18285
|
};
|
|
18195
18286
|
}
|
|
18196
18287
|
|
|
18288
|
+
// src/chat/services/message-actor-identity.ts
|
|
18289
|
+
var messageActors = /* @__PURE__ */ new WeakMap();
|
|
18290
|
+
function canonicalUserId(author, identity) {
|
|
18291
|
+
const authorUserId = parseActorUserId(author.userId);
|
|
18292
|
+
const identityUserId = parseActorUserId(identity.userId);
|
|
18293
|
+
if (authorUserId && identityUserId && authorUserId !== identityUserId) {
|
|
18294
|
+
throw new Error("Message actor identity user id mismatch");
|
|
18295
|
+
}
|
|
18296
|
+
const userId = authorUserId ?? identityUserId;
|
|
18297
|
+
if (!userId) {
|
|
18298
|
+
throw new Error("Message actor identity requires a user id");
|
|
18299
|
+
}
|
|
18300
|
+
return userId;
|
|
18301
|
+
}
|
|
18302
|
+
function actorIdentityFromAuthor(author) {
|
|
18303
|
+
const userId = parseActorUserId(author.userId);
|
|
18304
|
+
return userId ? { userId } : void 0;
|
|
18305
|
+
}
|
|
18306
|
+
function applyIdentityToAuthor(author, identity) {
|
|
18307
|
+
if (!isActorUserId(identity.userId)) {
|
|
18308
|
+
throw new Error("Message actor identity requires a user id");
|
|
18309
|
+
}
|
|
18310
|
+
author.userId = identity.userId;
|
|
18311
|
+
author.userName = identity.userName ?? "";
|
|
18312
|
+
author.fullName = identity.fullName ?? "";
|
|
18313
|
+
}
|
|
18314
|
+
function bindMessageActorIdentity(message, identity) {
|
|
18315
|
+
const userId = canonicalUserId(message.author, identity);
|
|
18316
|
+
const actorIdentity = buildActorIdentity(identity, userId);
|
|
18317
|
+
if (!actorIdentity?.userId) {
|
|
18318
|
+
throw new Error("Message actor identity requires a user id");
|
|
18319
|
+
}
|
|
18320
|
+
messageActors.set(message, actorIdentity);
|
|
18321
|
+
applyIdentityToAuthor(message.author, actorIdentity);
|
|
18322
|
+
return actorIdentity;
|
|
18323
|
+
}
|
|
18324
|
+
function getMessageActorIdentity(message) {
|
|
18325
|
+
return messageActors.get(message) ?? actorIdentityFromAuthor(message.author);
|
|
18326
|
+
}
|
|
18327
|
+
async function ensureSlackMessageActorIdentity(message, lookupSlackUser2) {
|
|
18328
|
+
const existing = messageActors.get(message);
|
|
18329
|
+
if (existing) {
|
|
18330
|
+
return existing;
|
|
18331
|
+
}
|
|
18332
|
+
const userId = parseActorUserId(message.author.userId);
|
|
18333
|
+
if (!userId) {
|
|
18334
|
+
throw new Error("Slack message actor identity requires a user id");
|
|
18335
|
+
}
|
|
18336
|
+
return bindMessageActorIdentity(
|
|
18337
|
+
message,
|
|
18338
|
+
slackActorIdentity(userId, await lookupSlackUser2(userId))
|
|
18339
|
+
);
|
|
18340
|
+
}
|
|
18341
|
+
|
|
18197
18342
|
// src/chat/runtime/slack-runtime.ts
|
|
18198
18343
|
var THREAD_OPTOUT_ACK = "Understood. I'll stay out of this thread unless someone @mentions me again.";
|
|
18199
18344
|
async function maybeHandleThreadOptOutDecision(args) {
|
|
@@ -18253,6 +18398,9 @@ function buildLogContext(deps, args) {
|
|
|
18253
18398
|
modelId: deps.modelId
|
|
18254
18399
|
};
|
|
18255
18400
|
}
|
|
18401
|
+
function requesterUserName(message) {
|
|
18402
|
+
return getMessageActorIdentity(message)?.userName;
|
|
18403
|
+
}
|
|
18256
18404
|
function createSlackTurnRuntime(deps) {
|
|
18257
18405
|
const logContext = (args) => buildLogContext(deps, args);
|
|
18258
18406
|
const createToolInvocationHook = (processingReaction, hooks) => {
|
|
@@ -18326,7 +18474,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18326
18474
|
logContext({
|
|
18327
18475
|
threadId: args.context.threadId,
|
|
18328
18476
|
requesterId: args.context.requesterId,
|
|
18329
|
-
requesterUserName: args.message
|
|
18477
|
+
requesterUserName: requesterUserName(args.message),
|
|
18330
18478
|
channelId: args.context.channelId,
|
|
18331
18479
|
runId: args.context.runId
|
|
18332
18480
|
}),
|
|
@@ -18368,7 +18516,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18368
18516
|
threadId,
|
|
18369
18517
|
channelId,
|
|
18370
18518
|
requesterId: message.author.userId,
|
|
18371
|
-
requesterUserName: message
|
|
18519
|
+
requesterUserName: requesterUserName(message),
|
|
18372
18520
|
runId
|
|
18373
18521
|
});
|
|
18374
18522
|
processingReaction = await processingReactions.start(context, message);
|
|
@@ -18428,7 +18576,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18428
18576
|
const errorContext = logContext({
|
|
18429
18577
|
threadId: deps.getThreadId(thread, message),
|
|
18430
18578
|
requesterId: message.author.userId,
|
|
18431
|
-
requesterUserName: message
|
|
18579
|
+
requesterUserName: requesterUserName(message),
|
|
18432
18580
|
channelId: deps.getChannelId(thread, message),
|
|
18433
18581
|
runId: deps.getRunId(thread, message)
|
|
18434
18582
|
});
|
|
@@ -18484,7 +18632,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18484
18632
|
const turnContext = logContext({
|
|
18485
18633
|
threadId,
|
|
18486
18634
|
requesterId: message.author.userId,
|
|
18487
|
-
requesterUserName: message
|
|
18635
|
+
requesterUserName: requesterUserName(message),
|
|
18488
18636
|
channelId,
|
|
18489
18637
|
runId
|
|
18490
18638
|
});
|
|
@@ -18634,7 +18782,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
18634
18782
|
const errorContext = logContext({
|
|
18635
18783
|
threadId: deps.getThreadId(thread, message),
|
|
18636
18784
|
requesterId: message.author.userId,
|
|
18637
|
-
requesterUserName: message
|
|
18785
|
+
requesterUserName: requesterUserName(message),
|
|
18638
18786
|
channelId: deps.getChannelId(thread, message),
|
|
18639
18787
|
runId: deps.getRunId(thread, message)
|
|
18640
18788
|
});
|
|
@@ -18992,84 +19140,6 @@ function createContextCompactor(deps) {
|
|
|
18992
19140
|
};
|
|
18993
19141
|
}
|
|
18994
19142
|
|
|
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
19143
|
// src/chat/services/subscribed-reply-policy.ts
|
|
19074
19144
|
function createSubscribedReplyPolicy(deps) {
|
|
19075
19145
|
return async (args) => {
|
|
@@ -19793,14 +19863,14 @@ function collectCanvasUrls(artifacts) {
|
|
|
19793
19863
|
].filter((url) => typeof url === "string" && url !== "")
|
|
19794
19864
|
);
|
|
19795
19865
|
}
|
|
19796
|
-
function turnRequester(
|
|
19866
|
+
function turnRequester(identity) {
|
|
19797
19867
|
const requester = {
|
|
19798
|
-
...
|
|
19799
|
-
...
|
|
19800
|
-
...
|
|
19801
|
-
...
|
|
19868
|
+
...identity.email ? { email: identity.email } : {},
|
|
19869
|
+
...identity.fullName ? { fullName: identity.fullName } : {},
|
|
19870
|
+
...identity.userId ? { slackUserId: identity.userId } : {},
|
|
19871
|
+
...identity.userName ? { slackUserName: identity.userName } : {}
|
|
19802
19872
|
};
|
|
19803
|
-
return
|
|
19873
|
+
return requester;
|
|
19804
19874
|
}
|
|
19805
19875
|
async function resolveChannelName(thread) {
|
|
19806
19876
|
const existingName = thread.channel.name?.trim();
|
|
@@ -19909,6 +19979,19 @@ function createReplyToThread(deps) {
|
|
|
19909
19979
|
options.queuedMessages ?? [],
|
|
19910
19980
|
currentText
|
|
19911
19981
|
).userText;
|
|
19982
|
+
await Promise.all(
|
|
19983
|
+
(options.queuedMessages ?? []).map(
|
|
19984
|
+
(queued) => ensureSlackMessageActorIdentity(
|
|
19985
|
+
queued.message,
|
|
19986
|
+
deps.services.lookupSlackUser
|
|
19987
|
+
)
|
|
19988
|
+
)
|
|
19989
|
+
);
|
|
19990
|
+
const requesterIdentity = await ensureSlackMessageActorIdentity(
|
|
19991
|
+
message,
|
|
19992
|
+
deps.services.lookupSlackUser
|
|
19993
|
+
);
|
|
19994
|
+
const requester = turnRequester(requesterIdentity);
|
|
19912
19995
|
const preparedState = options.preparedState ?? await deps.prepareTurnState({
|
|
19913
19996
|
thread,
|
|
19914
19997
|
message,
|
|
@@ -19926,15 +20009,6 @@ function createReplyToThread(deps) {
|
|
|
19926
20009
|
});
|
|
19927
20010
|
const slackMessageTs = getSlackMessageTs(message);
|
|
19928
20011
|
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
20012
|
const turnTraceContext = {
|
|
19939
20013
|
conversationId,
|
|
19940
20014
|
slackThreadId: threadId,
|
|
@@ -20122,16 +20196,15 @@ function createReplyToThread(deps) {
|
|
|
20122
20196
|
conversation: preparedState.conversation
|
|
20123
20197
|
});
|
|
20124
20198
|
await options.onTurnStatePersisted?.();
|
|
20125
|
-
const resolvedUserName = message.author.userName ?? fallbackIdentity?.userName;
|
|
20126
20199
|
if (message.author.userId) {
|
|
20127
20200
|
setSentryUser({
|
|
20128
20201
|
id: message.author.userId,
|
|
20129
|
-
...
|
|
20130
|
-
...
|
|
20202
|
+
...requesterIdentity.userName ? { username: requesterIdentity.userName } : {},
|
|
20203
|
+
...requesterIdentity.email ? { email: requesterIdentity.email } : {}
|
|
20131
20204
|
});
|
|
20132
20205
|
}
|
|
20133
|
-
if (
|
|
20134
|
-
setTags({ slackUserName:
|
|
20206
|
+
if (requesterIdentity.userName) {
|
|
20207
|
+
setTags({ slackUserName: requesterIdentity.userName });
|
|
20135
20208
|
}
|
|
20136
20209
|
const turnAttachments = collectTurnAttachments(
|
|
20137
20210
|
message,
|
|
@@ -20261,12 +20334,7 @@ function createReplyToThread(deps) {
|
|
|
20261
20334
|
credentialContext: {
|
|
20262
20335
|
actor: { type: "user", userId: message.author.userId }
|
|
20263
20336
|
},
|
|
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
|
-
},
|
|
20337
|
+
requester: requesterIdentity,
|
|
20270
20338
|
conversationContext: preparedState.conversationContext,
|
|
20271
20339
|
artifactState: preparedState.artifacts,
|
|
20272
20340
|
piMessages,
|
|
@@ -20673,6 +20741,7 @@ function resolveMessageText(args) {
|
|
|
20673
20741
|
return text || NON_TEXT_MESSAGE_TEXT;
|
|
20674
20742
|
}
|
|
20675
20743
|
function toConversationMessage(args) {
|
|
20744
|
+
const actor = getMessageActorIdentity(args.entry);
|
|
20676
20745
|
const messageHasPotentialImageAttachment = hasPotentialImageAttachment(
|
|
20677
20746
|
args.entry.attachments
|
|
20678
20747
|
);
|
|
@@ -20683,9 +20752,9 @@ function toConversationMessage(args) {
|
|
|
20683
20752
|
text: resolveMessageText(args),
|
|
20684
20753
|
createdAtMs: args.entry.metadata.dateSent.getTime(),
|
|
20685
20754
|
author: {
|
|
20686
|
-
userId:
|
|
20687
|
-
userName:
|
|
20688
|
-
fullName:
|
|
20755
|
+
...actor?.userId ? { userId: actor.userId } : {},
|
|
20756
|
+
...actor?.userName ? { userName: actor.userName } : {},
|
|
20757
|
+
...actor?.fullName ? { fullName: actor.fullName } : {},
|
|
20689
20758
|
isBot: typeof args.entry.author.isBot === "boolean" ? args.entry.author.isBot : void 0
|
|
20690
20759
|
},
|
|
20691
20760
|
meta: {
|
|
@@ -21102,6 +21171,13 @@ async function runWithSlackInstallation(args) {
|
|
|
21102
21171
|
}
|
|
21103
21172
|
|
|
21104
21173
|
// src/chat/task-execution/slack-work.ts
|
|
21174
|
+
function requireSlackAuthorId(message) {
|
|
21175
|
+
const authorId = parseActorUserId(message.author.userId);
|
|
21176
|
+
if (!authorId) {
|
|
21177
|
+
throw new Error("Slack message requires an actor user id");
|
|
21178
|
+
}
|
|
21179
|
+
return authorId;
|
|
21180
|
+
}
|
|
21105
21181
|
function getConnectedState3(stateAdapter) {
|
|
21106
21182
|
return stateAdapter ?? getStateAdapter();
|
|
21107
21183
|
}
|
|
@@ -21126,6 +21202,23 @@ function restoreMessage(args) {
|
|
|
21126
21202
|
rehydrateAttachmentFetchers(message);
|
|
21127
21203
|
return message;
|
|
21128
21204
|
}
|
|
21205
|
+
async function bindSlackActorIdentities(args) {
|
|
21206
|
+
const byAuthorId = /* @__PURE__ */ new Map();
|
|
21207
|
+
for (const message of args.messages) {
|
|
21208
|
+
const authorId = requireSlackAuthorId(message);
|
|
21209
|
+
byAuthorId.set(authorId, [...byAuthorId.get(authorId) ?? [], message]);
|
|
21210
|
+
}
|
|
21211
|
+
await Promise.all(
|
|
21212
|
+
[...byAuthorId].map(async ([authorId, messages]) => {
|
|
21213
|
+
const profile = await args.lookupSlackUser(authorId);
|
|
21214
|
+
await Promise.all(
|
|
21215
|
+
messages.map(
|
|
21216
|
+
(message) => ensureSlackMessageActorIdentity(message, async () => profile)
|
|
21217
|
+
)
|
|
21218
|
+
);
|
|
21219
|
+
})
|
|
21220
|
+
);
|
|
21221
|
+
}
|
|
21129
21222
|
function restoreThread(args) {
|
|
21130
21223
|
const threadId = normalizeIncomingSlackThreadId(
|
|
21131
21224
|
args.threadJson.id,
|
|
@@ -21205,6 +21298,7 @@ function getPendingRecords(work) {
|
|
|
21205
21298
|
function createSlackConversationWorker(options) {
|
|
21206
21299
|
return async (context) => {
|
|
21207
21300
|
const adapter = options.getSlackAdapter();
|
|
21301
|
+
const actorLookup = options.lookupSlackUser ?? lookupSlackUser;
|
|
21208
21302
|
const state = getConnectedState3(options.state);
|
|
21209
21303
|
await state.connect();
|
|
21210
21304
|
const resumeContinuation = options.resumeAwaitingContinuation ?? resumeAwaitingContinuation;
|
|
@@ -21242,6 +21336,10 @@ function createSlackConversationWorker(options) {
|
|
|
21242
21336
|
const messages = records.map(
|
|
21243
21337
|
(record) => restoreMessage({ adapter, record })
|
|
21244
21338
|
);
|
|
21339
|
+
await bindSlackActorIdentities({
|
|
21340
|
+
lookupSlackUser: actorLookup,
|
|
21341
|
+
messages
|
|
21342
|
+
});
|
|
21245
21343
|
const latestMessage = messages[messages.length - 1];
|
|
21246
21344
|
if (!latestMessage) {
|
|
21247
21345
|
return;
|
|
@@ -21328,6 +21426,7 @@ function createSlackConversationWorker(options) {
|
|
|
21328
21426
|
};
|
|
21329
21427
|
}
|
|
21330
21428
|
function buildSlackInboundMessage(args) {
|
|
21429
|
+
const authorId = requireSlackAuthorId(args.message);
|
|
21331
21430
|
return {
|
|
21332
21431
|
conversationId: args.conversationId,
|
|
21333
21432
|
inboundMessageId: [
|
|
@@ -21341,7 +21440,7 @@ function buildSlackInboundMessage(args) {
|
|
|
21341
21440
|
receivedAtMs: args.receivedAtMs,
|
|
21342
21441
|
input: {
|
|
21343
21442
|
text: args.message.text || " ",
|
|
21344
|
-
authorId
|
|
21443
|
+
authorId,
|
|
21345
21444
|
attachments: args.message.attachments,
|
|
21346
21445
|
metadata: {
|
|
21347
21446
|
platform: "slack",
|
|
@@ -21460,7 +21559,8 @@ function extractMessageChangedMention(body, botUserId, adapter) {
|
|
|
21460
21559
|
const channelId = event.channel;
|
|
21461
21560
|
const messageTs = event.message.ts;
|
|
21462
21561
|
const threadTs = event.message.thread_ts ?? messageTs;
|
|
21463
|
-
const userId = event.message.user
|
|
21562
|
+
const userId = parseActorUserId(event.message.user);
|
|
21563
|
+
if (!userId) return null;
|
|
21464
21564
|
const threadId = `slack:${channelId}:${threadTs}`;
|
|
21465
21565
|
const teamId = typeof body.team_id === "string" ? body.team_id : void 0;
|
|
21466
21566
|
const userTeam = typeof event.message.user_team === "string" ? event.message.user_team : void 0;
|
|
@@ -21485,8 +21585,9 @@ function extractMessageChangedMention(body, botUserId, adapter) {
|
|
|
21485
21585
|
raw,
|
|
21486
21586
|
author: {
|
|
21487
21587
|
userId,
|
|
21488
|
-
|
|
21489
|
-
|
|
21588
|
+
// Raw message_changed payloads do not include profile fields.
|
|
21589
|
+
userName: "",
|
|
21590
|
+
fullName: "",
|
|
21490
21591
|
isBot: false,
|
|
21491
21592
|
isMe: false
|
|
21492
21593
|
}
|
|
@@ -21516,10 +21617,17 @@ function isExternalSlackUser(raw) {
|
|
|
21516
21617
|
async function postEphemeral(event, text) {
|
|
21517
21618
|
await event.channel.postEphemeral(event.user, text, { fallbackToDM: false });
|
|
21518
21619
|
}
|
|
21620
|
+
function requireRequesterId(event) {
|
|
21621
|
+
const userId = parseActorUserId(event.user.userId);
|
|
21622
|
+
if (!userId) {
|
|
21623
|
+
throw new Error("Slack slash command requires a requester user id");
|
|
21624
|
+
}
|
|
21625
|
+
return userId;
|
|
21626
|
+
}
|
|
21519
21627
|
function getCommandName() {
|
|
21520
21628
|
return getChatConfig().slack.slashCommand;
|
|
21521
21629
|
}
|
|
21522
|
-
async function handleLink(event, provider) {
|
|
21630
|
+
async function handleLink(event, requesterId, provider) {
|
|
21523
21631
|
if (!isPluginProvider(provider)) {
|
|
21524
21632
|
await postEphemeral(event, `Unknown provider: \`${provider}\``);
|
|
21525
21633
|
return;
|
|
@@ -21533,7 +21641,7 @@ async function handleLink(event, provider) {
|
|
|
21533
21641
|
}
|
|
21534
21642
|
const raw = event.raw;
|
|
21535
21643
|
const result = await startOAuthFlow(provider, {
|
|
21536
|
-
requesterId
|
|
21644
|
+
requesterId,
|
|
21537
21645
|
channelId: raw.channel_id
|
|
21538
21646
|
});
|
|
21539
21647
|
if (!result.ok) {
|
|
@@ -21552,7 +21660,7 @@ async function handleLink(event, provider) {
|
|
|
21552
21660
|
);
|
|
21553
21661
|
}
|
|
21554
21662
|
}
|
|
21555
|
-
async function handleUnlink(event, provider) {
|
|
21663
|
+
async function handleUnlink(event, requesterId, provider) {
|
|
21556
21664
|
if (!isPluginProvider(provider)) {
|
|
21557
21665
|
await postEphemeral(event, `Unknown provider: \`${provider}\``);
|
|
21558
21666
|
return;
|
|
@@ -21565,10 +21673,10 @@ async function handleUnlink(event, provider) {
|
|
|
21565
21673
|
return;
|
|
21566
21674
|
}
|
|
21567
21675
|
const tokenStore = createUserTokenStore();
|
|
21568
|
-
await tokenStore.delete(
|
|
21676
|
+
await tokenStore.delete(requesterId, provider);
|
|
21569
21677
|
logInfo(
|
|
21570
21678
|
"slash_command_unlink",
|
|
21571
|
-
{ slackUserId:
|
|
21679
|
+
{ slackUserId: requesterId },
|
|
21572
21680
|
{ "app.credential.provider": provider },
|
|
21573
21681
|
`Unlinked ${formatProviderLabel(provider)} account via ${getCommandName()} slash command`
|
|
21574
21682
|
);
|
|
@@ -21594,10 +21702,11 @@ async function handleSlashCommand(event) {
|
|
|
21594
21702
|
return;
|
|
21595
21703
|
}
|
|
21596
21704
|
const normalized = provider.toLowerCase();
|
|
21705
|
+
const requesterId = requireRequesterId(event);
|
|
21597
21706
|
if (subcommand === "link") {
|
|
21598
|
-
await handleLink(event, normalized);
|
|
21707
|
+
await handleLink(event, requesterId, normalized);
|
|
21599
21708
|
} else {
|
|
21600
|
-
await handleUnlink(event, normalized);
|
|
21709
|
+
await handleUnlink(event, requesterId, normalized);
|
|
21601
21710
|
}
|
|
21602
21711
|
}
|
|
21603
21712
|
|
|
@@ -21837,15 +21946,12 @@ async function handleSlackEvent(args) {
|
|
|
21837
21946
|
})
|
|
21838
21947
|
);
|
|
21839
21948
|
}
|
|
21840
|
-
function
|
|
21841
|
-
const userId =
|
|
21842
|
-
|
|
21843
|
-
|
|
21844
|
-
|
|
21845
|
-
|
|
21846
|
-
isBot: false,
|
|
21847
|
-
isMe: false
|
|
21848
|
-
};
|
|
21949
|
+
function requireSlackPayloadUserId(value, source) {
|
|
21950
|
+
const userId = parseActorUserId(value);
|
|
21951
|
+
if (!userId) {
|
|
21952
|
+
throw new Error(`${source} is missing a Slack user id`);
|
|
21953
|
+
}
|
|
21954
|
+
return userId;
|
|
21849
21955
|
}
|
|
21850
21956
|
async function handleSlashCommandForm(args) {
|
|
21851
21957
|
const raw = Object.fromEntries(args.params);
|
|
@@ -21855,7 +21961,21 @@ async function handleSlashCommandForm(args) {
|
|
|
21855
21961
|
adapter: args.adapter,
|
|
21856
21962
|
stateAdapter: args.state
|
|
21857
21963
|
});
|
|
21858
|
-
const userId =
|
|
21964
|
+
const userId = requireSlackPayloadUserId(
|
|
21965
|
+
args.params.get("user_id"),
|
|
21966
|
+
"Slack slash command payload"
|
|
21967
|
+
);
|
|
21968
|
+
const userIdentity = buildActorIdentity(
|
|
21969
|
+
{
|
|
21970
|
+
userId,
|
|
21971
|
+
userName: args.params.get("user_name") ?? void 0,
|
|
21972
|
+
fullName: args.params.get("user_name") ?? void 0
|
|
21973
|
+
},
|
|
21974
|
+
userId
|
|
21975
|
+
);
|
|
21976
|
+
if (!userIdentity?.userId) {
|
|
21977
|
+
throw new Error("Slack slash command payload actor identity is invalid");
|
|
21978
|
+
}
|
|
21859
21979
|
await withSpan(
|
|
21860
21980
|
"chat.slash_command",
|
|
21861
21981
|
"chat.slash_command",
|
|
@@ -21870,8 +21990,8 @@ async function handleSlashCommandForm(args) {
|
|
|
21870
21990
|
raw,
|
|
21871
21991
|
user: {
|
|
21872
21992
|
userId,
|
|
21873
|
-
userName:
|
|
21874
|
-
fullName:
|
|
21993
|
+
userName: userIdentity.userName ?? "",
|
|
21994
|
+
fullName: userIdentity.fullName ?? "",
|
|
21875
21995
|
isBot: false,
|
|
21876
21996
|
isMe: false
|
|
21877
21997
|
},
|
|
@@ -21888,10 +22008,13 @@ async function handleInteractivePayload(args) {
|
|
|
21888
22008
|
(candidate) => candidate.action_id === "app_home_disconnect"
|
|
21889
22009
|
);
|
|
21890
22010
|
const provider = action?.selected_option?.value ?? action?.value;
|
|
21891
|
-
|
|
21892
|
-
if (!provider || !userId) {
|
|
22011
|
+
if (!provider) {
|
|
21893
22012
|
return;
|
|
21894
22013
|
}
|
|
22014
|
+
const userId = requireSlackPayloadUserId(
|
|
22015
|
+
args.payload.user?.id,
|
|
22016
|
+
"Slack app home disconnect payload"
|
|
22017
|
+
);
|
|
21895
22018
|
await withSpan(
|
|
21896
22019
|
"chat.app_home_disconnect",
|
|
21897
22020
|
"chat.app_home_disconnect",
|
|
@@ -21986,7 +22109,7 @@ async function handleSlackForm(args) {
|
|
|
21986
22109
|
})
|
|
21987
22110
|
).catch((error) => {
|
|
21988
22111
|
logException(error, "slack_interactive_payload_failed", {
|
|
21989
|
-
slackUserId:
|
|
22112
|
+
slackUserId: payload.user?.id?.trim() || void 0
|
|
21990
22113
|
});
|
|
21991
22114
|
})
|
|
21992
22115
|
);
|