@inkeep/agents-work-apps 0.0.0-dev-20260204182014 → 0.0.0-dev-20260204210021
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/db/index.d.ts +1 -2
- package/dist/db/index.js +1 -2
- package/dist/db/runDbClient.d.ts +2 -2
- package/dist/env.d.ts +2 -24
- package/dist/env.js +1 -12
- package/dist/github/routes/setup.d.ts +2 -2
- package/dist/github/routes/tokenExchange.d.ts +2 -2
- package/package.json +2 -10
- package/dist/db/manageDbClient.d.ts +0 -7
- package/dist/db/manageDbClient.js +0 -16
- package/dist/slack/index.d.ts +0 -19
- package/dist/slack/index.js +0 -29
- package/dist/slack/middleware/permissions.d.ts +0 -16
- package/dist/slack/middleware/permissions.js +0 -49
- package/dist/slack/routes/events.d.ts +0 -10
- package/dist/slack/routes/events.js +0 -319
- package/dist/slack/routes/index.d.ts +0 -11
- package/dist/slack/routes/index.js +0 -64
- package/dist/slack/routes/internal.d.ts +0 -10
- package/dist/slack/routes/internal.js +0 -107
- package/dist/slack/routes/oauth.d.ts +0 -12
- package/dist/slack/routes/oauth.js +0 -218
- package/dist/slack/routes/resources.d.ts +0 -10
- package/dist/slack/routes/resources.js +0 -163
- package/dist/slack/routes/users.d.ts +0 -15
- package/dist/slack/routes/users.js +0 -430
- package/dist/slack/routes/workspaces.d.ts +0 -10
- package/dist/slack/routes/workspaces.js +0 -828
- package/dist/slack/routes.d.ts +0 -7
- package/dist/slack/routes.js +0 -12
- package/dist/slack/services/agent-resolution.d.ts +0 -49
- package/dist/slack/services/agent-resolution.js +0 -135
- package/dist/slack/services/api-client.d.ts +0 -161
- package/dist/slack/services/api-client.js +0 -248
- package/dist/slack/services/auth/index.d.ts +0 -61
- package/dist/slack/services/auth/index.js +0 -164
- package/dist/slack/services/blocks/index.d.ts +0 -60
- package/dist/slack/services/blocks/index.js +0 -143
- package/dist/slack/services/client.d.ts +0 -78
- package/dist/slack/services/client.js +0 -152
- package/dist/slack/services/commands/index.d.ts +0 -15
- package/dist/slack/services/commands/index.js +0 -556
- package/dist/slack/services/events/app-mention.d.ts +0 -41
- package/dist/slack/services/events/app-mention.js +0 -212
- package/dist/slack/services/events/block-actions.d.ts +0 -47
- package/dist/slack/services/events/block-actions.js +0 -287
- package/dist/slack/services/events/index.d.ts +0 -6
- package/dist/slack/services/events/index.js +0 -7
- package/dist/slack/services/events/modal-submission.d.ts +0 -12
- package/dist/slack/services/events/modal-submission.js +0 -279
- package/dist/slack/services/events/streaming.d.ts +0 -27
- package/dist/slack/services/events/streaming.js +0 -285
- package/dist/slack/services/events/utils.d.ts +0 -129
- package/dist/slack/services/events/utils.js +0 -315
- package/dist/slack/services/index.d.ts +0 -18
- package/dist/slack/services/index.js +0 -18
- package/dist/slack/services/modals.d.ts +0 -67
- package/dist/slack/services/modals.js +0 -203
- package/dist/slack/services/nango.d.ts +0 -82
- package/dist/slack/services/nango.js +0 -326
- package/dist/slack/services/security.d.ts +0 -35
- package/dist/slack/services/security.js +0 -65
- package/dist/slack/services/types.d.ts +0 -26
- package/dist/slack/services/types.js +0 -1
- package/dist/slack/services/workspace-tokens.d.ts +0 -37
- package/dist/slack/services/workspace-tokens.js +0 -39
- package/dist/slack/types.d.ts +0 -10
- package/dist/slack/types.js +0 -1
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { env } from "../../../env.js";
|
|
2
|
-
import { getLogger } from "../../../logger.js";
|
|
3
|
-
import runDbClient_default from "../../../db/runDbClient.js";
|
|
4
|
-
import { findWorkspaceConnectionByTeamId } from "../nango.js";
|
|
5
|
-
import { getSlackClient, postMessageInThread } from "../client.js";
|
|
6
|
-
import { getBotTokenForTeam } from "../workspace-tokens.js";
|
|
7
|
-
import { checkIfBotThread, classifyError, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage } from "./utils.js";
|
|
8
|
-
import { streamAgentResponse } from "./streaming.js";
|
|
9
|
-
import { findWorkAppSlackUserMapping, signSlackUserToken } from "@inkeep/agents-core";
|
|
10
|
-
|
|
11
|
-
//#region src/slack/services/events/app-mention.ts
|
|
12
|
-
/**
|
|
13
|
-
* Handler for Slack @mention events
|
|
14
|
-
*
|
|
15
|
-
* Flow:
|
|
16
|
-
* 1. Resolve agent config (channel override > workspace default)
|
|
17
|
-
* 2. If no agent configured → prompt to set up in dashboard
|
|
18
|
-
* 3. Check if user is linked to Inkeep
|
|
19
|
-
* 4. If not linked → prompt to link account
|
|
20
|
-
* 5. Handle based on context:
|
|
21
|
-
* - Channel + no query → Show welcome/help message
|
|
22
|
-
* - Channel + query → Execute agent with streaming response
|
|
23
|
-
* - Thread + no query → Show modal to select agent
|
|
24
|
-
* - Thread + query → Execute agent with thread context included
|
|
25
|
-
*/
|
|
26
|
-
const logger = getLogger("slack-app-mention");
|
|
27
|
-
/**
|
|
28
|
-
* Main handler for @mention events in Slack
|
|
29
|
-
*/
|
|
30
|
-
async function handleAppMention(params) {
|
|
31
|
-
const { slackUserId, channel, text, threadTs, messageTs, teamId } = params;
|
|
32
|
-
const manageUiUrl = env.INKEEP_AGENTS_MANAGE_UI_URL || "http://localhost:3000";
|
|
33
|
-
logger.info({
|
|
34
|
-
slackUserId,
|
|
35
|
-
channel,
|
|
36
|
-
teamId
|
|
37
|
-
}, "Handling app mention");
|
|
38
|
-
const tenantId = (await findWorkspaceConnectionByTeamId(teamId))?.tenantId || "default";
|
|
39
|
-
const dashboardUrl = `${manageUiUrl}/${tenantId}/work-apps/slack`;
|
|
40
|
-
const botToken = await resolveBotToken(teamId);
|
|
41
|
-
if (!botToken) {
|
|
42
|
-
logger.error({ teamId }, "No bot token available");
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
const slackClient = getSlackClient(botToken);
|
|
46
|
-
const replyThreadTs = threadTs || messageTs;
|
|
47
|
-
const isInThread = Boolean(threadTs && threadTs !== messageTs);
|
|
48
|
-
const hasQuery = Boolean(text && text.trim().length > 0);
|
|
49
|
-
try {
|
|
50
|
-
const agentConfig = await getChannelAgentConfig(teamId, channel);
|
|
51
|
-
if (!agentConfig) {
|
|
52
|
-
await slackClient.chat.postEphemeral({
|
|
53
|
-
channel,
|
|
54
|
-
user: slackUserId,
|
|
55
|
-
thread_ts: isInThread ? threadTs : void 0,
|
|
56
|
-
text: `⚙️ No agents configured for this workspace.\n\n👉 *<${dashboardUrl}|Set up agents in the dashboard>*`
|
|
57
|
-
});
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
const agentDisplayName = agentConfig.agentName || agentConfig.agentId;
|
|
61
|
-
const existingLink = await findWorkAppSlackUserMapping(runDbClient_default)(tenantId, slackUserId, teamId, "work-apps-slack");
|
|
62
|
-
if (!existingLink) {
|
|
63
|
-
await slackClient.chat.postEphemeral({
|
|
64
|
-
channel,
|
|
65
|
-
user: slackUserId,
|
|
66
|
-
thread_ts: isInThread ? threadTs : void 0,
|
|
67
|
-
text: `🔗 *Link your account to use @Inkeep*
|
|
68
|
-
|
|
69
|
-
Run \`/inkeep link\` to connect your Slack and Inkeep accounts.
|
|
70
|
-
|
|
71
|
-
This workspace uses: *${agentDisplayName}*`
|
|
72
|
-
});
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
if (isInThread && !hasQuery) {
|
|
76
|
-
if (await checkIfBotThread(slackClient, channel, threadTs)) await slackClient.chat.postEphemeral({
|
|
77
|
-
channel,
|
|
78
|
-
user: slackUserId,
|
|
79
|
-
thread_ts: threadTs,
|
|
80
|
-
text: `💬 *Continue the conversation*
|
|
81
|
-
|
|
82
|
-
Just type your follow-up — no need to mention me in this thread.
|
|
83
|
-
Or use \`@Inkeep <prompt>\` to run a new prompt.
|
|
84
|
-
|
|
85
|
-
_Using: ${agentDisplayName}_`
|
|
86
|
-
});
|
|
87
|
-
else {
|
|
88
|
-
const metadata = {
|
|
89
|
-
channel,
|
|
90
|
-
threadTs,
|
|
91
|
-
messageTs,
|
|
92
|
-
teamId,
|
|
93
|
-
slackUserId,
|
|
94
|
-
tenantId,
|
|
95
|
-
threadMessageCount: 0
|
|
96
|
-
};
|
|
97
|
-
await slackClient.chat.postEphemeral({
|
|
98
|
-
channel,
|
|
99
|
-
user: slackUserId,
|
|
100
|
-
thread_ts: threadTs,
|
|
101
|
-
text: "Select an agent to analyze this thread",
|
|
102
|
-
blocks: [{
|
|
103
|
-
type: "section",
|
|
104
|
-
text: {
|
|
105
|
-
type: "mrkdwn",
|
|
106
|
-
text: "*Run an agent on this thread*\nClick the button below to select an agent and run it with this thread as context."
|
|
107
|
-
}
|
|
108
|
-
}, {
|
|
109
|
-
type: "actions",
|
|
110
|
-
block_id: "agent_selector_trigger",
|
|
111
|
-
elements: [{
|
|
112
|
-
type: "button",
|
|
113
|
-
action_id: "open_agent_selector_modal",
|
|
114
|
-
text: {
|
|
115
|
-
type: "plain_text",
|
|
116
|
-
text: "Select Agent",
|
|
117
|
-
emoji: true
|
|
118
|
-
},
|
|
119
|
-
style: "primary",
|
|
120
|
-
value: JSON.stringify(metadata)
|
|
121
|
-
}]
|
|
122
|
-
}]
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
if (!hasQuery) {
|
|
128
|
-
await slackClient.chat.postEphemeral({
|
|
129
|
-
channel,
|
|
130
|
-
user: slackUserId,
|
|
131
|
-
text: `*${agentDisplayName}* is your workspace's default agent.\n\n*Get started:*\n\`@Inkeep <prompt>\` — Run the agent with your prompt\n\n*In threads:*\n• \`@Inkeep <prompt>\` — Include thread context automatically\n• \`@Inkeep\` (no prompt) — Open agent selector to choose a different agent\n\nUse \`/inkeep help\` for more options.`
|
|
132
|
-
});
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
let queryText = text;
|
|
136
|
-
if (isInThread && threadTs) {
|
|
137
|
-
const contextMessages = await getThreadContext(slackClient, channel, threadTs);
|
|
138
|
-
if (contextMessages) queryText = `Based on the following conversation:\n\n${contextMessages}\n\nUser question: ${text}`;
|
|
139
|
-
}
|
|
140
|
-
const slackUserToken = await signSlackUserToken({
|
|
141
|
-
inkeepUserId: existingLink.inkeepUserId,
|
|
142
|
-
tenantId,
|
|
143
|
-
slackTeamId: teamId,
|
|
144
|
-
slackUserId
|
|
145
|
-
});
|
|
146
|
-
const ackMessage = await slackClient.chat.postMessage({
|
|
147
|
-
channel,
|
|
148
|
-
thread_ts: replyThreadTs,
|
|
149
|
-
text: `_${agentDisplayName} is preparing a response..._`
|
|
150
|
-
});
|
|
151
|
-
const conversationId = generateSlackConversationId({
|
|
152
|
-
teamId,
|
|
153
|
-
threadTs: replyThreadTs,
|
|
154
|
-
channel,
|
|
155
|
-
isDM: false
|
|
156
|
-
});
|
|
157
|
-
logger.info({
|
|
158
|
-
projectId: agentConfig.projectId,
|
|
159
|
-
agentId: agentConfig.agentId,
|
|
160
|
-
conversationId
|
|
161
|
-
}, "Executing agent");
|
|
162
|
-
await streamAgentResponse({
|
|
163
|
-
slackClient,
|
|
164
|
-
channel,
|
|
165
|
-
threadTs: replyThreadTs,
|
|
166
|
-
thinkingMessageTs: ackMessage.ts || "",
|
|
167
|
-
slackUserId,
|
|
168
|
-
teamId,
|
|
169
|
-
jwtToken: slackUserToken,
|
|
170
|
-
projectId: agentConfig.projectId,
|
|
171
|
-
agentId: agentConfig.agentId,
|
|
172
|
-
question: queryText,
|
|
173
|
-
agentName: agentDisplayName,
|
|
174
|
-
conversationId
|
|
175
|
-
});
|
|
176
|
-
} catch (error) {
|
|
177
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
178
|
-
logger.error({
|
|
179
|
-
errorMessage: errorMsg,
|
|
180
|
-
channel,
|
|
181
|
-
teamId
|
|
182
|
-
}, "Failed in app mention handler");
|
|
183
|
-
const userMessage = getUserFriendlyErrorMessage(classifyError(error));
|
|
184
|
-
try {
|
|
185
|
-
await slackClient.chat.postEphemeral({
|
|
186
|
-
channel,
|
|
187
|
-
user: slackUserId,
|
|
188
|
-
thread_ts: isInThread ? threadTs : void 0,
|
|
189
|
-
text: userMessage
|
|
190
|
-
});
|
|
191
|
-
} catch (postError) {
|
|
192
|
-
logger.error({ error: postError }, "Failed to post error message");
|
|
193
|
-
try {
|
|
194
|
-
await postMessageInThread(slackClient, channel, replyThreadTs, userMessage);
|
|
195
|
-
} catch {}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Resolve bot token from various sources (Nango, memory cache, env)
|
|
201
|
-
*/
|
|
202
|
-
async function resolveBotToken(teamId) {
|
|
203
|
-
const workspaceConnection = await findWorkspaceConnectionByTeamId(teamId);
|
|
204
|
-
if (workspaceConnection?.botToken) return workspaceConnection.botToken;
|
|
205
|
-
const memoryToken = getBotTokenForTeam(teamId);
|
|
206
|
-
if (memoryToken) return memoryToken;
|
|
207
|
-
if (env.SLACK_BOT_TOKEN) return env.SLACK_BOT_TOKEN;
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
//#endregion
|
|
212
|
-
export { handleAppMention };
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { ModalMetadata } from "../modals.js";
|
|
2
|
-
|
|
3
|
-
//#region src/slack/services/events/block-actions.d.ts
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Handle "Share to Thread" button click from ephemeral responses
|
|
7
|
-
* Posts the response to the current thread instead of the main channel
|
|
8
|
-
*/
|
|
9
|
-
declare function handleShareToThread(params: {
|
|
10
|
-
teamId: string;
|
|
11
|
-
channelId: string;
|
|
12
|
-
userId: string;
|
|
13
|
-
actionValue: string;
|
|
14
|
-
responseUrl: string;
|
|
15
|
-
}): Promise<void>;
|
|
16
|
-
/**
|
|
17
|
-
* Handle "Share to Channel" button click from ephemeral responses
|
|
18
|
-
*/
|
|
19
|
-
declare function handleShareToChannel(params: {
|
|
20
|
-
teamId: string;
|
|
21
|
-
channelId: string;
|
|
22
|
-
userId: string;
|
|
23
|
-
actionValue: string;
|
|
24
|
-
responseUrl: string;
|
|
25
|
-
}): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Handle opening the agent selector modal when user clicks "Select Agent" button
|
|
28
|
-
*/
|
|
29
|
-
declare function handleOpenAgentSelectorModal(params: {
|
|
30
|
-
triggerId: string;
|
|
31
|
-
actionValue: string;
|
|
32
|
-
teamId: string;
|
|
33
|
-
responseUrl: string;
|
|
34
|
-
}): Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
* Handle project selection change in modal (updates agent dropdown)
|
|
37
|
-
*/
|
|
38
|
-
declare function handleModalProjectSelect(params: {
|
|
39
|
-
triggerId: string;
|
|
40
|
-
viewId: string;
|
|
41
|
-
teamId: string;
|
|
42
|
-
tenantId: string;
|
|
43
|
-
selectedProjectId: string;
|
|
44
|
-
currentMetadata: ModalMetadata;
|
|
45
|
-
}): Promise<void>;
|
|
46
|
-
//#endregion
|
|
47
|
-
export { handleModalProjectSelect, handleOpenAgentSelectorModal, handleShareToChannel, handleShareToThread };
|
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
import { getLogger } from "../../../logger.js";
|
|
2
|
-
import { findWorkspaceConnectionByTeamId } from "../nango.js";
|
|
3
|
-
import { getSlackClient } from "../client.js";
|
|
4
|
-
import { fetchAgentsForProject, fetchProjectsForTenant, getChannelAgentConfig, sendResponseUrlMessage } from "./utils.js";
|
|
5
|
-
import { buildAgentSelectorModal } from "../modals.js";
|
|
6
|
-
|
|
7
|
-
//#region src/slack/services/events/block-actions.ts
|
|
8
|
-
/**
|
|
9
|
-
* Handlers for Slack block action events (button clicks, selections, etc.)
|
|
10
|
-
*/
|
|
11
|
-
const logger = getLogger("slack-block-actions");
|
|
12
|
-
/**
|
|
13
|
-
* Handle "Share to Thread" button click from ephemeral responses
|
|
14
|
-
* Posts the response to the current thread instead of the main channel
|
|
15
|
-
*/
|
|
16
|
-
async function handleShareToThread(params) {
|
|
17
|
-
const { teamId, channelId, userId, actionValue, responseUrl } = params;
|
|
18
|
-
let textToShare = "";
|
|
19
|
-
let agentName = "Inkeep";
|
|
20
|
-
let threadTs = "";
|
|
21
|
-
try {
|
|
22
|
-
const valueData = JSON.parse(actionValue);
|
|
23
|
-
textToShare = valueData.text || "";
|
|
24
|
-
agentName = valueData.agentName || "Inkeep";
|
|
25
|
-
threadTs = valueData.threadTs || "";
|
|
26
|
-
} catch {
|
|
27
|
-
logger.warn({ actionValue }, "Failed to parse share_to_thread action value");
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (!textToShare) {
|
|
31
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
32
|
-
text: "❌ Could not find content to share.",
|
|
33
|
-
response_type: "ephemeral"
|
|
34
|
-
});
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (!threadTs) {
|
|
38
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
39
|
-
text: "❌ Could not find thread to share to.",
|
|
40
|
-
response_type: "ephemeral"
|
|
41
|
-
});
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const workspaceConnection = await findWorkspaceConnectionByTeamId(teamId);
|
|
45
|
-
if (!workspaceConnection?.botToken) {
|
|
46
|
-
logger.error({ teamId }, "No bot token for share_to_thread");
|
|
47
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
48
|
-
text: "❌ Could not share to thread. Please try again.",
|
|
49
|
-
response_type: "ephemeral"
|
|
50
|
-
});
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const slackClient = getSlackClient(workspaceConnection.botToken);
|
|
54
|
-
try {
|
|
55
|
-
await slackClient.chat.postMessage({
|
|
56
|
-
channel: channelId,
|
|
57
|
-
thread_ts: threadTs,
|
|
58
|
-
text: textToShare,
|
|
59
|
-
blocks: [{
|
|
60
|
-
type: "section",
|
|
61
|
-
text: {
|
|
62
|
-
type: "mrkdwn",
|
|
63
|
-
text: textToShare
|
|
64
|
-
}
|
|
65
|
-
}, {
|
|
66
|
-
type: "context",
|
|
67
|
-
elements: [{
|
|
68
|
-
type: "mrkdwn",
|
|
69
|
-
text: `Shared by <@${userId}> • Powered by *${agentName}* via Inkeep`
|
|
70
|
-
}]
|
|
71
|
-
}]
|
|
72
|
-
});
|
|
73
|
-
logger.info({
|
|
74
|
-
channelId,
|
|
75
|
-
threadTs,
|
|
76
|
-
userId
|
|
77
|
-
}, "Shared message to thread");
|
|
78
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
79
|
-
text: "✅ Response shared to thread!",
|
|
80
|
-
response_type: "ephemeral"
|
|
81
|
-
});
|
|
82
|
-
} catch (error) {
|
|
83
|
-
logger.error({
|
|
84
|
-
error,
|
|
85
|
-
channelId,
|
|
86
|
-
threadTs
|
|
87
|
-
}, "Failed to share message to thread");
|
|
88
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
89
|
-
text: "❌ Failed to share to thread. Please try again.",
|
|
90
|
-
response_type: "ephemeral"
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Handle "Share to Channel" button click from ephemeral responses
|
|
96
|
-
*/
|
|
97
|
-
async function handleShareToChannel(params) {
|
|
98
|
-
const { teamId, channelId, userId, actionValue, responseUrl } = params;
|
|
99
|
-
let textToShare = "";
|
|
100
|
-
let agentName = "Inkeep";
|
|
101
|
-
try {
|
|
102
|
-
const valueData = JSON.parse(actionValue);
|
|
103
|
-
textToShare = valueData.text || "";
|
|
104
|
-
agentName = valueData.agentName || "Inkeep";
|
|
105
|
-
} catch {
|
|
106
|
-
logger.warn({ actionValue }, "Failed to parse share_to_channel action value");
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (!textToShare) {
|
|
110
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
111
|
-
text: "❌ Could not find content to share.",
|
|
112
|
-
response_type: "ephemeral"
|
|
113
|
-
});
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
const workspaceConnection = await findWorkspaceConnectionByTeamId(teamId);
|
|
117
|
-
if (!workspaceConnection?.botToken) {
|
|
118
|
-
logger.error({ teamId }, "No bot token for share_to_channel");
|
|
119
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
120
|
-
text: "❌ Could not share to channel. Please try again.",
|
|
121
|
-
response_type: "ephemeral"
|
|
122
|
-
});
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
const slackClient = getSlackClient(workspaceConnection.botToken);
|
|
126
|
-
try {
|
|
127
|
-
await slackClient.chat.postMessage({
|
|
128
|
-
channel: channelId,
|
|
129
|
-
text: textToShare,
|
|
130
|
-
blocks: [{
|
|
131
|
-
type: "section",
|
|
132
|
-
text: {
|
|
133
|
-
type: "mrkdwn",
|
|
134
|
-
text: textToShare
|
|
135
|
-
}
|
|
136
|
-
}, {
|
|
137
|
-
type: "context",
|
|
138
|
-
elements: [{
|
|
139
|
-
type: "mrkdwn",
|
|
140
|
-
text: `Shared by <@${userId}> • Powered by *${agentName}* via Inkeep`
|
|
141
|
-
}]
|
|
142
|
-
}]
|
|
143
|
-
});
|
|
144
|
-
logger.info({
|
|
145
|
-
channelId,
|
|
146
|
-
userId
|
|
147
|
-
}, "Shared message to channel");
|
|
148
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
149
|
-
text: "✅ Response shared to channel!",
|
|
150
|
-
response_type: "ephemeral"
|
|
151
|
-
});
|
|
152
|
-
} catch (error) {
|
|
153
|
-
logger.error({
|
|
154
|
-
error,
|
|
155
|
-
channelId
|
|
156
|
-
}, "Failed to share message to channel");
|
|
157
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
158
|
-
text: "❌ Failed to share to channel. Please try again.",
|
|
159
|
-
response_type: "ephemeral"
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Handle opening the agent selector modal when user clicks "Select Agent" button
|
|
165
|
-
*/
|
|
166
|
-
async function handleOpenAgentSelectorModal(params) {
|
|
167
|
-
const { triggerId, actionValue, teamId, responseUrl } = params;
|
|
168
|
-
try {
|
|
169
|
-
const metadata = JSON.parse(actionValue);
|
|
170
|
-
const { channel, threadTs, slackUserId, tenantId } = metadata;
|
|
171
|
-
const workspaceConnection = await findWorkspaceConnectionByTeamId(teamId);
|
|
172
|
-
if (!workspaceConnection?.botToken) {
|
|
173
|
-
logger.error({ teamId }, "No bot token for modal");
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
const slackClient = getSlackClient(workspaceConnection.botToken);
|
|
177
|
-
let projectList = await fetchProjectsForTenant(tenantId);
|
|
178
|
-
if (projectList.length === 0) {
|
|
179
|
-
const defaultAgent = await getChannelAgentConfig(teamId, channel);
|
|
180
|
-
if (defaultAgent) projectList = [{
|
|
181
|
-
id: defaultAgent.projectId,
|
|
182
|
-
name: defaultAgent.projectName || defaultAgent.projectId
|
|
183
|
-
}];
|
|
184
|
-
}
|
|
185
|
-
if (projectList.length === 0) {
|
|
186
|
-
await slackClient.chat.postEphemeral({
|
|
187
|
-
channel,
|
|
188
|
-
user: slackUserId,
|
|
189
|
-
thread_ts: threadTs,
|
|
190
|
-
text: "⚙️ No projects configured. Please set up projects in the dashboard."
|
|
191
|
-
});
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
const firstProject = projectList[0];
|
|
195
|
-
let agentList = await fetchAgentsForProject(tenantId, firstProject.id);
|
|
196
|
-
if (agentList.length === 0) {
|
|
197
|
-
const defaultAgent = await getChannelAgentConfig(teamId, channel);
|
|
198
|
-
if (defaultAgent && defaultAgent.projectId === firstProject.id) agentList = [{
|
|
199
|
-
id: defaultAgent.agentId,
|
|
200
|
-
name: defaultAgent.agentName || defaultAgent.agentId,
|
|
201
|
-
projectId: defaultAgent.projectId,
|
|
202
|
-
projectName: defaultAgent.projectName || defaultAgent.projectId
|
|
203
|
-
}];
|
|
204
|
-
}
|
|
205
|
-
const modalMetadata = {
|
|
206
|
-
channel,
|
|
207
|
-
threadTs,
|
|
208
|
-
messageTs: metadata.messageTs,
|
|
209
|
-
teamId,
|
|
210
|
-
slackUserId,
|
|
211
|
-
tenantId,
|
|
212
|
-
isInThread: true,
|
|
213
|
-
threadMessageCount: 0,
|
|
214
|
-
buttonResponseUrl: responseUrl
|
|
215
|
-
};
|
|
216
|
-
const modal = buildAgentSelectorModal({
|
|
217
|
-
projects: projectList,
|
|
218
|
-
agents: agentList.map((a) => ({
|
|
219
|
-
id: a.id,
|
|
220
|
-
name: a.name,
|
|
221
|
-
projectId: a.projectId,
|
|
222
|
-
projectName: a.projectName || a.projectId
|
|
223
|
-
})),
|
|
224
|
-
metadata: modalMetadata,
|
|
225
|
-
selectedProjectId: firstProject.id
|
|
226
|
-
});
|
|
227
|
-
await slackClient.views.open({
|
|
228
|
-
trigger_id: triggerId,
|
|
229
|
-
view: modal
|
|
230
|
-
});
|
|
231
|
-
logger.info({
|
|
232
|
-
teamId,
|
|
233
|
-
channel,
|
|
234
|
-
threadTs,
|
|
235
|
-
projectCount: projectList.length,
|
|
236
|
-
agentCount: agentList.length
|
|
237
|
-
}, "Opened agent selector modal");
|
|
238
|
-
} catch (error) {
|
|
239
|
-
logger.error({
|
|
240
|
-
error,
|
|
241
|
-
teamId
|
|
242
|
-
}, "Failed to open agent selector modal");
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Handle project selection change in modal (updates agent dropdown)
|
|
247
|
-
*/
|
|
248
|
-
async function handleModalProjectSelect(params) {
|
|
249
|
-
const { viewId, teamId, tenantId, selectedProjectId, currentMetadata } = params;
|
|
250
|
-
try {
|
|
251
|
-
const workspaceConnection = await findWorkspaceConnectionByTeamId(teamId);
|
|
252
|
-
if (!workspaceConnection?.botToken) {
|
|
253
|
-
logger.error({ teamId }, "No bot token for modal update");
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
const slackClient = getSlackClient(workspaceConnection.botToken);
|
|
257
|
-
const [projectList, agentList] = await Promise.all([fetchProjectsForTenant(tenantId), fetchAgentsForProject(tenantId, selectedProjectId)]);
|
|
258
|
-
const modal = buildAgentSelectorModal({
|
|
259
|
-
projects: projectList,
|
|
260
|
-
agents: agentList.map((a) => ({
|
|
261
|
-
id: a.id,
|
|
262
|
-
name: a.name,
|
|
263
|
-
projectId: a.projectId,
|
|
264
|
-
projectName: a.projectName || a.projectId
|
|
265
|
-
})),
|
|
266
|
-
metadata: currentMetadata,
|
|
267
|
-
selectedProjectId
|
|
268
|
-
});
|
|
269
|
-
await slackClient.views.update({
|
|
270
|
-
view_id: viewId,
|
|
271
|
-
view: modal
|
|
272
|
-
});
|
|
273
|
-
logger.info({
|
|
274
|
-
teamId,
|
|
275
|
-
selectedProjectId,
|
|
276
|
-
agentCount: agentList.length
|
|
277
|
-
}, "Updated modal view");
|
|
278
|
-
} catch (error) {
|
|
279
|
-
logger.error({
|
|
280
|
-
error,
|
|
281
|
-
teamId
|
|
282
|
-
}, "Failed to update modal after project select");
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
//#endregion
|
|
287
|
-
export { handleModalProjectSelect, handleOpenAgentSelectorModal, handleShareToChannel, handleShareToThread };
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { InlineSelectorMetadata, handleAppMention } from "./app-mention.js";
|
|
2
|
-
import { handleModalProjectSelect, handleOpenAgentSelectorModal, handleShareToChannel, handleShareToThread } from "./block-actions.js";
|
|
3
|
-
import { handleModalSubmission } from "./modal-submission.js";
|
|
4
|
-
import { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
5
|
-
import { StreamResult, streamAgentResponse } from "./streaming.js";
|
|
6
|
-
export { type InlineSelectorMetadata, SlackErrorType, type StreamResult, checkIfBotThread, classifyError, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleModalProjectSelect, handleModalSubmission, handleOpenAgentSelectorModal, handleShareToChannel, handleShareToThread, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
2
|
-
import { streamAgentResponse } from "./streaming.js";
|
|
3
|
-
import { handleAppMention } from "./app-mention.js";
|
|
4
|
-
import { handleModalProjectSelect, handleOpenAgentSelectorModal, handleShareToChannel, handleShareToThread } from "./block-actions.js";
|
|
5
|
-
import { handleModalSubmission } from "./modal-submission.js";
|
|
6
|
-
|
|
7
|
-
export { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleModalProjectSelect, handleModalSubmission, handleOpenAgentSelectorModal, handleShareToChannel, handleShareToThread, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
//#region src/slack/services/events/modal-submission.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Handler for Slack modal submission events
|
|
4
|
-
*/
|
|
5
|
-
declare function handleModalSubmission(view: {
|
|
6
|
-
private_metadata?: string;
|
|
7
|
-
state?: {
|
|
8
|
-
values?: Record<string, Record<string, unknown>>;
|
|
9
|
-
};
|
|
10
|
-
}): Promise<void>;
|
|
11
|
-
//#endregion
|
|
12
|
-
export { handleModalSubmission };
|