@inkeep/agents-work-apps 0.53.2 → 0.53.3
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/github/mcp/index.d.ts +2 -2
- 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 +54 -40
- package/dist/slack/i18n/strings.d.ts +6 -5
- package/dist/slack/i18n/strings.js +7 -10
- package/dist/slack/routes/events.js +1 -1
- package/dist/slack/services/blocks/index.d.ts +3 -35
- package/dist/slack/services/blocks/index.js +5 -42
- package/dist/slack/services/commands/index.js +42 -104
- package/dist/slack/services/events/app-mention.js +8 -31
- package/dist/slack/services/events/block-actions.d.ts +1 -11
- package/dist/slack/services/events/block-actions.js +6 -49
- package/dist/slack/services/events/direct-message.d.ts +11 -0
- package/dist/slack/services/events/direct-message.js +148 -0
- package/dist/slack/services/events/execution.d.ts +20 -0
- package/dist/slack/services/events/execution.js +46 -0
- package/dist/slack/services/events/index.d.ts +5 -3
- package/dist/slack/services/events/index.js +5 -3
- package/dist/slack/services/events/modal-submission.d.ts +1 -21
- package/dist/slack/services/events/modal-submission.js +14 -294
- package/dist/slack/services/events/streaming.d.ts +1 -1
- package/dist/slack/services/events/streaming.js +69 -70
- package/dist/slack/services/events/utils.d.ts +2 -14
- package/dist/slack/services/events/utils.js +2 -13
- package/dist/slack/services/index.d.ts +7 -5
- package/dist/slack/services/index.js +8 -6
- package/dist/slack/services/modals.d.ts +1 -18
- package/dist/slack/services/modals.js +1 -48
- package/dist/slack/services/resume-intent.js +43 -3
- package/dist/slack/socket-mode.js +1 -1
- package/dist/slack/tracer.d.ts +2 -4
- package/dist/slack/tracer.js +1 -3
- package/package.json +2 -2
|
@@ -5,9 +5,9 @@ import { checkIfBotThread, classifyError, findCachedUserMapping, formatAttachmen
|
|
|
5
5
|
import { resolveEffectiveAgent } from "../agent-resolution.js";
|
|
6
6
|
import { SlackStrings } from "../../i18n/strings.js";
|
|
7
7
|
import { getSlackChannelInfo, getSlackClient, getSlackUserInfo, postMessageInThread } from "../client.js";
|
|
8
|
-
import { buildLinkPromptMessage, resolveUnlinkedUserAction } from "../link-prompt.js";
|
|
9
8
|
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
10
|
-
import {
|
|
9
|
+
import { executeAgentPublicly } from "./execution.js";
|
|
10
|
+
import { buildLinkPromptMessage, resolveUnlinkedUserAction } from "../link-prompt.js";
|
|
11
11
|
import { signSlackUserToken } from "@inkeep/agents-core";
|
|
12
12
|
|
|
13
13
|
//#region src/slack/services/events/app-mention.ts
|
|
@@ -72,7 +72,6 @@ async function handleAppMention(params) {
|
|
|
72
72
|
const replyThreadTs = threadTs || messageTs;
|
|
73
73
|
const isInThread = Boolean(threadTs && threadTs !== messageTs);
|
|
74
74
|
const hasQuery = Boolean(text && text.trim().length > 0);
|
|
75
|
-
let thinkingMessageTs;
|
|
76
75
|
try {
|
|
77
76
|
const { result: [agentConfig, existingLink] } = await timedOp(Promise.all([resolveEffectiveAgent({
|
|
78
77
|
tenantId,
|
|
@@ -205,16 +204,9 @@ async function handleAppMention(params) {
|
|
|
205
204
|
slackChannelId: channel,
|
|
206
205
|
slackAuthorizedProjectId: agentConfig?.projectId
|
|
207
206
|
});
|
|
208
|
-
thinkingMessageTs = (await slackClient.chat.postMessage({
|
|
209
|
-
channel,
|
|
210
|
-
thread_ts: threadTs,
|
|
211
|
-
text: SlackStrings.status.readingThread(agentDisplayName)
|
|
212
|
-
})).ts || void 0;
|
|
213
207
|
const conversationId$1 = generateSlackConversationId({
|
|
214
208
|
teamId,
|
|
215
|
-
|
|
216
|
-
channel,
|
|
217
|
-
isDM: false,
|
|
209
|
+
messageTs,
|
|
218
210
|
agentId: agentConfig.agentId
|
|
219
211
|
});
|
|
220
212
|
span.setAttribute(SLACK_SPAN_KEYS.CONVERSATION_ID, conversationId$1);
|
|
@@ -235,18 +227,17 @@ Respond naturally as if you're joining the conversation to help.`;
|
|
|
235
227
|
agentId: agentConfig.agentId,
|
|
236
228
|
conversationId: conversationId$1
|
|
237
229
|
}, "Auto-executing agent with thread context");
|
|
238
|
-
await
|
|
230
|
+
await executeAgentPublicly({
|
|
239
231
|
slackClient,
|
|
240
232
|
channel,
|
|
241
233
|
threadTs,
|
|
242
|
-
thinkingMessageTs: thinkingMessageTs || "",
|
|
243
234
|
slackUserId,
|
|
244
235
|
teamId,
|
|
245
236
|
jwtToken: slackUserToken$1,
|
|
246
237
|
projectId: agentConfig.projectId,
|
|
247
238
|
agentId: agentConfig.agentId,
|
|
248
|
-
question: threadQuery,
|
|
249
239
|
agentName: agentDisplayName,
|
|
240
|
+
question: threadQuery,
|
|
250
241
|
conversationId: conversationId$1
|
|
251
242
|
});
|
|
252
243
|
span.end();
|
|
@@ -292,16 +283,9 @@ Respond naturally as if you're joining the conversation to help.`;
|
|
|
292
283
|
slackChannelId: channel,
|
|
293
284
|
slackAuthorizedProjectId: agentConfig?.projectId
|
|
294
285
|
});
|
|
295
|
-
thinkingMessageTs = (await slackClient.chat.postMessage({
|
|
296
|
-
channel,
|
|
297
|
-
thread_ts: replyThreadTs,
|
|
298
|
-
text: SlackStrings.status.thinking(agentDisplayName)
|
|
299
|
-
})).ts || void 0;
|
|
300
286
|
const conversationId = generateSlackConversationId({
|
|
301
287
|
teamId,
|
|
302
|
-
|
|
303
|
-
channel,
|
|
304
|
-
isDM: false,
|
|
288
|
+
messageTs,
|
|
305
289
|
agentId: agentConfig.agentId
|
|
306
290
|
});
|
|
307
291
|
span.setAttribute(SLACK_SPAN_KEYS.CONVERSATION_ID, conversationId);
|
|
@@ -313,18 +297,17 @@ Respond naturally as if you're joining the conversation to help.`;
|
|
|
313
297
|
totalPreExecMs,
|
|
314
298
|
dispatchDelayMs
|
|
315
299
|
}, "Executing agent");
|
|
316
|
-
await
|
|
300
|
+
await executeAgentPublicly({
|
|
317
301
|
slackClient,
|
|
318
302
|
channel,
|
|
319
303
|
threadTs: replyThreadTs,
|
|
320
|
-
thinkingMessageTs: thinkingMessageTs || "",
|
|
321
304
|
slackUserId,
|
|
322
305
|
teamId,
|
|
323
306
|
jwtToken: slackUserToken,
|
|
324
307
|
projectId: agentConfig.projectId,
|
|
325
308
|
agentId: agentConfig.agentId,
|
|
326
|
-
question: queryText,
|
|
327
309
|
agentName: agentDisplayName,
|
|
310
|
+
question: queryText,
|
|
328
311
|
conversationId
|
|
329
312
|
});
|
|
330
313
|
span.end();
|
|
@@ -336,12 +319,6 @@ Respond naturally as if you're joining the conversation to help.`;
|
|
|
336
319
|
teamId
|
|
337
320
|
}, "Failed in app mention handler");
|
|
338
321
|
if (error instanceof Error) setSpanWithError(span, error);
|
|
339
|
-
if (thinkingMessageTs) try {
|
|
340
|
-
await slackClient.chat.delete({
|
|
341
|
-
channel,
|
|
342
|
-
ts: thinkingMessageTs
|
|
343
|
-
});
|
|
344
|
-
} catch {}
|
|
345
322
|
const userMessage = getUserFriendlyErrorMessage(classifyError(error));
|
|
346
323
|
try {
|
|
347
324
|
await slackClient.chat.postEphemeral({
|
|
@@ -23,16 +23,6 @@ declare function handleOpenAgentSelectorModal(params: {
|
|
|
23
23
|
teamId: string;
|
|
24
24
|
responseUrl: string;
|
|
25
25
|
}): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Handle "Follow Up" button click.
|
|
28
|
-
* Opens a prompt-only modal that carries the conversationId for multi-turn context.
|
|
29
|
-
*/
|
|
30
|
-
declare function handleOpenFollowUpModal(params: {
|
|
31
|
-
triggerId: string;
|
|
32
|
-
actionValue: string;
|
|
33
|
-
teamId: string;
|
|
34
|
-
responseUrl?: string;
|
|
35
|
-
}): Promise<void>;
|
|
36
26
|
/**
|
|
37
27
|
* Handle message shortcut (context menu action on a message)
|
|
38
28
|
* Opens a modal with the message content pre-filled as context
|
|
@@ -48,4 +38,4 @@ declare function handleMessageShortcut(params: {
|
|
|
48
38
|
responseUrl?: string;
|
|
49
39
|
}): Promise<void>;
|
|
50
40
|
//#endregion
|
|
51
|
-
export { handleMessageShortcut, handleOpenAgentSelectorModal,
|
|
41
|
+
export { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval };
|
|
@@ -5,8 +5,8 @@ import { fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, g
|
|
|
5
5
|
import { SlackStrings } from "../../i18n/strings.js";
|
|
6
6
|
import { ToolApprovalButtonValueSchema, buildToolApprovalDoneBlocks } from "../blocks/index.js";
|
|
7
7
|
import { getSlackClient } from "../client.js";
|
|
8
|
-
import { buildAgentSelectorModal, buildFollowUpModal, buildMessageShortcutModal } from "../modals.js";
|
|
9
8
|
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
9
|
+
import { buildAgentSelectorModal, buildMessageShortcutModal } from "../modals.js";
|
|
10
10
|
import { getInProcessFetch, signSlackUserToken } from "@inkeep/agents-core";
|
|
11
11
|
|
|
12
12
|
//#region src/slack/services/events/block-actions.ts
|
|
@@ -36,11 +36,12 @@ async function handleToolApproval(params) {
|
|
|
36
36
|
}
|
|
37
37
|
const tenantId = workspaceConnection.tenantId;
|
|
38
38
|
const slackClient = getSlackClient(workspaceConnection.botToken);
|
|
39
|
+
const approvalThreadParam = buttonValue.threadTs ? { thread_ts: buttonValue.threadTs } : {};
|
|
39
40
|
if (slackUserId !== buttonValue.slackUserId) {
|
|
40
41
|
await slackClient.chat.postEphemeral({
|
|
41
42
|
channel: buttonValue.channel,
|
|
42
43
|
user: slackUserId,
|
|
43
|
-
|
|
44
|
+
...approvalThreadParam,
|
|
44
45
|
text: "Only the user who started this conversation can approve or deny this action."
|
|
45
46
|
}).catch((e) => logger.warn({ error: e }, "Failed to send ownership error notification"));
|
|
46
47
|
span.end();
|
|
@@ -51,7 +52,7 @@ async function handleToolApproval(params) {
|
|
|
51
52
|
await slackClient.chat.postEphemeral({
|
|
52
53
|
channel: buttonValue.channel,
|
|
53
54
|
user: slackUserId,
|
|
54
|
-
|
|
55
|
+
...approvalThreadParam,
|
|
55
56
|
text: "You need to link your Inkeep account first. Use `/inkeep link`."
|
|
56
57
|
}).catch((e) => logger.warn({ error: e }, "Failed to send not-linked notification"));
|
|
57
58
|
span.end();
|
|
@@ -99,7 +100,7 @@ async function handleToolApproval(params) {
|
|
|
99
100
|
await slackClient.chat.postEphemeral({
|
|
100
101
|
channel: buttonValue.channel,
|
|
101
102
|
user: slackUserId,
|
|
102
|
-
|
|
103
|
+
...approvalThreadParam,
|
|
103
104
|
text: `Failed to ${approved ? "approve" : "deny"} \`${toolName}\`. Please try again.`
|
|
104
105
|
}).catch((e) => logger.warn({ error: e }, "Failed to send approval error notification"));
|
|
105
106
|
span.end();
|
|
@@ -238,50 +239,6 @@ async function handleOpenAgentSelectorModal(params) {
|
|
|
238
239
|
});
|
|
239
240
|
}
|
|
240
241
|
/**
|
|
241
|
-
* Handle "Follow Up" button click.
|
|
242
|
-
* Opens a prompt-only modal that carries the conversationId for multi-turn context.
|
|
243
|
-
*/
|
|
244
|
-
async function handleOpenFollowUpModal(params) {
|
|
245
|
-
return tracer.startActiveSpan(SLACK_SPAN_NAMES.OPEN_FOLLOW_UP_MODAL, async (span) => {
|
|
246
|
-
const { triggerId, actionValue, teamId, responseUrl } = params;
|
|
247
|
-
span.setAttribute(SLACK_SPAN_KEYS.TEAM_ID, teamId);
|
|
248
|
-
try {
|
|
249
|
-
const metadata = JSON.parse(actionValue);
|
|
250
|
-
span.setAttribute(SLACK_SPAN_KEYS.CONVERSATION_ID, metadata.conversationId || "");
|
|
251
|
-
span.setAttribute(SLACK_SPAN_KEYS.AGENT_ID, metadata.agentId || "");
|
|
252
|
-
const workspaceConnection = await findWorkspaceConnectionByTeamId(teamId);
|
|
253
|
-
if (!workspaceConnection?.botToken) {
|
|
254
|
-
logger.error({ teamId }, "No bot token for follow-up modal");
|
|
255
|
-
span.end();
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
const slackClient = getSlackClient(workspaceConnection.botToken);
|
|
259
|
-
const modal = buildFollowUpModal(metadata);
|
|
260
|
-
await slackClient.views.open({
|
|
261
|
-
trigger_id: triggerId,
|
|
262
|
-
view: modal
|
|
263
|
-
});
|
|
264
|
-
logger.info({
|
|
265
|
-
teamId,
|
|
266
|
-
conversationId: metadata.conversationId,
|
|
267
|
-
agentId: metadata.agentId
|
|
268
|
-
}, "Opened follow-up modal");
|
|
269
|
-
span.end();
|
|
270
|
-
} catch (error) {
|
|
271
|
-
if (error instanceof Error) setSpanWithError(span, error);
|
|
272
|
-
logger.error({
|
|
273
|
-
error,
|
|
274
|
-
teamId
|
|
275
|
-
}, "Failed to open follow-up modal");
|
|
276
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
277
|
-
text: "Failed to open follow-up dialog. Please try again.",
|
|
278
|
-
response_type: "ephemeral"
|
|
279
|
-
}).catch((e) => logger.warn({ error: e }, "Failed to send follow-up error notification"));
|
|
280
|
-
span.end();
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
/**
|
|
285
242
|
* Handle message shortcut (context menu action on a message)
|
|
286
243
|
* Opens a modal with the message content pre-filled as context
|
|
287
244
|
*/
|
|
@@ -386,4 +343,4 @@ async function handleMessageShortcut(params) {
|
|
|
386
343
|
}
|
|
387
344
|
|
|
388
345
|
//#endregion
|
|
389
|
-
export { handleMessageShortcut, handleOpenAgentSelectorModal,
|
|
346
|
+
export { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/slack/services/events/direct-message.d.ts
|
|
2
|
+
declare function handleDirectMessage(params: {
|
|
3
|
+
slackUserId: string;
|
|
4
|
+
channel: string;
|
|
5
|
+
text: string;
|
|
6
|
+
threadTs?: string;
|
|
7
|
+
messageTs: string;
|
|
8
|
+
teamId: string;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { handleDirectMessage };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { getLogger } from "../../../logger.js";
|
|
2
|
+
import { findWorkspaceConnectionByTeamId } from "../nango.js";
|
|
3
|
+
import { classifyError, findCachedUserMapping, generateSlackConversationId, getThreadContext, getUserFriendlyErrorMessage } from "./utils.js";
|
|
4
|
+
import { SlackStrings } from "../../i18n/strings.js";
|
|
5
|
+
import { getSlackClient } from "../client.js";
|
|
6
|
+
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
7
|
+
import { executeAgentPublicly } from "./execution.js";
|
|
8
|
+
import { buildLinkPromptMessage, resolveUnlinkedUserAction } from "../link-prompt.js";
|
|
9
|
+
import { signSlackUserToken } from "@inkeep/agents-core";
|
|
10
|
+
|
|
11
|
+
//#region src/slack/services/events/direct-message.ts
|
|
12
|
+
const logger = getLogger("slack-direct-message");
|
|
13
|
+
async function handleDirectMessage(params) {
|
|
14
|
+
return tracer.startActiveSpan(SLACK_SPAN_NAMES.DIRECT_MESSAGE, async (span) => {
|
|
15
|
+
const { slackUserId, channel, text, threadTs, messageTs, teamId } = params;
|
|
16
|
+
span.setAttribute(SLACK_SPAN_KEYS.TEAM_ID, teamId);
|
|
17
|
+
span.setAttribute(SLACK_SPAN_KEYS.CHANNEL_ID, channel);
|
|
18
|
+
span.setAttribute(SLACK_SPAN_KEYS.USER_ID, slackUserId);
|
|
19
|
+
span.setAttribute(SLACK_SPAN_KEYS.MESSAGE_TS, messageTs);
|
|
20
|
+
if (threadTs) span.setAttribute(SLACK_SPAN_KEYS.THREAD_TS, threadTs);
|
|
21
|
+
logger.info({
|
|
22
|
+
slackUserId,
|
|
23
|
+
channel,
|
|
24
|
+
teamId
|
|
25
|
+
}, "Handling direct message");
|
|
26
|
+
const workspaceConnection = await findWorkspaceConnectionByTeamId(teamId);
|
|
27
|
+
if (!workspaceConnection?.botToken) {
|
|
28
|
+
logger.error({ teamId }, "No bot token available — cannot respond to DM");
|
|
29
|
+
span.end();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const { botToken, tenantId } = workspaceConnection;
|
|
33
|
+
if (!tenantId) {
|
|
34
|
+
logger.error({ teamId }, "Workspace connection has no tenantId");
|
|
35
|
+
span.end();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
span.setAttribute(SLACK_SPAN_KEYS.TENANT_ID, tenantId);
|
|
39
|
+
const slackClient = getSlackClient(botToken);
|
|
40
|
+
const replyThreadTs = threadTs || messageTs;
|
|
41
|
+
const isInThread = Boolean(threadTs && threadTs !== messageTs);
|
|
42
|
+
try {
|
|
43
|
+
const defaultAgent = workspaceConnection.defaultAgent;
|
|
44
|
+
if (!defaultAgent?.agentId || !defaultAgent?.projectId) {
|
|
45
|
+
logger.info({ teamId }, "No default agent configured — sending hint in DM");
|
|
46
|
+
await slackClient.chat.postMessage({
|
|
47
|
+
channel,
|
|
48
|
+
thread_ts: replyThreadTs,
|
|
49
|
+
text: SlackStrings.errors.noAgentConfigured
|
|
50
|
+
});
|
|
51
|
+
span.end();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
span.setAttribute(SLACK_SPAN_KEYS.AGENT_ID, defaultAgent.agentId);
|
|
55
|
+
span.setAttribute(SLACK_SPAN_KEYS.PROJECT_ID, defaultAgent.projectId);
|
|
56
|
+
const agentDisplayName = defaultAgent.agentName || defaultAgent.agentId;
|
|
57
|
+
const existingLink = await findCachedUserMapping(tenantId, slackUserId, teamId);
|
|
58
|
+
if (!existingLink) {
|
|
59
|
+
logger.info({
|
|
60
|
+
slackUserId,
|
|
61
|
+
teamId
|
|
62
|
+
}, "User not linked — sending link prompt in DM");
|
|
63
|
+
const message = buildLinkPromptMessage(await resolveUnlinkedUserAction({
|
|
64
|
+
tenantId,
|
|
65
|
+
teamId,
|
|
66
|
+
slackUserId,
|
|
67
|
+
botToken,
|
|
68
|
+
intent: {
|
|
69
|
+
entryPoint: "dm",
|
|
70
|
+
question: text.slice(0, 2e3),
|
|
71
|
+
channelId: channel,
|
|
72
|
+
messageTs,
|
|
73
|
+
agentId: defaultAgent.agentId,
|
|
74
|
+
projectId: defaultAgent.projectId
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
await slackClient.chat.postMessage({
|
|
78
|
+
channel,
|
|
79
|
+
thread_ts: replyThreadTs,
|
|
80
|
+
text: SlackStrings.linkPrompt.intro,
|
|
81
|
+
blocks: message.blocks
|
|
82
|
+
});
|
|
83
|
+
span.end();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
let queryText = text;
|
|
87
|
+
if (isInThread && threadTs) {
|
|
88
|
+
const contextMessages = await getThreadContext(slackClient, channel, threadTs);
|
|
89
|
+
if (contextMessages) queryText = text ? `The following is thread context from a DM conversation:\n\n<slack_thread_context>\n${contextMessages}\n</slack_thread_context>\n\nUser message: ${text}` : contextMessages;
|
|
90
|
+
}
|
|
91
|
+
const slackUserToken = await signSlackUserToken({
|
|
92
|
+
inkeepUserId: existingLink.inkeepUserId,
|
|
93
|
+
tenantId,
|
|
94
|
+
slackTeamId: teamId,
|
|
95
|
+
slackUserId,
|
|
96
|
+
slackAuthorized: false
|
|
97
|
+
});
|
|
98
|
+
const conversationId = generateSlackConversationId({
|
|
99
|
+
teamId,
|
|
100
|
+
messageTs,
|
|
101
|
+
agentId: defaultAgent.agentId,
|
|
102
|
+
isDM: true
|
|
103
|
+
});
|
|
104
|
+
span.setAttribute(SLACK_SPAN_KEYS.CONVERSATION_ID, conversationId);
|
|
105
|
+
logger.info({
|
|
106
|
+
agentId: defaultAgent.agentId,
|
|
107
|
+
projectId: defaultAgent.projectId,
|
|
108
|
+
conversationId
|
|
109
|
+
}, "Executing agent for DM");
|
|
110
|
+
await executeAgentPublicly({
|
|
111
|
+
slackClient,
|
|
112
|
+
channel,
|
|
113
|
+
threadTs: replyThreadTs,
|
|
114
|
+
slackUserId,
|
|
115
|
+
teamId,
|
|
116
|
+
jwtToken: slackUserToken,
|
|
117
|
+
projectId: defaultAgent.projectId,
|
|
118
|
+
agentId: defaultAgent.agentId,
|
|
119
|
+
agentName: agentDisplayName,
|
|
120
|
+
question: queryText,
|
|
121
|
+
conversationId
|
|
122
|
+
});
|
|
123
|
+
span.end();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
126
|
+
logger.error({
|
|
127
|
+
errorMessage: errorMsg,
|
|
128
|
+
channel,
|
|
129
|
+
teamId
|
|
130
|
+
}, "Failed in DM handler");
|
|
131
|
+
if (error instanceof Error) setSpanWithError(span, error);
|
|
132
|
+
const userMessage = getUserFriendlyErrorMessage(classifyError(error));
|
|
133
|
+
try {
|
|
134
|
+
await slackClient.chat.postMessage({
|
|
135
|
+
channel,
|
|
136
|
+
thread_ts: replyThreadTs,
|
|
137
|
+
text: userMessage
|
|
138
|
+
});
|
|
139
|
+
} catch (postError) {
|
|
140
|
+
logger.error({ error: postError }, "Failed to post DM error message");
|
|
141
|
+
}
|
|
142
|
+
span.end();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//#endregion
|
|
148
|
+
export { handleDirectMessage };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getSlackClient } from "../client.js";
|
|
2
|
+
import { StreamResult } from "./streaming.js";
|
|
3
|
+
|
|
4
|
+
//#region src/slack/services/events/execution.d.ts
|
|
5
|
+
interface PublicExecutionParams {
|
|
6
|
+
slackClient: ReturnType<typeof getSlackClient>;
|
|
7
|
+
channel: string;
|
|
8
|
+
threadTs?: string;
|
|
9
|
+
slackUserId: string;
|
|
10
|
+
teamId: string;
|
|
11
|
+
jwtToken: string;
|
|
12
|
+
projectId: string;
|
|
13
|
+
agentId: string;
|
|
14
|
+
agentName: string;
|
|
15
|
+
question: string;
|
|
16
|
+
conversationId: string;
|
|
17
|
+
}
|
|
18
|
+
declare function executeAgentPublicly(params: PublicExecutionParams): Promise<StreamResult>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { PublicExecutionParams, executeAgentPublicly };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { getLogger } from "../../../logger.js";
|
|
2
|
+
import { SlackStrings } from "../../i18n/strings.js";
|
|
3
|
+
import { streamAgentResponse } from "./streaming.js";
|
|
4
|
+
|
|
5
|
+
//#region src/slack/services/events/execution.ts
|
|
6
|
+
const logger = getLogger("slack-execution");
|
|
7
|
+
async function executeAgentPublicly(params) {
|
|
8
|
+
const { slackClient, channel, threadTs, agentName } = params;
|
|
9
|
+
let thinkingMessageTs = "";
|
|
10
|
+
try {
|
|
11
|
+
thinkingMessageTs = (await slackClient.chat.postMessage({
|
|
12
|
+
channel,
|
|
13
|
+
...threadTs ? { thread_ts: threadTs } : {},
|
|
14
|
+
text: SlackStrings.status.thinking(agentName)
|
|
15
|
+
})).ts || "";
|
|
16
|
+
} catch (error) {
|
|
17
|
+
logger.warn({
|
|
18
|
+
error,
|
|
19
|
+
channel
|
|
20
|
+
}, "Failed to post thinking acknowledgment - proceeding anyway");
|
|
21
|
+
}
|
|
22
|
+
const effectiveThreadTs = threadTs || thinkingMessageTs || void 0;
|
|
23
|
+
logger.info({
|
|
24
|
+
channel,
|
|
25
|
+
threadTs: effectiveThreadTs,
|
|
26
|
+
agentId: params.agentId,
|
|
27
|
+
conversationId: params.conversationId
|
|
28
|
+
}, "Starting stream");
|
|
29
|
+
return streamAgentResponse({
|
|
30
|
+
slackClient: params.slackClient,
|
|
31
|
+
channel,
|
|
32
|
+
threadTs: effectiveThreadTs,
|
|
33
|
+
thinkingMessageTs,
|
|
34
|
+
slackUserId: params.slackUserId,
|
|
35
|
+
teamId: params.teamId,
|
|
36
|
+
jwtToken: params.jwtToken,
|
|
37
|
+
projectId: params.projectId,
|
|
38
|
+
agentId: params.agentId,
|
|
39
|
+
question: params.question,
|
|
40
|
+
agentName,
|
|
41
|
+
conversationId: params.conversationId
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { executeAgentPublicly };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
2
2
|
import { InlineSelectorMetadata, handleAppMention } from "./app-mention.js";
|
|
3
|
-
import { handleMessageShortcut, handleOpenAgentSelectorModal,
|
|
4
|
-
import {
|
|
3
|
+
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval } from "./block-actions.js";
|
|
4
|
+
import { handleDirectMessage } from "./direct-message.js";
|
|
5
5
|
import { StreamResult, streamAgentResponse } from "./streaming.js";
|
|
6
|
-
|
|
6
|
+
import { PublicExecutionParams, executeAgentPublicly } from "./execution.js";
|
|
7
|
+
import { handleModalSubmission } from "./modal-submission.js";
|
|
8
|
+
export { type InlineSelectorMetadata, type PublicExecutionParams, SlackErrorType, type StreamResult, checkIfBotThread, classifyError, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleDirectMessage, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleToolApproval, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
2
2
|
import { streamAgentResponse } from "./streaming.js";
|
|
3
|
+
import { executeAgentPublicly } from "./execution.js";
|
|
3
4
|
import { handleAppMention } from "./app-mention.js";
|
|
4
|
-
import { handleMessageShortcut, handleOpenAgentSelectorModal,
|
|
5
|
-
import {
|
|
5
|
+
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval } from "./block-actions.js";
|
|
6
|
+
import { handleDirectMessage } from "./direct-message.js";
|
|
7
|
+
import { handleModalSubmission } from "./modal-submission.js";
|
|
6
8
|
|
|
7
|
-
export { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention,
|
|
9
|
+
export { SlackErrorType, checkIfBotThread, classifyError, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleDirectMessage, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleToolApproval, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
//#region src/slack/services/events/modal-submission.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Handler for Slack modal submission events
|
|
4
|
-
*
|
|
5
|
-
* Handles both initial agent selector modal and follow-up modal submissions.
|
|
6
|
-
* All responses are private (ephemeral) with a Follow Up button for multi-turn conversations.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Handle initial agent selector modal submission.
|
|
10
|
-
* Always posts ephemeral (private) responses with a Follow Up button.
|
|
11
|
-
*/
|
|
12
2
|
declare function handleModalSubmission(view: {
|
|
13
3
|
private_metadata?: string;
|
|
14
4
|
callback_id?: string;
|
|
@@ -16,15 +6,5 @@ declare function handleModalSubmission(view: {
|
|
|
16
6
|
values?: Record<string, Record<string, unknown>>;
|
|
17
7
|
};
|
|
18
8
|
}): Promise<void>;
|
|
19
|
-
/**
|
|
20
|
-
* Handle follow-up modal submission.
|
|
21
|
-
* Reuses the existing conversationId so the agent has full conversation history.
|
|
22
|
-
*/
|
|
23
|
-
declare function handleFollowUpSubmission(view: {
|
|
24
|
-
private_metadata?: string;
|
|
25
|
-
state?: {
|
|
26
|
-
values?: Record<string, Record<string, unknown>>;
|
|
27
|
-
};
|
|
28
|
-
}): Promise<void>;
|
|
29
9
|
//#endregion
|
|
30
|
-
export {
|
|
10
|
+
export { handleModalSubmission };
|