@inkeep/agents-work-apps 0.52.0 → 0.53.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/env.d.ts +2 -2
- package/dist/github/mcp/auth.d.ts +2 -2
- package/dist/github/mcp/index.d.ts +2 -2
- package/dist/github/mcp/index.js +63 -26
- package/dist/github/mcp/schemas.d.ts +1 -1
- package/dist/github/mcp/utils.d.ts +2 -1
- package/dist/github/mcp/utils.js +16 -1
- package/dist/github/routes/setup.d.ts +2 -2
- package/dist/github/routes/tokenExchange.d.ts +2 -2
- package/dist/github/routes/webhooks.d.ts +2 -2
- package/dist/slack/dispatcher.js +11 -1
- package/dist/slack/routes/oauth.js +21 -1
- package/dist/slack/routes/users.js +29 -3
- package/dist/slack/services/agent-resolution.d.ts +1 -0
- package/dist/slack/services/agent-resolution.js +105 -18
- package/dist/slack/services/blocks/index.d.ts +9 -2
- package/dist/slack/services/blocks/index.js +27 -11
- package/dist/slack/services/commands/index.d.ts +1 -1
- package/dist/slack/services/commands/index.js +34 -124
- package/dist/slack/services/events/app-mention.d.ts +4 -14
- package/dist/slack/services/events/app-mention.js +40 -19
- package/dist/slack/services/events/block-actions.js +1 -1
- package/dist/slack/services/events/index.d.ts +1 -1
- package/dist/slack/services/events/modal-submission.js +14 -7
- package/dist/slack/services/events/streaming.js +9 -12
- package/dist/slack/services/events/utils.d.ts +26 -5
- package/dist/slack/services/events/utils.js +40 -15
- package/dist/slack/services/index.d.ts +4 -4
- package/dist/slack/services/index.js +3 -3
- package/dist/slack/services/link-prompt.d.ts +27 -0
- package/dist/slack/services/link-prompt.js +142 -0
- package/dist/slack/services/modals.d.ts +1 -0
- package/dist/slack/services/modals.js +6 -4
- package/dist/slack/services/resume-intent.d.ts +15 -0
- package/dist/slack/services/resume-intent.js +338 -0
- package/dist/slack/tracer.d.ts +1 -1
- package/package.json +2 -2
|
@@ -8,10 +8,10 @@ import { AgentOption } from "../modals.js";
|
|
|
8
8
|
* Called on every @mention and /inkeep command — caching avoids redundant DB queries.
|
|
9
9
|
*/
|
|
10
10
|
declare function findCachedUserMapping(tenantId: string, slackUserId: string, teamId: string, clientId?: string): Promise<{
|
|
11
|
-
|
|
11
|
+
id: string;
|
|
12
12
|
createdAt: string;
|
|
13
13
|
updatedAt: string;
|
|
14
|
-
|
|
14
|
+
slackUserId: string;
|
|
15
15
|
tenantId: string;
|
|
16
16
|
clientId: string;
|
|
17
17
|
slackTeamId: string;
|
|
@@ -112,6 +112,24 @@ declare function checkIfBotThread(slackClient: {
|
|
|
112
112
|
}>;
|
|
113
113
|
};
|
|
114
114
|
}, channel: string, threadTs: string): Promise<boolean>;
|
|
115
|
+
interface SlackAttachment {
|
|
116
|
+
text?: string;
|
|
117
|
+
fallback?: string;
|
|
118
|
+
pretext?: string;
|
|
119
|
+
author_name?: string;
|
|
120
|
+
author_id?: string;
|
|
121
|
+
channel_name?: string;
|
|
122
|
+
channel_id?: string;
|
|
123
|
+
title?: string;
|
|
124
|
+
is_msg_unfurl?: boolean;
|
|
125
|
+
is_share?: boolean;
|
|
126
|
+
from_url?: string;
|
|
127
|
+
fields?: Array<{
|
|
128
|
+
title?: string;
|
|
129
|
+
value?: string;
|
|
130
|
+
}>;
|
|
131
|
+
}
|
|
132
|
+
declare function formatAttachments(attachments: SlackAttachment[] | undefined): string;
|
|
115
133
|
interface ThreadContextOptions {
|
|
116
134
|
includeLastMessage?: boolean;
|
|
117
135
|
resolveUserNames?: boolean;
|
|
@@ -128,6 +146,7 @@ declare function getThreadContext(slackClient: {
|
|
|
128
146
|
user?: string;
|
|
129
147
|
text?: string;
|
|
130
148
|
ts?: string;
|
|
149
|
+
attachments?: SlackAttachment[];
|
|
131
150
|
}>;
|
|
132
151
|
}>;
|
|
133
152
|
};
|
|
@@ -137,8 +156,10 @@ declare function getThreadContext(slackClient: {
|
|
|
137
156
|
}) => Promise<{
|
|
138
157
|
user?: {
|
|
139
158
|
real_name?: string;
|
|
140
|
-
|
|
141
|
-
|
|
159
|
+
profile?: {
|
|
160
|
+
display_name?: string;
|
|
161
|
+
email?: string;
|
|
162
|
+
};
|
|
142
163
|
};
|
|
143
164
|
}>;
|
|
144
165
|
};
|
|
@@ -158,4 +179,4 @@ declare function formatChannelContext(channelInfo: {
|
|
|
158
179
|
name?: string;
|
|
159
180
|
} | null): string;
|
|
160
181
|
//#endregion
|
|
161
|
-
export { ProjectOption, SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatChannelContext, formatChannelLabel, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
|
|
182
|
+
export { ProjectOption, SlackAttachment, SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatAttachments, formatChannelContext, formatChannelLabel, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
|
|
@@ -34,17 +34,19 @@ async function findCachedUserMapping(tenantId, slackUserId, teamId, clientId = "
|
|
|
34
34
|
const cached = userMappingCache.get(cacheKey);
|
|
35
35
|
if (cached && cached.expiresAt > Date.now()) return cached.mapping;
|
|
36
36
|
const mapping = await findWorkAppSlackUserMapping(runDbClient_default)(tenantId, slackUserId, teamId, clientId);
|
|
37
|
-
if (
|
|
38
|
-
evictExpiredEntries();
|
|
37
|
+
if (mapping) {
|
|
39
38
|
if (userMappingCache.size >= USER_MAPPING_CACHE_MAX_SIZE) {
|
|
40
|
-
|
|
41
|
-
if (
|
|
39
|
+
evictExpiredEntries();
|
|
40
|
+
if (userMappingCache.size >= USER_MAPPING_CACHE_MAX_SIZE) {
|
|
41
|
+
const oldestKey = userMappingCache.keys().next().value;
|
|
42
|
+
if (oldestKey) userMappingCache.delete(oldestKey);
|
|
43
|
+
}
|
|
42
44
|
}
|
|
45
|
+
userMappingCache.set(cacheKey, {
|
|
46
|
+
mapping,
|
|
47
|
+
expiresAt: Date.now() + USER_MAPPING_CACHE_TTL_MS
|
|
48
|
+
});
|
|
43
49
|
}
|
|
44
|
-
userMappingCache.set(cacheKey, {
|
|
45
|
-
mapping,
|
|
46
|
-
expiresAt: Date.now() + USER_MAPPING_CACHE_TTL_MS
|
|
47
|
-
});
|
|
48
50
|
return mapping;
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
@@ -328,6 +330,27 @@ async function checkIfBotThread(slackClient, channel, threadTs) {
|
|
|
328
330
|
return false;
|
|
329
331
|
}
|
|
330
332
|
}
|
|
333
|
+
function formatAttachments(attachments) {
|
|
334
|
+
if (!attachments || attachments.length === 0) return "";
|
|
335
|
+
const parts = [];
|
|
336
|
+
for (const att of attachments) {
|
|
337
|
+
const content = att.text || att.fallback;
|
|
338
|
+
if (!content) continue;
|
|
339
|
+
const isSharedMessage = att.is_msg_unfurl || att.is_share;
|
|
340
|
+
const meta = [];
|
|
341
|
+
if (att.author_name) meta.push(`from ${att.author_name}`);
|
|
342
|
+
if (att.channel_name) meta.push(`in #${att.channel_name}`);
|
|
343
|
+
else if (att.channel_id) meta.push(`in channel ${att.channel_id}`);
|
|
344
|
+
const label = isSharedMessage ? "Shared message" : "Attachment";
|
|
345
|
+
const metaSuffix = meta.length > 0 ? ` (${meta.join(", ")})` : "";
|
|
346
|
+
const sourceLine = att.from_url ? `\n[Source: ${att.from_url}]` : "";
|
|
347
|
+
parts.push(`[${label}${metaSuffix}]:\n\`\`\`\n${content}\n\`\`\`${sourceLine}`);
|
|
348
|
+
if (att.fields && att.fields.length > 0) {
|
|
349
|
+
for (const field of att.fields) if (field.title && field.value) parts.push(`${field.title}: ${field.value}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return parts.join("\n\n");
|
|
353
|
+
}
|
|
331
354
|
async function getThreadContext(slackClient, channel, threadTs, options = {}) {
|
|
332
355
|
const { includeLastMessage = false, resolveUserNames = true } = options;
|
|
333
356
|
try {
|
|
@@ -347,15 +370,15 @@ async function getThreadContext(slackClient, channel, threadTs, options = {}) {
|
|
|
347
370
|
try {
|
|
348
371
|
const userInfo = await slackClient.users?.info({ user: userId });
|
|
349
372
|
userNameCache.set(userId, {
|
|
350
|
-
displayName: userInfo?.user?.display_name,
|
|
373
|
+
displayName: userInfo?.user?.profile?.display_name,
|
|
351
374
|
fullName: userInfo?.user?.real_name,
|
|
352
|
-
|
|
375
|
+
email: userInfo?.user?.profile?.email
|
|
353
376
|
});
|
|
354
377
|
} catch {
|
|
355
378
|
userNameCache.set(userId, {
|
|
356
379
|
displayName: void 0,
|
|
357
380
|
fullName: void 0,
|
|
358
|
-
|
|
381
|
+
email: void 0
|
|
359
382
|
});
|
|
360
383
|
}
|
|
361
384
|
}));
|
|
@@ -365,10 +388,10 @@ async function getThreadContext(slackClient, channel, threadTs, options = {}) {
|
|
|
365
388
|
const parts = [`userId: ${userId}`];
|
|
366
389
|
if (info.displayName) parts.push(`"${info.displayName}"`);
|
|
367
390
|
if (info.fullName) parts.push(`"${info.fullName}"`);
|
|
368
|
-
if (info.
|
|
391
|
+
if (info.email) parts.push(info.email);
|
|
369
392
|
userDirectoryLines.push(`- ${parts.join(", ")}`);
|
|
370
393
|
}
|
|
371
|
-
return `${userDirectoryLines.length > 0 ? `Users in this thread (UserId - DisplayName, FullName,
|
|
394
|
+
return `${userDirectoryLines.length > 0 ? `Users in this thread (UserId - DisplayName, FullName, Email):\n${userDirectoryLines.join("\n")}\n\n` : ""}Messages in this thread:\n${messagesToProcess.map((msg, index) => {
|
|
372
395
|
const isBot = !!msg.bot_id;
|
|
373
396
|
const isParent = index === 0;
|
|
374
397
|
let role;
|
|
@@ -377,7 +400,9 @@ async function getThreadContext(slackClient, channel, threadTs, options = {}) {
|
|
|
377
400
|
else role = "Unknown";
|
|
378
401
|
const prefix = isParent ? "[Thread Start] " : "";
|
|
379
402
|
const messageText = msg.text || "";
|
|
380
|
-
|
|
403
|
+
const attachmentText = formatAttachments(msg.attachments);
|
|
404
|
+
const fullText = attachmentText ? `${messageText}\n${attachmentText}` : messageText;
|
|
405
|
+
return `${prefix}${role}: """${fullText}"""`;
|
|
381
406
|
}).join("\n\n")}`;
|
|
382
407
|
} catch (threadError) {
|
|
383
408
|
logger.warn({
|
|
@@ -412,4 +437,4 @@ function formatChannelContext(channelInfo) {
|
|
|
412
437
|
}
|
|
413
438
|
|
|
414
439
|
//#endregion
|
|
415
|
-
export { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatChannelContext, formatChannelLabel, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
|
|
440
|
+
export { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatAttachments, formatChannelContext, formatChannelLabel, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
|
|
2
|
-
import { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildCitationsBlock, buildConversationResponseBlocks, buildDataArtifactBlocks, buildDataComponentBlocks, buildFollowUpButton, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage,
|
|
2
|
+
import { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildCitationsBlock, buildConversationResponseBlocks, buildDataArtifactBlocks, buildDataComponentBlocks, buildFollowUpButton, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
|
|
3
3
|
import { checkUserIsChannelMember, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread, revokeSlackToken } from "./client.js";
|
|
4
4
|
import { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
|
|
5
5
|
import { SlackCommandPayload, SlackCommandResponse } from "./types.js";
|
|
6
6
|
import { handleAgentPickerCommand, handleCommand, handleHelpCommand, handleLinkCommand, handleQuestionCommand, handleStatusCommand, handleUnlinkCommand } from "./commands/index.js";
|
|
7
|
+
import { AgentOption, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, FollowUpModalMetadata, ModalMetadata, buildAgentSelectorModal, buildFollowUpModal, buildMessageShortcutModal } from "./modals.js";
|
|
8
|
+
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
7
9
|
import { InlineSelectorMetadata, handleAppMention } from "./events/app-mention.js";
|
|
8
10
|
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleToolApproval } from "./events/block-actions.js";
|
|
9
11
|
import { handleFollowUpSubmission, handleModalSubmission } from "./events/modal-submission.js";
|
|
10
|
-
import { AgentOption, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, FollowUpModalMetadata, ModalMetadata, buildAgentSelectorModal, buildFollowUpModal, buildMessageShortcutModal } from "./modals.js";
|
|
11
|
-
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
12
12
|
import { StreamResult, streamAgentResponse } from "./events/streaming.js";
|
|
13
13
|
import "./events/index.js";
|
|
14
14
|
import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
|
|
15
15
|
import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
|
|
16
|
-
export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, FollowUpButtonParams, FollowUpModalMetadata, InlineSelectorMetadata, ModalMetadata, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceInstallData, buildAgentSelectorModal, buildCitationsBlock, buildConversationResponseBlocks, buildDataArtifactBlocks, buildDataComponentBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage,
|
|
16
|
+
export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, FollowUpButtonParams, FollowUpModalMetadata, InlineSelectorMetadata, ModalMetadata, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceInstallData, buildAgentSelectorModal, buildCitationsBlock, buildConversationResponseBlocks, buildDataArtifactBlocks, buildDataComponentBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleFollowUpSubmission, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
|
|
2
|
+
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
2
3
|
import { getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
|
|
3
|
-
import { ToolApprovalButtonValueSchema, buildCitationsBlock, buildConversationResponseBlocks, buildDataArtifactBlocks, buildDataComponentBlocks, buildFollowUpButton, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage,
|
|
4
|
+
import { ToolApprovalButtonValueSchema, buildCitationsBlock, buildConversationResponseBlocks, buildDataArtifactBlocks, buildDataComponentBlocks, buildFollowUpButton, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
|
|
4
5
|
import { checkUserIsChannelMember, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread, revokeSlackToken } from "./client.js";
|
|
5
|
-
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
6
6
|
import { buildAgentSelectorModal, buildFollowUpModal, buildMessageShortcutModal } from "./modals.js";
|
|
7
7
|
import { handleAgentPickerCommand, handleCommand, handleHelpCommand, handleLinkCommand, handleQuestionCommand, handleStatusCommand, handleUnlinkCommand } from "./commands/index.js";
|
|
8
8
|
import { streamAgentResponse } from "./events/streaming.js";
|
|
@@ -13,4 +13,4 @@ import "./events/index.js";
|
|
|
13
13
|
import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
|
|
14
14
|
import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
|
|
15
15
|
|
|
16
|
-
export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildCitationsBlock, buildConversationResponseBlocks, buildDataArtifactBlocks, buildDataComponentBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage,
|
|
16
|
+
export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildCitationsBlock, buildConversationResponseBlocks, buildDataArtifactBlocks, buildDataComponentBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleFollowUpSubmission, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SlackLinkIntent } from "@inkeep/agents-core";
|
|
2
|
+
import * as slack_block_builder0 from "slack-block-builder";
|
|
3
|
+
|
|
4
|
+
//#region src/slack/services/link-prompt.d.ts
|
|
5
|
+
type LinkPromptResult = {
|
|
6
|
+
type: 'auto_invite';
|
|
7
|
+
url: string;
|
|
8
|
+
email: string;
|
|
9
|
+
expiresInMinutes: number;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'jwt_link';
|
|
12
|
+
url: string;
|
|
13
|
+
expiresInMinutes: number;
|
|
14
|
+
};
|
|
15
|
+
interface ResolveLinkActionParams {
|
|
16
|
+
tenantId: string;
|
|
17
|
+
teamId: string;
|
|
18
|
+
slackUserId: string;
|
|
19
|
+
botToken: string;
|
|
20
|
+
slackEnterpriseId?: string;
|
|
21
|
+
slackUsername?: string;
|
|
22
|
+
intent?: SlackLinkIntent;
|
|
23
|
+
}
|
|
24
|
+
declare function resolveUnlinkedUserAction(params: ResolveLinkActionParams): Promise<LinkPromptResult>;
|
|
25
|
+
declare function buildLinkPromptMessage(result: LinkPromptResult): Readonly<slack_block_builder0.SlackMessageDto>;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { LinkPromptResult, ResolveLinkActionParams, buildLinkPromptMessage, resolveUnlinkedUserAction };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { env } from "../../env.js";
|
|
2
|
+
import { getLogger } from "../../logger.js";
|
|
3
|
+
import runDbClient_default from "../../db/runDbClient.js";
|
|
4
|
+
import { createCreateInkeepAccountMessage, createSmartLinkMessage } from "./blocks/index.js";
|
|
5
|
+
import { getSlackClient } from "./client.js";
|
|
6
|
+
import { createInvitationInDb, findWorkAppSlackWorkspaceByTeamId, getOrganizationMemberByEmail, getPendingInvitationsByEmail, signSlackLinkToken } from "@inkeep/agents-core";
|
|
7
|
+
|
|
8
|
+
//#region src/slack/services/link-prompt.ts
|
|
9
|
+
const logger = getLogger("slack-link-prompt");
|
|
10
|
+
const LINK_CODE_TTL_MINUTES = 10;
|
|
11
|
+
async function resolveUnlinkedUserAction(params) {
|
|
12
|
+
const { tenantId, teamId, slackUserId, botToken, slackEnterpriseId, slackUsername, intent } = params;
|
|
13
|
+
const manageUiUrl = env.INKEEP_AGENTS_MANAGE_UI_URL || "http://localhost:3000";
|
|
14
|
+
const autoInvite = await tryAutoInvite({
|
|
15
|
+
tenantId,
|
|
16
|
+
teamId,
|
|
17
|
+
slackUserId,
|
|
18
|
+
botToken
|
|
19
|
+
});
|
|
20
|
+
if (autoInvite) {
|
|
21
|
+
const linkToken$1 = await signSlackLinkToken({
|
|
22
|
+
tenantId,
|
|
23
|
+
slackTeamId: teamId,
|
|
24
|
+
slackUserId,
|
|
25
|
+
slackEnterpriseId,
|
|
26
|
+
slackUsername,
|
|
27
|
+
intent
|
|
28
|
+
});
|
|
29
|
+
const authMethod = autoInvite.authMethod;
|
|
30
|
+
const linkReturnUrl = `/link?token=${encodeURIComponent(linkToken$1)}`;
|
|
31
|
+
const acceptUrl = authMethod === "email-password" ? `${manageUiUrl}/accept-invitation/${autoInvite.invitationId}?email=${encodeURIComponent(autoInvite.email)}&returnUrl=${encodeURIComponent(linkReturnUrl)}` : `${manageUiUrl}/login?invitation=${encodeURIComponent(autoInvite.invitationId)}&returnUrl=${encodeURIComponent(linkReturnUrl)}&email=${encodeURIComponent(autoInvite.email)}&authMethod=${encodeURIComponent(authMethod)}`;
|
|
32
|
+
logger.info({
|
|
33
|
+
invitationId: autoInvite.invitationId,
|
|
34
|
+
email: autoInvite.email,
|
|
35
|
+
hasIntent: !!intent
|
|
36
|
+
}, "Directing unlinked user to accept-invitation page");
|
|
37
|
+
return {
|
|
38
|
+
type: "auto_invite",
|
|
39
|
+
url: acceptUrl,
|
|
40
|
+
email: autoInvite.email,
|
|
41
|
+
expiresInMinutes: LINK_CODE_TTL_MINUTES
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const linkToken = await signSlackLinkToken({
|
|
45
|
+
tenantId,
|
|
46
|
+
slackTeamId: teamId,
|
|
47
|
+
slackUserId,
|
|
48
|
+
slackEnterpriseId,
|
|
49
|
+
slackUsername,
|
|
50
|
+
intent
|
|
51
|
+
});
|
|
52
|
+
const linkUrl = `${manageUiUrl}/link?token=${encodeURIComponent(linkToken)}`;
|
|
53
|
+
logger.info({
|
|
54
|
+
slackUserId,
|
|
55
|
+
tenantId,
|
|
56
|
+
hasIntent: !!intent
|
|
57
|
+
}, "Generated JWT link token for unlinked user");
|
|
58
|
+
return {
|
|
59
|
+
type: "jwt_link",
|
|
60
|
+
url: linkUrl,
|
|
61
|
+
expiresInMinutes: LINK_CODE_TTL_MINUTES
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function buildLinkPromptMessage(result) {
|
|
65
|
+
if (result.type === "auto_invite") return createCreateInkeepAccountMessage(result.url, result.expiresInMinutes);
|
|
66
|
+
return createSmartLinkMessage(result.url);
|
|
67
|
+
}
|
|
68
|
+
async function tryAutoInvite(params) {
|
|
69
|
+
const { tenantId, teamId, slackUserId, botToken } = params;
|
|
70
|
+
if (!botToken) return null;
|
|
71
|
+
try {
|
|
72
|
+
if (!(await findWorkAppSlackWorkspaceByTeamId(runDbClient_default)(tenantId, teamId))?.shouldAllowJoinFromWorkspace) {
|
|
73
|
+
logger.warn({
|
|
74
|
+
userId: slackUserId,
|
|
75
|
+
tenantId,
|
|
76
|
+
teamId
|
|
77
|
+
}, "Workspace should not allow join from workspace");
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const slackClient = getSlackClient(botToken);
|
|
81
|
+
let userEmail;
|
|
82
|
+
try {
|
|
83
|
+
userEmail = (await slackClient.users.info({ user: slackUserId })).user?.profile?.email;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
logger.warn({
|
|
86
|
+
error,
|
|
87
|
+
userId: slackUserId
|
|
88
|
+
}, "Failed to get user info from Slack");
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if (!userEmail) {
|
|
92
|
+
logger.warn({ userId: slackUserId }, "No email found in Slack user profile");
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
if (await getOrganizationMemberByEmail(runDbClient_default)(tenantId, userEmail)) {
|
|
96
|
+
logger.debug({
|
|
97
|
+
userId: slackUserId,
|
|
98
|
+
email: userEmail
|
|
99
|
+
}, "User already has Inkeep account, skipping auto-invite");
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const existingInvitation = (await getPendingInvitationsByEmail(runDbClient_default)(userEmail)).find((inv) => inv.organizationId === tenantId);
|
|
103
|
+
if (existingInvitation) {
|
|
104
|
+
logger.info({
|
|
105
|
+
userId: slackUserId,
|
|
106
|
+
tenantId,
|
|
107
|
+
invitationId: existingInvitation.id,
|
|
108
|
+
email: userEmail
|
|
109
|
+
}, "Reusing existing pending invitation for Slack user");
|
|
110
|
+
return {
|
|
111
|
+
invitationId: existingInvitation.id,
|
|
112
|
+
email: userEmail,
|
|
113
|
+
authMethod: existingInvitation.authMethod ?? "email-password"
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const invitation = await createInvitationInDb(runDbClient_default)({
|
|
117
|
+
organizationId: tenantId,
|
|
118
|
+
email: userEmail
|
|
119
|
+
});
|
|
120
|
+
logger.info({
|
|
121
|
+
userId: slackUserId,
|
|
122
|
+
tenantId,
|
|
123
|
+
invitationId: invitation.id,
|
|
124
|
+
email: userEmail
|
|
125
|
+
}, "Invitation created for Slack user without Inkeep account");
|
|
126
|
+
return {
|
|
127
|
+
invitationId: invitation.id,
|
|
128
|
+
email: userEmail,
|
|
129
|
+
authMethod: invitation.authMethod
|
|
130
|
+
};
|
|
131
|
+
} catch (error) {
|
|
132
|
+
logger.warn({
|
|
133
|
+
error,
|
|
134
|
+
userId: slackUserId,
|
|
135
|
+
tenantId
|
|
136
|
+
}, "Auto-invite attempt failed");
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
export { buildLinkPromptMessage, resolveUnlinkedUserAction };
|
|
@@ -29,12 +29,13 @@ function buildAgentSelectorModal(params) {
|
|
|
29
29
|
const agentOptions = agents.length > 0 ? agents.map((agent) => ({
|
|
30
30
|
text: {
|
|
31
31
|
type: "plain_text",
|
|
32
|
-
text: agent.name
|
|
32
|
+
text: agent.name ? `${agent.name} (${agent.id})` : agent.id,
|
|
33
33
|
emoji: true
|
|
34
34
|
},
|
|
35
35
|
value: JSON.stringify({
|
|
36
36
|
agentId: agent.id,
|
|
37
|
-
projectId: agent.projectId
|
|
37
|
+
projectId: agent.projectId,
|
|
38
|
+
agentName: agent.name
|
|
38
39
|
})
|
|
39
40
|
})) : [{
|
|
40
41
|
text: {
|
|
@@ -234,12 +235,13 @@ function buildMessageShortcutModal(params) {
|
|
|
234
235
|
const agentOptions = agents.length > 0 ? agents.map((agent) => ({
|
|
235
236
|
text: {
|
|
236
237
|
type: "plain_text",
|
|
237
|
-
text: agent.name
|
|
238
|
+
text: agent.name ? `${agent.name} (${agent.id})` : agent.id,
|
|
238
239
|
emoji: true
|
|
239
240
|
},
|
|
240
241
|
value: JSON.stringify({
|
|
241
242
|
agentId: agent.id,
|
|
242
|
-
projectId: agent.projectId
|
|
243
|
+
projectId: agent.projectId,
|
|
244
|
+
agentName: agent.name
|
|
243
245
|
})
|
|
244
246
|
})) : [{
|
|
245
247
|
text: {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SlackLinkIntent } from "@inkeep/agents-core";
|
|
2
|
+
|
|
3
|
+
//#region src/slack/services/resume-intent.d.ts
|
|
4
|
+
interface ResumeSmartLinkIntentParams {
|
|
5
|
+
intent: SlackLinkIntent;
|
|
6
|
+
teamId: string;
|
|
7
|
+
slackUserId: string;
|
|
8
|
+
inkeepUserId: string;
|
|
9
|
+
tenantId: string;
|
|
10
|
+
slackEnterpriseId?: string;
|
|
11
|
+
slackUsername?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function resumeSmartLinkIntent(params: ResumeSmartLinkIntentParams): Promise<void>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { ResumeSmartLinkIntentParams, resumeSmartLinkIntent };
|