@inkeep/agents-work-apps 0.51.0 → 0.53.0

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.
@@ -1,9 +1,9 @@
1
1
  import { env } from "../../../env.js";
2
2
  import { getLogger } from "../../../logger.js";
3
- import { buildToolApprovalBlocks, buildToolApprovalExpiredBlocks, createContextBlock } from "../blocks/index.js";
4
3
  import { SlackErrorType, classifyError, extractApiErrorMessage, getUserFriendlyErrorMessage } from "./utils.js";
4
+ import { buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, createContextBlock } from "../blocks/index.js";
5
5
  import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
6
- import { getInProcessFetch } from "@inkeep/agents-core";
6
+ import { getInProcessFetch, retryWithBackoff } from "@inkeep/agents-core";
7
7
 
8
8
  //#region src/slack/services/events/streaming.ts
9
9
  /**
@@ -192,6 +192,14 @@ async function streamAgentResponse(params) {
192
192
  thread_ts: threadTs
193
193
  });
194
194
  const pendingApprovalMessages = [];
195
+ const toolCallIdToName = /* @__PURE__ */ new Map();
196
+ const toolCallIdToInput = /* @__PURE__ */ new Map();
197
+ const toolErrors = [];
198
+ const citations = [];
199
+ const summaryLabels = [];
200
+ let richMessageCount = 0;
201
+ let richMessageCapWarned = false;
202
+ const MAX_RICH_MESSAGES = 20;
195
203
  try {
196
204
  let agentCompleted = false;
197
205
  while (true) {
@@ -214,9 +222,9 @@ async function streamAgentResponse(params) {
214
222
  continue;
215
223
  }
216
224
  if (data.type === "tool-approval-request" && conversationId) {
217
- const toolName = data.toolName || "Tool";
218
225
  const toolCallId = data.toolCallId;
219
- const input = data.input;
226
+ const toolName = toolCallIdToName.get(toolCallId) || "Tool";
227
+ const input = toolCallIdToInput.get(toolCallId);
220
228
  const buttonValue = {
221
229
  toolCallId,
222
230
  conversationId,
@@ -245,11 +253,118 @@ async function streamAgentResponse(params) {
245
253
  });
246
254
  if (approvalPost?.ts) pendingApprovalMessages.push({
247
255
  messageTs: approvalPost.ts,
248
- toolName
256
+ toolName,
257
+ toolCallId
249
258
  });
250
259
  clearTimeout(timeoutId);
251
260
  continue;
252
261
  }
262
+ if (data.type === "tool-input-available" && data.toolCallId && data.toolName) {
263
+ toolCallIdToName.set(String(data.toolCallId), String(data.toolName));
264
+ if (data.input && typeof data.input === "object") toolCallIdToInput.set(String(data.toolCallId), data.input);
265
+ continue;
266
+ }
267
+ if (data.type === "tool-output-denied" && data.toolCallId) {
268
+ const idx = pendingApprovalMessages.findIndex((m) => m.toolCallId === data.toolCallId);
269
+ if (idx !== -1) pendingApprovalMessages.splice(idx, 1);
270
+ continue;
271
+ }
272
+ if (data.type === "tool-output-error" && data.toolCallId) {
273
+ const toolName = toolCallIdToName.get(String(data.toolCallId)) || "Tool";
274
+ toolErrors.push({
275
+ toolName,
276
+ errorText: String(data.errorText || "Unknown error")
277
+ });
278
+ continue;
279
+ }
280
+ if (data.type === "data-component" && data.data && typeof data.data === "object") {
281
+ if (richMessageCount < MAX_RICH_MESSAGES) {
282
+ const { blocks, overflowJson, componentType } = buildDataComponentBlocks({
283
+ id: String(data.id || ""),
284
+ data: data.data
285
+ });
286
+ if (overflowJson) {
287
+ const label = componentType || "data-component";
288
+ await retryWithBackoff(() => slackClient.files.uploadV2({
289
+ channel_id: channel,
290
+ thread_ts: threadTs,
291
+ filename: `${label}.json`,
292
+ content: overflowJson,
293
+ initial_comment: `📊 ${label}`
294
+ }), { label: "slack-file-upload" }).catch((e) => logger.warn({
295
+ error: e,
296
+ channel,
297
+ threadTs,
298
+ agentId,
299
+ componentType: label
300
+ }, "Failed to upload data component file"));
301
+ } else await slackClient.chat.postMessage({
302
+ channel,
303
+ thread_ts: threadTs,
304
+ text: "📊 Data component",
305
+ blocks
306
+ }).catch((e) => logger.warn({ error: e }, "Failed to post data component"));
307
+ richMessageCount++;
308
+ } else if (!richMessageCapWarned) {
309
+ logger.warn({
310
+ channel,
311
+ threadTs,
312
+ agentId,
313
+ eventType: "data-component",
314
+ MAX_RICH_MESSAGES
315
+ }, "MAX_RICH_MESSAGES cap reached — additional rich content will be dropped");
316
+ richMessageCapWarned = true;
317
+ }
318
+ continue;
319
+ }
320
+ if (data.type === "data-artifact" && data.data && typeof data.data === "object") {
321
+ const artifactData = data.data;
322
+ if (typeof artifactData.type === "string" && artifactData.type.toLowerCase() === "citation") {
323
+ const summary = artifactData.artifactSummary;
324
+ if (summary?.url && !citations.some((c) => c.url === summary.url)) citations.push({
325
+ title: summary.title,
326
+ url: summary.url
327
+ });
328
+ } else if (richMessageCount < MAX_RICH_MESSAGES) {
329
+ const { blocks, overflowContent, artifactName } = buildDataArtifactBlocks({ data: artifactData });
330
+ if (overflowContent) {
331
+ const label = artifactName || "artifact";
332
+ await retryWithBackoff(() => slackClient.files.uploadV2({
333
+ channel_id: channel,
334
+ thread_ts: threadTs,
335
+ filename: `${label}.md`,
336
+ content: overflowContent,
337
+ initial_comment: `📄 ${label}`
338
+ }), { label: "slack-file-upload" }).catch((e) => logger.warn({
339
+ error: e,
340
+ channel,
341
+ threadTs,
342
+ agentId,
343
+ artifactName: label
344
+ }, "Failed to upload artifact file"));
345
+ } else await slackClient.chat.postMessage({
346
+ channel,
347
+ thread_ts: threadTs,
348
+ text: "📄 Data",
349
+ blocks
350
+ }).catch((e) => logger.warn({ error: e }, "Failed to post data artifact"));
351
+ richMessageCount++;
352
+ } else if (!richMessageCapWarned) {
353
+ logger.warn({
354
+ channel,
355
+ threadTs,
356
+ agentId,
357
+ eventType: "data-artifact",
358
+ MAX_RICH_MESSAGES
359
+ }, "MAX_RICH_MESSAGES cap reached — additional rich content will be dropped");
360
+ richMessageCapWarned = true;
361
+ }
362
+ continue;
363
+ }
364
+ if (data.type === "data-summary" && data.data?.label) {
365
+ summaryLabels.push(String(data.data.label));
366
+ continue;
367
+ }
253
368
  if (data.type === "text-start" || data.type === "text-end") continue;
254
369
  if (data.type === "text-delta" && data.delta) {
255
370
  fullText += data.delta;
@@ -267,9 +382,16 @@ async function streamAgentResponse(params) {
267
382
  if (agentCompleted) break;
268
383
  }
269
384
  clearTimeout(timeoutId);
270
- const contextBlock = createContextBlock({ agentName });
385
+ const stopBlocks = [];
386
+ for (const { toolName, errorText } of toolErrors) stopBlocks.push(buildToolOutputErrorBlock(toolName, errorText));
387
+ if (summaryLabels.length > 0) stopBlocks.push(buildSummaryBreadcrumbBlock(summaryLabels));
388
+ if (citations.length > 0) {
389
+ const citationBlocks = buildCitationsBlock(citations);
390
+ stopBlocks.push(...citationBlocks);
391
+ }
392
+ stopBlocks.push(createContextBlock({ agentName }));
271
393
  try {
272
- await withTimeout(streamer.stop({ blocks: [contextBlock] }), CHATSTREAM_OP_TIMEOUT_MS, "streamer.stop");
394
+ await withTimeout(streamer.stop({ blocks: stopBlocks.slice(0, 50) }), CHATSTREAM_OP_TIMEOUT_MS, "streamer.stop");
273
395
  } catch (stopError) {
274
396
  span.setAttribute(SLACK_SPAN_KEYS.STREAM_FINALIZATION_FAILED, true);
275
397
  logger.warn({
@@ -292,7 +414,10 @@ async function streamAgentResponse(params) {
292
414
  threadTs,
293
415
  responseLength: fullText.length,
294
416
  agentId,
295
- conversationId
417
+ conversationId,
418
+ toolErrorCount: toolErrors.length,
419
+ citationCount: citations.length,
420
+ richMessageCount
296
421
  }, "Streaming completed");
297
422
  span.end();
298
423
  return { success: true };
@@ -11,9 +11,9 @@ declare function findCachedUserMapping(tenantId: string, slackUserId: string, te
11
11
  id: string;
12
12
  createdAt: string;
13
13
  updatedAt: string;
14
- slackUserId: string;
15
14
  tenantId: string;
16
15
  clientId: string;
16
+ slackUserId: string;
17
17
  slackTeamId: string;
18
18
  slackEnterpriseId: string | null;
19
19
  inkeepUserId: string;
@@ -137,8 +137,10 @@ declare function getThreadContext(slackClient: {
137
137
  }) => Promise<{
138
138
  user?: {
139
139
  real_name?: string;
140
- display_name?: string;
141
- name?: string;
140
+ profile?: {
141
+ display_name?: string;
142
+ email?: string;
143
+ };
142
144
  };
143
145
  }>;
144
146
  };
@@ -347,15 +347,15 @@ async function getThreadContext(slackClient, channel, threadTs, options = {}) {
347
347
  try {
348
348
  const userInfo = await slackClient.users?.info({ user: userId });
349
349
  userNameCache.set(userId, {
350
- displayName: userInfo?.user?.display_name,
350
+ displayName: userInfo?.user?.profile?.display_name,
351
351
  fullName: userInfo?.user?.real_name,
352
- name: userInfo?.user?.name
352
+ email: userInfo?.user?.profile?.email
353
353
  });
354
354
  } catch {
355
355
  userNameCache.set(userId, {
356
356
  displayName: void 0,
357
357
  fullName: void 0,
358
- name: void 0
358
+ email: void 0
359
359
  });
360
360
  }
361
361
  }));
@@ -365,10 +365,10 @@ async function getThreadContext(slackClient, channel, threadTs, options = {}) {
365
365
  const parts = [`userId: ${userId}`];
366
366
  if (info.displayName) parts.push(`"${info.displayName}"`);
367
367
  if (info.fullName) parts.push(`"${info.fullName}"`);
368
- if (info.name) parts.push(`"${info.name}"`);
368
+ if (info.email) parts.push(info.email);
369
369
  userDirectoryLines.push(`- ${parts.join(", ")}`);
370
370
  }
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) => {
371
+ 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
372
  const isBot = !!msg.bot_id;
373
373
  const isParent = index === 0;
374
374
  let role;
@@ -1,5 +1,5 @@
1
1
  import { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
2
- import { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, 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, createJwtLinkMessage, createNotLinkedMessage, 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";
@@ -13,4 +13,4 @@ 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, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, 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, 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 };
@@ -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, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, 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, createJwtLinkMessage, createNotLinkedMessage, 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, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, 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, 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 };
@@ -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: {
@@ -2,7 +2,7 @@ import { env } from "../../env.js";
2
2
  import { getLogger } from "../../logger.js";
3
3
  import runDbClient_default from "../../db/runDbClient.js";
4
4
  import { getDevDefaultAgent, isSlackDevMode, loadSlackDevConfig, saveSlackDevConfig } from "./dev-config.js";
5
- import { findWorkAppSlackWorkspaceBySlackTeamId } from "@inkeep/agents-core";
5
+ import { findWorkAppSlackWorkspaceBySlackTeamId, retryWithBackoff } from "@inkeep/agents-core";
6
6
  import { Nango } from "@nangohq/node";
7
7
 
8
8
  //#region src/slack/services/nango.ts
@@ -30,28 +30,6 @@ const workspaceConnectionCache = /* @__PURE__ */ new Map();
30
30
  const CACHE_TTL_MS = 6e4;
31
31
  const logger = getLogger("slack-nango");
32
32
  /**
33
- * Retry a function with exponential backoff for transient failures.
34
- * Retries on AbortError (timeout) and 5xx HTTP errors.
35
- */
36
- async function retryWithBackoff(fn, maxAttempts = 3) {
37
- for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
38
- return await fn();
39
- } catch (error) {
40
- const isTimeout = error.name === "AbortError";
41
- const isServerError = typeof error.status === "number" && error.status >= 500;
42
- if (!(isTimeout || isServerError) || attempt === maxAttempts) throw error;
43
- const delay = Math.min(500 * 2 ** (attempt - 1), 2e3) + Math.random() * 100;
44
- logger.warn({
45
- attempt,
46
- maxAttempts,
47
- isTimeout,
48
- delay: Math.round(delay)
49
- }, "Retrying Nango API call after transient failure");
50
- await new Promise((resolve) => setTimeout(resolve, delay));
51
- }
52
- throw new Error("Unreachable");
53
- }
54
- /**
55
33
  * Evict expired entries from workspace cache to bound memory.
56
34
  */
57
35
  function evictWorkspaceCache() {
@@ -40,6 +40,6 @@ declare const SLACK_SPAN_KEYS: {
40
40
  readonly AUTHORIZED: "slack.authorized";
41
41
  readonly AUTH_SOURCE: "slack.auth_source";
42
42
  };
43
- type SlackOutcome = 'handled' | 'ignored_bot_message' | 'ignored_unknown_event' | 'ignored_no_action_match' | 'ignored_slack_retry' | 'url_verification' | 'validation_error' | 'signature_invalid' | 'error';
43
+ type SlackOutcome = 'handled' | 'ignored_bot_message' | 'ignored_edited_message' | 'ignored_unknown_event' | 'ignored_no_action_match' | 'ignored_slack_retry' | 'url_verification' | 'validation_error' | 'signature_invalid' | 'error';
44
44
  //#endregion
45
45
  export { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, SlackOutcome, setSpanWithError, tracer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-work-apps",
3
- "version": "0.51.0",
3
+ "version": "0.53.0",
4
4
  "description": "First party integrations for Inkeep Agents",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -33,7 +33,7 @@
33
33
  "jose": "^6.1.0",
34
34
  "minimatch": "^10.1.1",
35
35
  "slack-block-builder": "^2.8.0",
36
- "@inkeep/agents-core": "0.51.0"
36
+ "@inkeep/agents-core": "0.53.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@hono/zod-openapi": "^1.1.5",