@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,556 +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 { resolveEffectiveAgent } from "../agent-resolution.js";
|
|
6
|
-
import { createAgentListMessage, createAlreadyLinkedMessage, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createSettingsMessage, createSettingsUpdatedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "../blocks/index.js";
|
|
7
|
-
import { deleteWorkAppSlackUserMapping, findWorkAppSlackUserMapping, findWorkAppSlackUserMappingBySlackUser, signSlackLinkToken, signSlackUserToken, upsertWorkAppSlackUserSettings } from "@inkeep/agents-core";
|
|
8
|
-
|
|
9
|
-
//#region src/slack/services/commands/index.ts
|
|
10
|
-
/**
|
|
11
|
-
* Fetch all agents from the manage API.
|
|
12
|
-
* This uses the proper ref-middleware and Dolt branch resolution.
|
|
13
|
-
* Requires an auth token to access the manage API.
|
|
14
|
-
*/
|
|
15
|
-
async function fetchAgentsFromManageApi(tenantId, authToken) {
|
|
16
|
-
const apiBaseUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
|
|
17
|
-
try {
|
|
18
|
-
const projectsResponse = await fetch(`${apiBaseUrl}/manage/tenants/${tenantId}/projects`, {
|
|
19
|
-
method: "GET",
|
|
20
|
-
headers: {
|
|
21
|
-
"Content-Type": "application/json",
|
|
22
|
-
Authorization: `Bearer ${authToken}`
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
if (!projectsResponse.ok) {
|
|
26
|
-
logger.error({
|
|
27
|
-
status: projectsResponse.status,
|
|
28
|
-
tenantId
|
|
29
|
-
}, "Failed to fetch projects from manage API");
|
|
30
|
-
return [];
|
|
31
|
-
}
|
|
32
|
-
const projectsData = await projectsResponse.json();
|
|
33
|
-
const projects = projectsData.data || projectsData || [];
|
|
34
|
-
logger.info({
|
|
35
|
-
projectCount: projects.length,
|
|
36
|
-
tenantId
|
|
37
|
-
}, "Fetched projects from manage API");
|
|
38
|
-
return (await Promise.all(projects.map(async (project) => {
|
|
39
|
-
try {
|
|
40
|
-
const agentsResponse = await fetch(`${apiBaseUrl}/manage/tenants/${tenantId}/projects/${project.id}/agents`, {
|
|
41
|
-
method: "GET",
|
|
42
|
-
headers: {
|
|
43
|
-
"Content-Type": "application/json",
|
|
44
|
-
Authorization: `Bearer ${authToken}`
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
if (agentsResponse.ok) {
|
|
48
|
-
const agentsData = await agentsResponse.json();
|
|
49
|
-
return (agentsData.data || agentsData || []).map((agent) => ({
|
|
50
|
-
id: agent.id,
|
|
51
|
-
name: agent.name,
|
|
52
|
-
projectId: project.id,
|
|
53
|
-
projectName: project.name
|
|
54
|
-
}));
|
|
55
|
-
}
|
|
56
|
-
return [];
|
|
57
|
-
} catch (error) {
|
|
58
|
-
logger.error({
|
|
59
|
-
error,
|
|
60
|
-
projectId: project.id
|
|
61
|
-
}, "Failed to fetch agents for project");
|
|
62
|
-
return [];
|
|
63
|
-
}
|
|
64
|
-
}))).flat();
|
|
65
|
-
} catch (error) {
|
|
66
|
-
logger.error({
|
|
67
|
-
error,
|
|
68
|
-
tenantId
|
|
69
|
-
}, "Failed to fetch agents from manage API");
|
|
70
|
-
return [];
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Find an agent by name or ID from the manage API.
|
|
75
|
-
*/
|
|
76
|
-
async function findAgentByIdentifier(tenantId, identifier, authToken) {
|
|
77
|
-
return (await fetchAgentsFromManageApi(tenantId, authToken)).find((a) => a.id === identifier || a.name?.toLowerCase() === identifier.toLowerCase()) || null;
|
|
78
|
-
}
|
|
79
|
-
const DEFAULT_CLIENT_ID = "work-apps-slack";
|
|
80
|
-
const LINK_CODE_TTL_MINUTES = 10;
|
|
81
|
-
const logger = getLogger("slack-commands");
|
|
82
|
-
/**
|
|
83
|
-
* Parse agent name and question from command text.
|
|
84
|
-
* Agent name must be in quotes: "agent name" question
|
|
85
|
-
*/
|
|
86
|
-
function parseAgentAndQuestion(text) {
|
|
87
|
-
if (!text.trim()) return {
|
|
88
|
-
agentName: null,
|
|
89
|
-
question: null
|
|
90
|
-
};
|
|
91
|
-
const quotedMatch = text.match(/^["']([^"']+)["']\s+(.+)$/);
|
|
92
|
-
if (quotedMatch) return {
|
|
93
|
-
agentName: quotedMatch[1].trim(),
|
|
94
|
-
question: quotedMatch[2].trim()
|
|
95
|
-
};
|
|
96
|
-
return {
|
|
97
|
-
agentName: null,
|
|
98
|
-
question: null
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
async function handleLinkCommand(payload, dashboardUrl, tenantId) {
|
|
102
|
-
const existingLink = await findWorkAppSlackUserMapping(runDbClient_default)(tenantId, payload.userId, payload.teamId, DEFAULT_CLIENT_ID);
|
|
103
|
-
if (existingLink) return {
|
|
104
|
-
response_type: "ephemeral",
|
|
105
|
-
...createAlreadyLinkedMessage(existingLink.slackEmail || existingLink.slackUsername || "Unknown", existingLink.linkedAt, dashboardUrl)
|
|
106
|
-
};
|
|
107
|
-
try {
|
|
108
|
-
const linkToken = await signSlackLinkToken({
|
|
109
|
-
tenantId,
|
|
110
|
-
slackTeamId: payload.teamId,
|
|
111
|
-
slackUserId: payload.userId,
|
|
112
|
-
slackEnterpriseId: payload.enterpriseId,
|
|
113
|
-
slackUsername: payload.userName
|
|
114
|
-
});
|
|
115
|
-
const linkUrl = `${env.INKEEP_AGENTS_MANAGE_UI_URL || "http://localhost:3000"}/link?token=${encodeURIComponent(linkToken)}`;
|
|
116
|
-
logger.info({
|
|
117
|
-
slackUserId: payload.userId,
|
|
118
|
-
tenantId
|
|
119
|
-
}, "Generated JWT link token");
|
|
120
|
-
return {
|
|
121
|
-
response_type: "ephemeral",
|
|
122
|
-
...createJwtLinkMessage(linkUrl, LINK_CODE_TTL_MINUTES)
|
|
123
|
-
};
|
|
124
|
-
} catch (error) {
|
|
125
|
-
logger.error({
|
|
126
|
-
error,
|
|
127
|
-
slackUserId: payload.userId,
|
|
128
|
-
tenantId
|
|
129
|
-
}, "Failed to generate link token");
|
|
130
|
-
return {
|
|
131
|
-
response_type: "ephemeral",
|
|
132
|
-
...createErrorMessage("Failed to generate link. Please try again.")
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
async function handleUnlinkCommand(payload, tenantId) {
|
|
137
|
-
if (!await findWorkAppSlackUserMapping(runDbClient_default)(tenantId, payload.userId, payload.teamId, DEFAULT_CLIENT_ID)) return {
|
|
138
|
-
response_type: "ephemeral",
|
|
139
|
-
...createNotLinkedMessage()
|
|
140
|
-
};
|
|
141
|
-
try {
|
|
142
|
-
if (await deleteWorkAppSlackUserMapping(runDbClient_default)(tenantId, payload.userId, payload.teamId, DEFAULT_CLIENT_ID)) {
|
|
143
|
-
logger.info({
|
|
144
|
-
slackUserId: payload.userId,
|
|
145
|
-
tenantId
|
|
146
|
-
}, "User unlinked Slack account");
|
|
147
|
-
return {
|
|
148
|
-
response_type: "ephemeral",
|
|
149
|
-
...createUnlinkSuccessMessage()
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
return {
|
|
153
|
-
response_type: "ephemeral",
|
|
154
|
-
...createErrorMessage("Failed to unlink account. Please try again.")
|
|
155
|
-
};
|
|
156
|
-
} catch (error) {
|
|
157
|
-
logger.error({
|
|
158
|
-
error,
|
|
159
|
-
slackUserId: payload.userId,
|
|
160
|
-
tenantId
|
|
161
|
-
}, "Failed to unlink account");
|
|
162
|
-
return {
|
|
163
|
-
response_type: "ephemeral",
|
|
164
|
-
...createErrorMessage("Failed to unlink account. Please try again.")
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
async function handleStatusCommand(payload, dashboardUrl, tenantId) {
|
|
169
|
-
const existingLink = await findWorkAppSlackUserMapping(runDbClient_default)(tenantId, payload.userId, payload.teamId, DEFAULT_CLIENT_ID);
|
|
170
|
-
if (existingLink) {
|
|
171
|
-
const { getAgentConfigSources } = await import("../agent-resolution.js");
|
|
172
|
-
const agentConfigs = await getAgentConfigSources({
|
|
173
|
-
tenantId,
|
|
174
|
-
teamId: payload.teamId,
|
|
175
|
-
channelId: payload.channelId,
|
|
176
|
-
userId: payload.userId
|
|
177
|
-
});
|
|
178
|
-
return {
|
|
179
|
-
response_type: "ephemeral",
|
|
180
|
-
...createStatusMessage(existingLink.slackEmail || existingLink.slackUsername || payload.userName, existingLink.linkedAt, dashboardUrl, agentConfigs)
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
response_type: "ephemeral",
|
|
185
|
-
...createNotLinkedMessage()
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
async function handleLogoutCommand(payload, tenantId) {
|
|
189
|
-
return handleUnlinkCommand(payload, tenantId);
|
|
190
|
-
}
|
|
191
|
-
async function handleHelpCommand() {
|
|
192
|
-
return {
|
|
193
|
-
response_type: "ephemeral",
|
|
194
|
-
...createUpdatedHelpMessage()
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
async function generateLinkCodeWithIntent(payload, tenantId) {
|
|
198
|
-
try {
|
|
199
|
-
const linkToken = await signSlackLinkToken({
|
|
200
|
-
tenantId,
|
|
201
|
-
slackTeamId: payload.teamId,
|
|
202
|
-
slackUserId: payload.userId,
|
|
203
|
-
slackEnterpriseId: payload.enterpriseId,
|
|
204
|
-
slackUsername: payload.userName
|
|
205
|
-
});
|
|
206
|
-
const linkUrl = `${env.INKEEP_AGENTS_MANAGE_UI_URL || "http://localhost:3000"}/link?token=${encodeURIComponent(linkToken)}`;
|
|
207
|
-
logger.info({
|
|
208
|
-
slackUserId: payload.userId,
|
|
209
|
-
tenantId
|
|
210
|
-
}, "Generated JWT link token with intent");
|
|
211
|
-
return {
|
|
212
|
-
response_type: "ephemeral",
|
|
213
|
-
...createJwtLinkMessage(linkUrl, LINK_CODE_TTL_MINUTES)
|
|
214
|
-
};
|
|
215
|
-
} catch (error) {
|
|
216
|
-
logger.error({
|
|
217
|
-
error,
|
|
218
|
-
slackUserId: payload.userId,
|
|
219
|
-
tenantId
|
|
220
|
-
}, "Failed to generate link token");
|
|
221
|
-
return {
|
|
222
|
-
response_type: "ephemeral",
|
|
223
|
-
...createErrorMessage("Failed to generate link. Please try again.")
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
async function handleQuestionCommand(payload, question, _dashboardUrl, tenantId) {
|
|
228
|
-
const existingLink = await findWorkAppSlackUserMappingBySlackUser(runDbClient_default)(payload.userId, payload.teamId, DEFAULT_CLIENT_ID);
|
|
229
|
-
if (!existingLink) return generateLinkCodeWithIntent(payload, tenantId);
|
|
230
|
-
const userTenantId = existingLink.tenantId;
|
|
231
|
-
const resolvedAgent = await resolveEffectiveAgent({
|
|
232
|
-
tenantId: userTenantId,
|
|
233
|
-
teamId: payload.teamId,
|
|
234
|
-
channelId: payload.channelId,
|
|
235
|
-
userId: payload.userId
|
|
236
|
-
});
|
|
237
|
-
if (!resolvedAgent) return {
|
|
238
|
-
response_type: "ephemeral",
|
|
239
|
-
...createErrorMessage("No default agent configured. Ask your admin to set a workspace default, or use `/inkeep settings set [agent]` to set your personal default.\n\nUse `/inkeep list` to see available agents.")
|
|
240
|
-
};
|
|
241
|
-
executeAgentInBackground(payload, existingLink, {
|
|
242
|
-
id: resolvedAgent.agentId,
|
|
243
|
-
name: resolvedAgent.agentName || null,
|
|
244
|
-
projectId: resolvedAgent.projectId
|
|
245
|
-
}, question, userTenantId).catch((error) => {
|
|
246
|
-
logger.error({ error }, "Background execution promise rejected");
|
|
247
|
-
});
|
|
248
|
-
return {};
|
|
249
|
-
}
|
|
250
|
-
async function executeAgentInBackground(payload, existingLink, targetAgent, question, tenantId) {
|
|
251
|
-
try {
|
|
252
|
-
const slackUserToken = await signSlackUserToken({
|
|
253
|
-
inkeepUserId: existingLink.inkeepUserId,
|
|
254
|
-
tenantId,
|
|
255
|
-
slackTeamId: payload.teamId,
|
|
256
|
-
slackUserId: payload.userId,
|
|
257
|
-
slackEnterpriseId: payload.enterpriseId
|
|
258
|
-
});
|
|
259
|
-
const apiBaseUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
|
|
260
|
-
const response = await fetch(`${apiBaseUrl}/run/api/chat`, {
|
|
261
|
-
method: "POST",
|
|
262
|
-
headers: {
|
|
263
|
-
"Content-Type": "application/json",
|
|
264
|
-
Authorization: `Bearer ${slackUserToken}`,
|
|
265
|
-
"x-inkeep-project-id": targetAgent.projectId,
|
|
266
|
-
"x-inkeep-agent-id": targetAgent.id
|
|
267
|
-
},
|
|
268
|
-
body: JSON.stringify({
|
|
269
|
-
messages: [{
|
|
270
|
-
role: "user",
|
|
271
|
-
content: question
|
|
272
|
-
}],
|
|
273
|
-
stream: false
|
|
274
|
-
})
|
|
275
|
-
});
|
|
276
|
-
let responsePayload;
|
|
277
|
-
if (!response.ok) {
|
|
278
|
-
const errorText = await response.text();
|
|
279
|
-
logger.error({
|
|
280
|
-
status: response.status,
|
|
281
|
-
error: errorText,
|
|
282
|
-
agentId: targetAgent.id,
|
|
283
|
-
projectId: targetAgent.projectId
|
|
284
|
-
}, "Run API call failed");
|
|
285
|
-
responsePayload = {
|
|
286
|
-
response_type: "ephemeral",
|
|
287
|
-
text: `Failed to run agent: ${response.status} ${response.statusText}`
|
|
288
|
-
};
|
|
289
|
-
} else {
|
|
290
|
-
const result = await response.json();
|
|
291
|
-
const assistantMessage = result.choices?.[0]?.message?.content || result.message?.content || "No response received";
|
|
292
|
-
logger.info({
|
|
293
|
-
slackUserId: payload.userId,
|
|
294
|
-
agentId: targetAgent.id,
|
|
295
|
-
projectId: targetAgent.projectId,
|
|
296
|
-
tenantId
|
|
297
|
-
}, "Agent execution completed via Slack");
|
|
298
|
-
responsePayload = {
|
|
299
|
-
response_type: "ephemeral",
|
|
300
|
-
blocks: [{
|
|
301
|
-
type: "section",
|
|
302
|
-
text: {
|
|
303
|
-
type: "mrkdwn",
|
|
304
|
-
text: assistantMessage
|
|
305
|
-
}
|
|
306
|
-
}, {
|
|
307
|
-
type: "context",
|
|
308
|
-
elements: [{
|
|
309
|
-
type: "mrkdwn",
|
|
310
|
-
text: `Powered by *${targetAgent.name || targetAgent.id}* via Inkeep`
|
|
311
|
-
}]
|
|
312
|
-
}]
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
await fetch(payload.responseUrl, {
|
|
316
|
-
method: "POST",
|
|
317
|
-
headers: { "Content-Type": "application/json" },
|
|
318
|
-
body: JSON.stringify(responsePayload)
|
|
319
|
-
});
|
|
320
|
-
} catch (error) {
|
|
321
|
-
logger.error({
|
|
322
|
-
error,
|
|
323
|
-
slackUserId: payload.userId
|
|
324
|
-
}, "Background agent execution failed");
|
|
325
|
-
try {
|
|
326
|
-
await fetch(payload.responseUrl, {
|
|
327
|
-
method: "POST",
|
|
328
|
-
headers: { "Content-Type": "application/json" },
|
|
329
|
-
body: JSON.stringify({
|
|
330
|
-
response_type: "ephemeral",
|
|
331
|
-
text: "An error occurred while running the agent. Please try again."
|
|
332
|
-
})
|
|
333
|
-
});
|
|
334
|
-
} catch {
|
|
335
|
-
logger.error({ slackUserId: payload.userId }, "Failed to send error response to Slack");
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
async function handleRunCommand(payload, agentIdentifier, question, _dashboardUrl, tenantId) {
|
|
340
|
-
const existingLink = await findWorkAppSlackUserMappingBySlackUser(runDbClient_default)(payload.userId, payload.teamId, DEFAULT_CLIENT_ID);
|
|
341
|
-
if (!existingLink) return generateLinkCodeWithIntent(payload, tenantId);
|
|
342
|
-
const userTenantId = existingLink.tenantId;
|
|
343
|
-
try {
|
|
344
|
-
const targetAgent = await findAgentByIdentifier(userTenantId, agentIdentifier, await signSlackUserToken({
|
|
345
|
-
inkeepUserId: existingLink.inkeepUserId,
|
|
346
|
-
tenantId: userTenantId,
|
|
347
|
-
slackTeamId: payload.teamId,
|
|
348
|
-
slackUserId: payload.userId,
|
|
349
|
-
slackEnterpriseId: payload.enterpriseId
|
|
350
|
-
}));
|
|
351
|
-
if (!targetAgent) return {
|
|
352
|
-
response_type: "ephemeral",
|
|
353
|
-
...createErrorMessage(`Agent "${agentIdentifier}" not found. Use \`/inkeep list\` to see available agents.`)
|
|
354
|
-
};
|
|
355
|
-
executeAgentInBackground(payload, existingLink, targetAgent, question, userTenantId).catch((error) => {
|
|
356
|
-
logger.error({ error }, "Background execution promise rejected");
|
|
357
|
-
});
|
|
358
|
-
return {};
|
|
359
|
-
} catch (error) {
|
|
360
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
361
|
-
logger.error({
|
|
362
|
-
error: errorMessage,
|
|
363
|
-
tenantId: userTenantId
|
|
364
|
-
}, "Failed to run agent");
|
|
365
|
-
return {
|
|
366
|
-
response_type: "ephemeral",
|
|
367
|
-
...createErrorMessage("Failed to run agent. Please try again or visit the dashboard.")
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
async function handleSettingsCommand(payload, subCommand, agentIdentifier, dashboardUrl, _tenantId) {
|
|
372
|
-
const existingLink = await findWorkAppSlackUserMappingBySlackUser(runDbClient_default)(payload.userId, payload.teamId, DEFAULT_CLIENT_ID);
|
|
373
|
-
if (!existingLink) return {
|
|
374
|
-
response_type: "ephemeral",
|
|
375
|
-
...createNotLinkedMessage()
|
|
376
|
-
};
|
|
377
|
-
const userTenantId = existingLink.tenantId;
|
|
378
|
-
if (subCommand === "set" && agentIdentifier) try {
|
|
379
|
-
const targetAgent = await findAgentByIdentifier(userTenantId, agentIdentifier, await signSlackUserToken({
|
|
380
|
-
inkeepUserId: existingLink.inkeepUserId,
|
|
381
|
-
tenantId: userTenantId,
|
|
382
|
-
slackTeamId: payload.teamId,
|
|
383
|
-
slackUserId: payload.userId,
|
|
384
|
-
slackEnterpriseId: payload.enterpriseId
|
|
385
|
-
}));
|
|
386
|
-
if (!targetAgent) return {
|
|
387
|
-
response_type: "ephemeral",
|
|
388
|
-
...createErrorMessage(`Agent "${agentIdentifier}" not found. Use \`/inkeep list\` to see available agents.`)
|
|
389
|
-
};
|
|
390
|
-
await upsertWorkAppSlackUserSettings(runDbClient_default)({
|
|
391
|
-
tenantId: userTenantId,
|
|
392
|
-
slackTeamId: payload.teamId,
|
|
393
|
-
slackUserId: payload.userId,
|
|
394
|
-
defaultProjectId: targetAgent.projectId,
|
|
395
|
-
defaultAgentId: targetAgent.id,
|
|
396
|
-
defaultAgentName: targetAgent.name
|
|
397
|
-
});
|
|
398
|
-
logger.info({
|
|
399
|
-
slackUserId: payload.userId,
|
|
400
|
-
tenantId: userTenantId,
|
|
401
|
-
agentId: targetAgent.id,
|
|
402
|
-
agentName: targetAgent.name
|
|
403
|
-
}, "User set personal default agent");
|
|
404
|
-
return {
|
|
405
|
-
response_type: "ephemeral",
|
|
406
|
-
...createSettingsUpdatedMessage(targetAgent.name || targetAgent.id)
|
|
407
|
-
};
|
|
408
|
-
} catch (error) {
|
|
409
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
410
|
-
logger.error({
|
|
411
|
-
error: errorMessage,
|
|
412
|
-
tenantId: userTenantId
|
|
413
|
-
}, "Failed to update user settings");
|
|
414
|
-
return {
|
|
415
|
-
response_type: "ephemeral",
|
|
416
|
-
...createErrorMessage("Failed to update settings. Please try again.")
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
if (subCommand === "clear") try {
|
|
420
|
-
await upsertWorkAppSlackUserSettings(runDbClient_default)({
|
|
421
|
-
tenantId: userTenantId,
|
|
422
|
-
slackTeamId: payload.teamId,
|
|
423
|
-
slackUserId: payload.userId,
|
|
424
|
-
defaultProjectId: void 0,
|
|
425
|
-
defaultAgentId: void 0,
|
|
426
|
-
defaultAgentName: void 0
|
|
427
|
-
});
|
|
428
|
-
logger.info({
|
|
429
|
-
slackUserId: payload.userId,
|
|
430
|
-
tenantId: userTenantId
|
|
431
|
-
}, "User cleared personal default agent");
|
|
432
|
-
return {
|
|
433
|
-
response_type: "ephemeral",
|
|
434
|
-
blocks: [{
|
|
435
|
-
type: "section",
|
|
436
|
-
text: {
|
|
437
|
-
type: "mrkdwn",
|
|
438
|
-
text: "✅ *Personal default agent cleared*\n\nYou will now use the workspace or channel default."
|
|
439
|
-
}
|
|
440
|
-
}]
|
|
441
|
-
};
|
|
442
|
-
} catch (error) {
|
|
443
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
444
|
-
logger.error({
|
|
445
|
-
error: errorMessage,
|
|
446
|
-
tenantId: userTenantId
|
|
447
|
-
}, "Failed to clear user settings");
|
|
448
|
-
return {
|
|
449
|
-
response_type: "ephemeral",
|
|
450
|
-
...createErrorMessage("Failed to clear settings. Please try again.")
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
return {
|
|
454
|
-
response_type: "ephemeral",
|
|
455
|
-
...createSettingsMessage(await resolveEffectiveAgent({
|
|
456
|
-
tenantId: userTenantId,
|
|
457
|
-
teamId: payload.teamId,
|
|
458
|
-
channelId: payload.channelId,
|
|
459
|
-
userId: payload.userId
|
|
460
|
-
}), dashboardUrl)
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
async function handleAgentListCommand(payload, dashboardUrl, _tenantId) {
|
|
464
|
-
const existingLink = await findWorkAppSlackUserMappingBySlackUser(runDbClient_default)(payload.userId, payload.teamId, DEFAULT_CLIENT_ID);
|
|
465
|
-
if (!existingLink) return {
|
|
466
|
-
response_type: "ephemeral",
|
|
467
|
-
...createNotLinkedMessage()
|
|
468
|
-
};
|
|
469
|
-
const userTenantId = existingLink.tenantId;
|
|
470
|
-
logger.info({
|
|
471
|
-
slackUserId: payload.userId,
|
|
472
|
-
existingLinkTenantId: existingLink.tenantId,
|
|
473
|
-
existingLinkInkeepUserId: existingLink.inkeepUserId
|
|
474
|
-
}, "Found user mapping for list command");
|
|
475
|
-
try {
|
|
476
|
-
const allAgents = await fetchAgentsFromManageApi(userTenantId, await signSlackUserToken({
|
|
477
|
-
inkeepUserId: existingLink.inkeepUserId,
|
|
478
|
-
tenantId: userTenantId,
|
|
479
|
-
slackTeamId: payload.teamId,
|
|
480
|
-
slackUserId: payload.userId,
|
|
481
|
-
slackEnterpriseId: payload.enterpriseId
|
|
482
|
-
}));
|
|
483
|
-
logger.info({
|
|
484
|
-
slackUserId: payload.userId,
|
|
485
|
-
tenantId: userTenantId,
|
|
486
|
-
agentCount: allAgents.length
|
|
487
|
-
}, "Listed agents for linked Slack user");
|
|
488
|
-
if (allAgents.length === 0) return {
|
|
489
|
-
response_type: "ephemeral",
|
|
490
|
-
...createErrorMessage("No agents found. Create an agent in the Inkeep dashboard first.")
|
|
491
|
-
};
|
|
492
|
-
return {
|
|
493
|
-
response_type: "ephemeral",
|
|
494
|
-
...createAgentListMessage(allAgents, dashboardUrl.replace("/work-apps/slack", ""))
|
|
495
|
-
};
|
|
496
|
-
} catch (error) {
|
|
497
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
498
|
-
logger.error({
|
|
499
|
-
error: errorMessage,
|
|
500
|
-
tenantId: userTenantId
|
|
501
|
-
}, "Failed to list agents");
|
|
502
|
-
return {
|
|
503
|
-
response_type: "ephemeral",
|
|
504
|
-
...createErrorMessage("Failed to list agents. Please try again or visit the dashboard.")
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
async function handleCommand(payload) {
|
|
509
|
-
const text = payload.text.trim();
|
|
510
|
-
const parts = text.split(/\s+/);
|
|
511
|
-
const subcommand = parts[0]?.toLowerCase() || "";
|
|
512
|
-
const manageUiUrl = env.INKEEP_AGENTS_MANAGE_UI_URL || "http://localhost:3000";
|
|
513
|
-
const tenantId = (await findWorkspaceConnectionByTeamId(payload.teamId))?.tenantId || "default";
|
|
514
|
-
const dashboardUrl = `${manageUiUrl}/${tenantId}/work-apps/slack`;
|
|
515
|
-
logger.info({
|
|
516
|
-
command: payload.command,
|
|
517
|
-
subcommand,
|
|
518
|
-
slackUserId: payload.userId,
|
|
519
|
-
teamId: payload.teamId,
|
|
520
|
-
tenantId
|
|
521
|
-
}, "Slack command received");
|
|
522
|
-
switch (subcommand) {
|
|
523
|
-
case "link":
|
|
524
|
-
case "connect": return handleLinkCommand(payload, dashboardUrl, tenantId);
|
|
525
|
-
case "status": return handleStatusCommand(payload, dashboardUrl, tenantId);
|
|
526
|
-
case "unlink":
|
|
527
|
-
case "logout":
|
|
528
|
-
case "disconnect": return handleUnlinkCommand(payload, tenantId);
|
|
529
|
-
case "list": return handleAgentListCommand(payload, dashboardUrl, tenantId);
|
|
530
|
-
case "run": {
|
|
531
|
-
const parsed = parseAgentAndQuestion(text.slice(4).trim());
|
|
532
|
-
if (!parsed.agentName || !parsed.question) return {
|
|
533
|
-
response_type: "ephemeral",
|
|
534
|
-
...createErrorMessage("Usage: `/inkeep run \"agent name\" [question]`\n\nExample: `/inkeep run \"my agent\" What is the weather?`\n\nAgent name must be in quotes.")
|
|
535
|
-
};
|
|
536
|
-
return handleRunCommand(payload, parsed.agentName, parsed.question, dashboardUrl, tenantId);
|
|
537
|
-
}
|
|
538
|
-
case "settings": {
|
|
539
|
-
const settingsSubcommand = parts[1]?.toLowerCase();
|
|
540
|
-
let agentName;
|
|
541
|
-
if (settingsSubcommand === "set") {
|
|
542
|
-
const quotedMatch = text.match(/^settings\s+set\s+["']([^"']+)["']/i);
|
|
543
|
-
if (quotedMatch) agentName = quotedMatch[1].trim();
|
|
544
|
-
}
|
|
545
|
-
return handleSettingsCommand(payload, settingsSubcommand, agentName, dashboardUrl, tenantId);
|
|
546
|
-
}
|
|
547
|
-
case "help":
|
|
548
|
-
case "":
|
|
549
|
-
if (text === "" || text === "help") return handleHelpCommand();
|
|
550
|
-
return handleQuestionCommand(payload, text, dashboardUrl, tenantId);
|
|
551
|
-
default: return handleQuestionCommand(payload, text, dashboardUrl, tenantId);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
//#endregion
|
|
556
|
-
export { handleAgentListCommand, handleCommand, handleHelpCommand, handleLinkCommand, handleLogoutCommand, handleQuestionCommand, handleRunCommand, handleSettingsCommand, handleStatusCommand, handleUnlinkCommand };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
//#region src/slack/services/events/app-mention.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Handler for Slack @mention events
|
|
4
|
-
*
|
|
5
|
-
* Flow:
|
|
6
|
-
* 1. Resolve agent config (channel override > workspace default)
|
|
7
|
-
* 2. If no agent configured → prompt to set up in dashboard
|
|
8
|
-
* 3. Check if user is linked to Inkeep
|
|
9
|
-
* 4. If not linked → prompt to link account
|
|
10
|
-
* 5. Handle based on context:
|
|
11
|
-
* - Channel + no query → Show welcome/help message
|
|
12
|
-
* - Channel + query → Execute agent with streaming response
|
|
13
|
-
* - Thread + no query → Show modal to select agent
|
|
14
|
-
* - Thread + query → Execute agent with thread context included
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* Metadata passed to the agent selector modal via button value
|
|
18
|
-
*/
|
|
19
|
-
interface InlineSelectorMetadata {
|
|
20
|
-
channel: string;
|
|
21
|
-
threadTs: string;
|
|
22
|
-
messageTs: string;
|
|
23
|
-
teamId: string;
|
|
24
|
-
slackUserId: string;
|
|
25
|
-
tenantId: string;
|
|
26
|
-
threadMessageCount: number;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Main handler for @mention events in Slack
|
|
30
|
-
*/
|
|
31
|
-
declare function handleAppMention(params: {
|
|
32
|
-
slackUserId: string;
|
|
33
|
-
channel: string;
|
|
34
|
-
text: string;
|
|
35
|
-
threadTs: string;
|
|
36
|
-
messageTs: string;
|
|
37
|
-
teamId: string;
|
|
38
|
-
triggerId?: string;
|
|
39
|
-
}): Promise<void>;
|
|
40
|
-
//#endregion
|
|
41
|
-
export { InlineSelectorMetadata, handleAppMention };
|