@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.
Files changed (37) hide show
  1. package/dist/env.d.ts +2 -2
  2. package/dist/github/mcp/auth.d.ts +2 -2
  3. package/dist/github/mcp/index.d.ts +2 -2
  4. package/dist/github/mcp/index.js +63 -26
  5. package/dist/github/mcp/schemas.d.ts +1 -1
  6. package/dist/github/mcp/utils.d.ts +2 -1
  7. package/dist/github/mcp/utils.js +16 -1
  8. package/dist/github/routes/setup.d.ts +2 -2
  9. package/dist/github/routes/tokenExchange.d.ts +2 -2
  10. package/dist/github/routes/webhooks.d.ts +2 -2
  11. package/dist/slack/dispatcher.js +11 -1
  12. package/dist/slack/routes/oauth.js +21 -1
  13. package/dist/slack/routes/users.js +29 -3
  14. package/dist/slack/services/agent-resolution.d.ts +1 -0
  15. package/dist/slack/services/agent-resolution.js +105 -18
  16. package/dist/slack/services/blocks/index.d.ts +9 -2
  17. package/dist/slack/services/blocks/index.js +27 -11
  18. package/dist/slack/services/commands/index.d.ts +1 -1
  19. package/dist/slack/services/commands/index.js +34 -124
  20. package/dist/slack/services/events/app-mention.d.ts +4 -14
  21. package/dist/slack/services/events/app-mention.js +40 -19
  22. package/dist/slack/services/events/block-actions.js +1 -1
  23. package/dist/slack/services/events/index.d.ts +1 -1
  24. package/dist/slack/services/events/modal-submission.js +14 -7
  25. package/dist/slack/services/events/streaming.js +9 -12
  26. package/dist/slack/services/events/utils.d.ts +26 -5
  27. package/dist/slack/services/events/utils.js +40 -15
  28. package/dist/slack/services/index.d.ts +4 -4
  29. package/dist/slack/services/index.js +3 -3
  30. package/dist/slack/services/link-prompt.d.ts +27 -0
  31. package/dist/slack/services/link-prompt.js +142 -0
  32. package/dist/slack/services/modals.d.ts +1 -0
  33. package/dist/slack/services/modals.js +6 -4
  34. package/dist/slack/services/resume-intent.d.ts +15 -0
  35. package/dist/slack/services/resume-intent.js +338 -0
  36. package/dist/slack/tracer.d.ts +1 -1
  37. 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
- slackUserId: string;
11
+ id: string;
12
12
  createdAt: string;
13
13
  updatedAt: string;
14
- id: string;
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
- display_name?: string;
141
- name?: string;
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 (userMappingCache.size >= USER_MAPPING_CACHE_MAX_SIZE) {
38
- evictExpiredEntries();
37
+ if (mapping) {
39
38
  if (userMappingCache.size >= USER_MAPPING_CACHE_MAX_SIZE) {
40
- const oldestKey = userMappingCache.keys().next().value;
41
- if (oldestKey) userMappingCache.delete(oldestKey);
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
- name: userInfo?.user?.name
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
- name: void 0
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.name) parts.push(`"${info.name}"`);
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, Name):\n${userDirectoryLines.join("\n")}\n\n` : ""}Messages in this thread:\n${messagesToProcess.map((msg, index) => {
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
- return `${prefix}${role}: """${messageText}"""`;
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, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
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, createJwtLinkMessage, createNotLinkedMessage, 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 };
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, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
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, createJwtLinkMessage, createNotLinkedMessage, 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 };
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 };
@@ -24,6 +24,7 @@ interface ModalMetadata {
24
24
  interface FollowUpModalMetadata {
25
25
  conversationId: string;
26
26
  agentId: string;
27
+ agentName?: string;
27
28
  projectId: string;
28
29
  tenantId: string;
29
30
  teamId: string;
@@ -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 || agent.id,
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 || agent.id,
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 };