@inkeep/agents-work-apps 0.50.1 → 0.50.4
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/_virtual/rolldown_runtime.js +32 -0
- package/dist/env.d.ts +4 -2
- package/dist/env.js +2 -1
- 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/node_modules/.pnpm/@slack_logger@4.0.0/node_modules/@slack/logger/dist/index.js +89 -0
- package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/package.js +85 -0
- package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.js +223 -0
- package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/SocketModeClient.js +367 -0
- package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/UnrecoverableSocketModeStartError.js +20 -0
- package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/errors.js +71 -0
- package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/index.js +44 -0
- package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/logger.js +32 -0
- package/dist/node_modules/.pnpm/eventemitter3@5.0.1/node_modules/eventemitter3/index.js +241 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/index.js +23 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js +107 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js +29 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js +226 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js +150 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js +57 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js +342 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js +457 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js +505 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js +123 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js +46 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js +203 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js +385 -0
- package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js +985 -0
- package/dist/slack/dispatcher.d.ts +16 -0
- package/dist/slack/dispatcher.js +335 -0
- package/dist/slack/i18n/strings.d.ts +5 -5
- package/dist/slack/i18n/strings.js +9 -9
- package/dist/slack/index.d.ts +3 -1
- package/dist/slack/index.js +4 -2
- package/dist/slack/middleware/permissions.js +120 -107
- package/dist/slack/routes/events.js +10 -328
- package/dist/slack/routes/oauth.js +6 -3
- package/dist/slack/routes/users.js +12 -6
- package/dist/slack/routes/workspaces.js +39 -39
- package/dist/slack/services/agent-resolution.d.ts +1 -0
- package/dist/slack/services/agent-resolution.js +8 -4
- package/dist/slack/services/blocks/index.js +7 -11
- package/dist/slack/services/commands/index.js +15 -7
- package/dist/slack/services/dev-config.d.ts +23 -0
- package/dist/slack/services/dev-config.js +91 -0
- package/dist/slack/services/events/app-mention.js +25 -21
- package/dist/slack/services/events/index.d.ts +2 -2
- package/dist/slack/services/events/index.js +2 -2
- package/dist/slack/services/events/modal-submission.js +18 -10
- package/dist/slack/services/events/streaming.js +7 -5
- package/dist/slack/services/events/utils.d.ts +2 -1
- package/dist/slack/services/events/utils.js +16 -9
- package/dist/slack/services/index.d.ts +2 -2
- package/dist/slack/services/index.js +3 -3
- package/dist/slack/services/modals.js +4 -4
- package/dist/slack/services/nango.d.ts +3 -0
- package/dist/slack/services/nango.js +84 -2
- package/dist/slack/socket-mode.d.ts +4 -0
- package/dist/slack/socket-mode.js +130 -0
- package/dist/slack/tracer.d.ts +2 -0
- package/dist/slack/tracer.js +3 -1
- package/package.json +3 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { env } from "../../../env.js";
|
|
2
2
|
import { getLogger } from "../../../logger.js";
|
|
3
3
|
import { findWorkspaceConnectionByTeamId } from "../nango.js";
|
|
4
|
+
import { resolveEffectiveAgent } from "../agent-resolution.js";
|
|
4
5
|
import { SlackStrings } from "../../i18n/strings.js";
|
|
5
6
|
import { getSlackChannelInfo, getSlackClient, getSlackUserInfo, postMessageInThread } from "../client.js";
|
|
6
|
-
import { checkIfBotThread, classifyError, findCachedUserMapping, formatChannelContext, generateSlackConversationId, getThreadContext, getUserFriendlyErrorMessage,
|
|
7
|
+
import { checkIfBotThread, classifyError, findCachedUserMapping, formatChannelContext, generateSlackConversationId, getThreadContext, getUserFriendlyErrorMessage, timedOp } from "./utils.js";
|
|
7
8
|
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
8
|
-
import { getBotTokenForTeam } from "../workspace-tokens.js";
|
|
9
9
|
import { streamAgentResponse } from "./streaming.js";
|
|
10
10
|
import { signSlackUserToken } from "@inkeep/agents-core";
|
|
11
11
|
|
|
@@ -60,19 +60,18 @@ async function handleAppMention(params) {
|
|
|
60
60
|
label: "workspace connection lookup",
|
|
61
61
|
context: { teamId }
|
|
62
62
|
});
|
|
63
|
-
|
|
64
|
-
if (!botToken) {
|
|
63
|
+
if (!workspaceConnection?.botToken) {
|
|
65
64
|
logger.error({ teamId }, "No bot token available — cannot respond to @mention");
|
|
66
65
|
span.end();
|
|
67
66
|
return;
|
|
68
67
|
}
|
|
69
|
-
const tenantId = workspaceConnection
|
|
68
|
+
const { botToken, tenantId } = workspaceConnection;
|
|
70
69
|
if (!tenantId) {
|
|
71
70
|
logger.error({ teamId }, "Workspace connection has no tenantId — workspace may need reinstall");
|
|
72
71
|
await getSlackClient(botToken).chat.postEphemeral({
|
|
73
72
|
channel,
|
|
74
73
|
user: slackUserId,
|
|
75
|
-
text: "
|
|
74
|
+
text: "This workspace is not properly configured. Please reinstall the Slack app from the Inkeep dashboard."
|
|
76
75
|
}).catch((e) => logger.warn({
|
|
77
76
|
error: e,
|
|
78
77
|
channel
|
|
@@ -88,7 +87,11 @@ async function handleAppMention(params) {
|
|
|
88
87
|
const hasQuery = Boolean(text && text.trim().length > 0);
|
|
89
88
|
let thinkingMessageTs;
|
|
90
89
|
try {
|
|
91
|
-
const { result: [agentConfig, existingLink] } = await timedOp(Promise.all([
|
|
90
|
+
const { result: [agentConfig, existingLink] } = await timedOp(Promise.all([resolveEffectiveAgent({
|
|
91
|
+
tenantId,
|
|
92
|
+
teamId,
|
|
93
|
+
channelId: channel
|
|
94
|
+
}), findCachedUserMapping(tenantId, slackUserId, teamId)]), {
|
|
92
95
|
label: "agent config / user mapping lookup",
|
|
93
96
|
context: {
|
|
94
97
|
teamId,
|
|
@@ -104,13 +107,15 @@ async function handleAppMention(params) {
|
|
|
104
107
|
channel,
|
|
105
108
|
user: slackUserId,
|
|
106
109
|
thread_ts: isInThread ? threadTs : void 0,
|
|
107
|
-
text:
|
|
110
|
+
text: `No agents configured for this workspace. *<${dashboardUrl}|Set up agents in the dashboard>*`
|
|
108
111
|
});
|
|
109
112
|
span.end();
|
|
110
113
|
return;
|
|
111
114
|
}
|
|
112
115
|
span.setAttribute(SLACK_SPAN_KEYS.AGENT_ID, agentConfig.agentId);
|
|
113
116
|
span.setAttribute(SLACK_SPAN_KEYS.PROJECT_ID, agentConfig.projectId);
|
|
117
|
+
span.setAttribute(SLACK_SPAN_KEYS.AUTHORIZED, agentConfig.grantAccessToMembers);
|
|
118
|
+
span.setAttribute(SLACK_SPAN_KEYS.AUTH_SOURCE, agentConfig.source);
|
|
114
119
|
const agentDisplayName = agentConfig.agentName || agentConfig.agentId;
|
|
115
120
|
if (!existingLink) {
|
|
116
121
|
logger.info({
|
|
@@ -122,11 +127,7 @@ async function handleAppMention(params) {
|
|
|
122
127
|
channel,
|
|
123
128
|
user: slackUserId,
|
|
124
129
|
thread_ts: isInThread ? threadTs : void 0,
|
|
125
|
-
text:
|
|
126
|
-
|
|
127
|
-
Run \`/inkeep link\` to connect your Slack and Inkeep accounts.
|
|
128
|
-
|
|
129
|
-
This workspace uses: *${agentDisplayName}*`
|
|
130
|
+
text: "*Link your account to use @Inkeep*\n\nRun `/inkeep link` to connect your Slack and Inkeep accounts."
|
|
130
131
|
});
|
|
131
132
|
span.end();
|
|
132
133
|
return;
|
|
@@ -162,12 +163,7 @@ This workspace uses: *${agentDisplayName}*`
|
|
|
162
163
|
channel,
|
|
163
164
|
user: slackUserId,
|
|
164
165
|
thread_ts: threadTs,
|
|
165
|
-
text:
|
|
166
|
-
|
|
167
|
-
Just type your follow-up — no need to mention me in this thread.
|
|
168
|
-
Or use \`@Inkeep <prompt>\` to run a new prompt.
|
|
169
|
-
|
|
170
|
-
_Using: ${agentDisplayName}_`
|
|
166
|
+
text: "*Continue the conversation*\n\nType your follow-up directly in this thread — no need to mention me.\nOr use `@Inkeep <prompt>` to start a new prompt."
|
|
171
167
|
});
|
|
172
168
|
span.end();
|
|
173
169
|
return;
|
|
@@ -191,7 +187,11 @@ _Using: ${agentDisplayName}_`
|
|
|
191
187
|
inkeepUserId: existingLink.inkeepUserId,
|
|
192
188
|
tenantId,
|
|
193
189
|
slackTeamId: teamId,
|
|
194
|
-
slackUserId
|
|
190
|
+
slackUserId,
|
|
191
|
+
slackAuthorized: agentConfig?.grantAccessToMembers ?? false,
|
|
192
|
+
slackAuthSource: agentConfig?.source === "none" ? void 0 : agentConfig?.source,
|
|
193
|
+
slackChannelId: channel,
|
|
194
|
+
slackAuthorizedProjectId: agentConfig?.projectId
|
|
195
195
|
});
|
|
196
196
|
thinkingMessageTs = (await slackClient.chat.postMessage({
|
|
197
197
|
channel,
|
|
@@ -265,7 +265,11 @@ Respond naturally as if you're joining the conversation to help.`;
|
|
|
265
265
|
inkeepUserId: existingLink.inkeepUserId,
|
|
266
266
|
tenantId,
|
|
267
267
|
slackTeamId: teamId,
|
|
268
|
-
slackUserId
|
|
268
|
+
slackUserId,
|
|
269
|
+
slackAuthorized: agentConfig?.grantAccessToMembers ?? false,
|
|
270
|
+
slackAuthSource: agentConfig?.source === "none" ? void 0 : agentConfig?.source,
|
|
271
|
+
slackChannelId: channel,
|
|
272
|
+
slackAuthorizedProjectId: agentConfig?.projectId
|
|
269
273
|
});
|
|
270
274
|
thinkingMessageTs = (await slackClient.chat.postMessage({
|
|
271
275
|
channel,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InlineSelectorMetadata, handleAppMention } from "./app-mention.js";
|
|
2
2
|
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./block-actions.js";
|
|
3
3
|
import { handleFollowUpSubmission, handleModalSubmission } from "./modal-submission.js";
|
|
4
|
-
import { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
4
|
+
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
5
5
|
import { StreamResult, streamAgentResponse } from "./streaming.js";
|
|
6
|
-
export { type InlineSelectorMetadata, SlackErrorType, type StreamResult, checkIfBotThread, classifyError, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleFollowUpSubmission, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
6
|
+
export { type InlineSelectorMetadata, SlackErrorType, type StreamResult, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleFollowUpSubmission, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
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
3
|
import { handleAppMention } from "./app-mention.js";
|
|
4
4
|
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./block-actions.js";
|
|
5
5
|
import { handleFollowUpSubmission, handleModalSubmission } from "./modal-submission.js";
|
|
6
6
|
|
|
7
|
-
export { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleFollowUpSubmission, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
7
|
+
export { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, handleAppMention, handleFollowUpSubmission, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
@@ -4,9 +4,9 @@ import { findWorkspaceConnectionByTeamId } from "../nango.js";
|
|
|
4
4
|
import { SlackStrings } from "../../i18n/strings.js";
|
|
5
5
|
import { buildConversationResponseBlocks } from "../blocks/index.js";
|
|
6
6
|
import { getSlackClient } from "../client.js";
|
|
7
|
-
import { classifyError, findCachedUserMapping, generateSlackConversationId, getThreadContext, getUserFriendlyErrorMessage, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
7
|
+
import { classifyError, extractApiErrorMessage, findCachedUserMapping, generateSlackConversationId, getThreadContext, getUserFriendlyErrorMessage, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
8
8
|
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
9
|
-
import { signSlackUserToken } from "@inkeep/agents-core";
|
|
9
|
+
import { getInProcessFetch, signSlackUserToken } from "@inkeep/agents-core";
|
|
10
10
|
|
|
11
11
|
//#region src/slack/services/events/modal-submission.ts
|
|
12
12
|
/**
|
|
@@ -29,7 +29,7 @@ async function handleModalSubmission(view) {
|
|
|
29
29
|
span.setAttribute(SLACK_SPAN_KEYS.USER_ID, metadata.slackUserId || "");
|
|
30
30
|
span.setAttribute(SLACK_SPAN_KEYS.TENANT_ID, metadata.tenantId || "");
|
|
31
31
|
const values = view.state?.values || {};
|
|
32
|
-
const agentSelectValue = values.
|
|
32
|
+
const agentSelectValue = Object.values(values).map((block) => block.agent_select).find(Boolean);
|
|
33
33
|
const questionValue = values.question_block?.question_input;
|
|
34
34
|
const includeContextValue = values.context_block?.include_context_checkbox;
|
|
35
35
|
const question = questionValue?.value || "";
|
|
@@ -54,6 +54,7 @@ async function handleModalSubmission(view) {
|
|
|
54
54
|
}
|
|
55
55
|
span.setAttribute(SLACK_SPAN_KEYS.AGENT_ID, agentId);
|
|
56
56
|
span.setAttribute(SLACK_SPAN_KEYS.PROJECT_ID, projectId);
|
|
57
|
+
span.setAttribute(SLACK_SPAN_KEYS.AUTHORIZED, false);
|
|
57
58
|
const tenantId = metadata.tenantId;
|
|
58
59
|
const [workspaceConnection, existingLink] = await Promise.all([findWorkspaceConnectionByTeamId(metadata.teamId), findCachedUserMapping(tenantId, metadata.slackUserId, metadata.teamId)]);
|
|
59
60
|
if (!workspaceConnection?.botToken) {
|
|
@@ -90,7 +91,7 @@ async function handleModalSubmission(view) {
|
|
|
90
91
|
await slackClient.chat.postEphemeral({
|
|
91
92
|
channel: metadata.channel,
|
|
92
93
|
user: metadata.slackUserId,
|
|
93
|
-
text: "
|
|
94
|
+
text: "Link your account first. Run `/inkeep link` to connect."
|
|
94
95
|
});
|
|
95
96
|
span.end();
|
|
96
97
|
return;
|
|
@@ -99,7 +100,8 @@ async function handleModalSubmission(view) {
|
|
|
99
100
|
inkeepUserId: existingLink.inkeepUserId,
|
|
100
101
|
tenantId,
|
|
101
102
|
slackTeamId: metadata.teamId,
|
|
102
|
-
slackUserId: metadata.slackUserId
|
|
103
|
+
slackUserId: metadata.slackUserId,
|
|
104
|
+
slackAuthorized: false
|
|
103
105
|
});
|
|
104
106
|
const conversationId = generateSlackConversationId({
|
|
105
107
|
teamId: metadata.teamId,
|
|
@@ -200,6 +202,7 @@ async function handleFollowUpSubmission(view) {
|
|
|
200
202
|
span.setAttribute(SLACK_SPAN_KEYS.AGENT_ID, agentId);
|
|
201
203
|
span.setAttribute(SLACK_SPAN_KEYS.PROJECT_ID, projectId);
|
|
202
204
|
span.setAttribute(SLACK_SPAN_KEYS.CONVERSATION_ID, conversationId);
|
|
205
|
+
span.setAttribute(SLACK_SPAN_KEYS.AUTHORIZED, false);
|
|
203
206
|
const [workspaceConnection, existingLink] = await Promise.all([findWorkspaceConnectionByTeamId(teamId), findCachedUserMapping(tenantId, slackUserId, teamId)]);
|
|
204
207
|
if (!workspaceConnection?.botToken) {
|
|
205
208
|
logger.error({ teamId }, "No bot token for follow-up submission");
|
|
@@ -215,7 +218,7 @@ async function handleFollowUpSubmission(view) {
|
|
|
215
218
|
await slackClient.chat.postEphemeral({
|
|
216
219
|
channel,
|
|
217
220
|
user: slackUserId,
|
|
218
|
-
text: "
|
|
221
|
+
text: "Link your account first. Run `/inkeep link` to connect."
|
|
219
222
|
});
|
|
220
223
|
span.end();
|
|
221
224
|
return;
|
|
@@ -224,7 +227,8 @@ async function handleFollowUpSubmission(view) {
|
|
|
224
227
|
inkeepUserId: existingLink.inkeepUserId,
|
|
225
228
|
tenantId,
|
|
226
229
|
slackTeamId: teamId,
|
|
227
|
-
slackUserId
|
|
230
|
+
slackUserId,
|
|
231
|
+
slackAuthorized: false
|
|
228
232
|
});
|
|
229
233
|
const apiBaseUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
|
|
230
234
|
await slackClient.chat.postEphemeral({
|
|
@@ -305,7 +309,7 @@ async function callAgentApi(params) {
|
|
|
305
309
|
const timeout = setTimeout(() => controller.abort(), 3e4);
|
|
306
310
|
let response;
|
|
307
311
|
try {
|
|
308
|
-
response = await
|
|
312
|
+
response = await getInProcessFetch()(`${apiBaseUrl}/run/api/chat`, {
|
|
309
313
|
method: "POST",
|
|
310
314
|
headers: {
|
|
311
315
|
"Content-Type": "application/json",
|
|
@@ -348,11 +352,15 @@ async function callAgentApi(params) {
|
|
|
348
352
|
isError: false
|
|
349
353
|
};
|
|
350
354
|
}
|
|
351
|
-
const
|
|
355
|
+
const errorBody = await response.text().catch(() => "");
|
|
356
|
+
const apiMessage = extractApiErrorMessage(errorBody);
|
|
357
|
+
const errorType = classifyError(null, response.status);
|
|
358
|
+
const errorText = apiMessage ? `*Error.* ${apiMessage}` : getUserFriendlyErrorMessage(errorType, agentId);
|
|
352
359
|
logger.warn({
|
|
353
360
|
status: response.status,
|
|
354
361
|
statusText: response.statusText,
|
|
355
|
-
agentId
|
|
362
|
+
agentId,
|
|
363
|
+
errorBody
|
|
356
364
|
}, "Agent API returned error");
|
|
357
365
|
apiSpan.end();
|
|
358
366
|
return {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { env } from "../../../env.js";
|
|
2
2
|
import { getLogger } from "../../../logger.js";
|
|
3
3
|
import { createContextBlock } from "../blocks/index.js";
|
|
4
|
-
import { SlackErrorType, classifyError, getUserFriendlyErrorMessage } from "./utils.js";
|
|
4
|
+
import { SlackErrorType, classifyError, extractApiErrorMessage, getUserFriendlyErrorMessage } from "./utils.js";
|
|
5
5
|
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
6
|
+
import { getInProcessFetch } from "@inkeep/agents-core";
|
|
6
7
|
|
|
7
8
|
//#region src/slack/services/events/streaming.ts
|
|
8
9
|
/**
|
|
@@ -12,8 +13,8 @@ import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../
|
|
|
12
13
|
* Streams responses incrementally to Slack using chatStream API.
|
|
13
14
|
*/
|
|
14
15
|
const logger = getLogger("slack-streaming");
|
|
15
|
-
const STREAM_TIMEOUT_MS =
|
|
16
|
-
const CHATSTREAM_OP_TIMEOUT_MS =
|
|
16
|
+
const STREAM_TIMEOUT_MS = 6e5;
|
|
17
|
+
const CHATSTREAM_OP_TIMEOUT_MS = 2e4;
|
|
17
18
|
/** Shorter timeout for best-effort cleanup in error paths to bound total error handling time. */
|
|
18
19
|
const CLEANUP_TIMEOUT_MS = 3e3;
|
|
19
20
|
/**
|
|
@@ -59,7 +60,7 @@ async function streamAgentResponse(params) {
|
|
|
59
60
|
}, STREAM_TIMEOUT_MS);
|
|
60
61
|
let response;
|
|
61
62
|
try {
|
|
62
|
-
response = await
|
|
63
|
+
response = await getInProcessFetch()(`${apiUrl.replace(/\/$/, "")}/run/api/chat`, {
|
|
63
64
|
method: "POST",
|
|
64
65
|
headers: {
|
|
65
66
|
"Content-Type": "application/json",
|
|
@@ -128,8 +129,9 @@ async function streamAgentResponse(params) {
|
|
|
128
129
|
status: response.status,
|
|
129
130
|
errorBody
|
|
130
131
|
}, "Agent streaming request failed");
|
|
132
|
+
const apiMessage = extractApiErrorMessage(errorBody);
|
|
131
133
|
const errorType = classifyError(null, response.status);
|
|
132
|
-
const errorMessage = getUserFriendlyErrorMessage(errorType, agentName);
|
|
134
|
+
const errorMessage = apiMessage ? `*Error.* ${apiMessage}` : getUserFriendlyErrorMessage(errorType, agentName);
|
|
133
135
|
await slackClient.chat.postMessage({
|
|
134
136
|
channel,
|
|
135
137
|
thread_ts: threadTs,
|
|
@@ -50,6 +50,7 @@ declare function classifyError(error: unknown, httpStatus?: number): SlackErrorT
|
|
|
50
50
|
/**
|
|
51
51
|
* Get a user-friendly error message based on error type
|
|
52
52
|
*/
|
|
53
|
+
declare function extractApiErrorMessage(responseBody: string): string | null;
|
|
53
54
|
declare function getUserFriendlyErrorMessage(errorType: SlackErrorType, agentName?: string): string;
|
|
54
55
|
type ProjectOption = {
|
|
55
56
|
id: string;
|
|
@@ -157,4 +158,4 @@ declare function formatChannelContext(channelInfo: {
|
|
|
157
158
|
name?: string;
|
|
158
159
|
} | null): string;
|
|
159
160
|
//#endregion
|
|
160
|
-
export { ProjectOption, SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatChannelContext, formatChannelLabel, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
|
|
161
|
+
export { ProjectOption, SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatChannelContext, formatChannelLabel, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
|
|
@@ -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 { findWorkspaceConnectionByTeamId } from "../nango.js";
|
|
5
|
-
import { InternalServices, findWorkAppSlackChannelAgentConfig, findWorkAppSlackUserMapping, generateInternalServiceToken } from "@inkeep/agents-core";
|
|
5
|
+
import { InternalServices, findWorkAppSlackChannelAgentConfig, findWorkAppSlackUserMapping, generateInternalServiceToken, getInProcessFetch } from "@inkeep/agents-core";
|
|
6
6
|
|
|
7
7
|
//#region src/slack/services/events/utils.ts
|
|
8
8
|
/**
|
|
@@ -94,14 +94,21 @@ function classifyError(error, httpStatus) {
|
|
|
94
94
|
/**
|
|
95
95
|
* Get a user-friendly error message based on error type
|
|
96
96
|
*/
|
|
97
|
+
function extractApiErrorMessage(responseBody) {
|
|
98
|
+
try {
|
|
99
|
+
const parsed = JSON.parse(responseBody);
|
|
100
|
+
if (typeof parsed.message === "string" && parsed.message.length > 0) return parsed.message;
|
|
101
|
+
} catch {}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
97
104
|
function getUserFriendlyErrorMessage(errorType, agentName) {
|
|
98
105
|
const agent = agentName || "The agent";
|
|
99
106
|
switch (errorType) {
|
|
100
|
-
case SlackErrorType.TIMEOUT: return
|
|
101
|
-
case SlackErrorType.RATE_LIMIT: return
|
|
102
|
-
case SlackErrorType.AUTH_ERROR: return
|
|
103
|
-
case SlackErrorType.API_ERROR: return
|
|
104
|
-
default: return
|
|
107
|
+
case SlackErrorType.TIMEOUT: return `*Request timed out.* ${agent} took too long to respond. Try again with a simpler question.`;
|
|
108
|
+
case SlackErrorType.RATE_LIMIT: return "*Rate limited.* Wait a moment and try again.";
|
|
109
|
+
case SlackErrorType.AUTH_ERROR: return "*Authentication error.* Run `/inkeep link` to reconnect your account.";
|
|
110
|
+
case SlackErrorType.API_ERROR: return `*Something went wrong.* ${agent} encountered an error. Try again in a moment.`;
|
|
111
|
+
default: return "*Unexpected error.* Something went wrong. Try again in a moment.";
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
114
|
const INTERNAL_FETCH_TIMEOUT_MS = 1e4;
|
|
@@ -114,7 +121,7 @@ async function fetchProjectsForTenant(tenantId) {
|
|
|
114
121
|
const controller = new AbortController();
|
|
115
122
|
const timeout = setTimeout(() => controller.abort(), INTERNAL_FETCH_TIMEOUT_MS);
|
|
116
123
|
try {
|
|
117
|
-
const response = await
|
|
124
|
+
const response = await getInProcessFetch()(`${apiUrl}/manage/tenants/${tenantId}/projects?limit=50`, {
|
|
118
125
|
method: "GET",
|
|
119
126
|
headers: {
|
|
120
127
|
Authorization: `Bearer ${token}`,
|
|
@@ -160,7 +167,7 @@ async function fetchAgentsForProject(tenantId, projectId) {
|
|
|
160
167
|
const controller = new AbortController();
|
|
161
168
|
const timeout = setTimeout(() => controller.abort(), INTERNAL_FETCH_TIMEOUT_MS);
|
|
162
169
|
try {
|
|
163
|
-
const response = await
|
|
170
|
+
const response = await getInProcessFetch()(`${apiUrl}/manage/tenants/${tenantId}/projects/${projectId}/agents?limit=50`, {
|
|
164
171
|
method: "GET",
|
|
165
172
|
headers: {
|
|
166
173
|
Authorization: `Bearer ${token}`,
|
|
@@ -402,4 +409,4 @@ function formatChannelContext(channelInfo) {
|
|
|
402
409
|
}
|
|
403
410
|
|
|
404
411
|
//#endregion
|
|
405
|
-
export { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatChannelContext, formatChannelLabel, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
|
|
412
|
+
export { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, formatChannelContext, formatChannelLabel, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, resolveChannelAgentConfig, sendResponseUrlMessage, timedOp };
|
|
@@ -8,9 +8,9 @@ import { InlineSelectorMetadata, handleAppMention } from "./events/app-mention.j
|
|
|
8
8
|
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./events/block-actions.js";
|
|
9
9
|
import { handleFollowUpSubmission, handleModalSubmission } from "./events/modal-submission.js";
|
|
10
10
|
import { AgentOption, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, FollowUpModalMetadata, ModalMetadata, buildAgentSelectorModal, buildFollowUpModal, buildMessageShortcutModal } from "./modals.js";
|
|
11
|
-
import { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
11
|
+
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
12
12
|
import { StreamResult, streamAgentResponse } from "./events/streaming.js";
|
|
13
13
|
import "./events/index.js";
|
|
14
14
|
import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
|
|
15
15
|
import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
|
|
16
|
-
export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, FollowUpButtonParams, FollowUpModalMetadata, InlineSelectorMetadata, ModalMetadata, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, WorkspaceInstallData, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, 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, 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, WorkspaceInstallData, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, 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, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
|
|
@@ -2,15 +2,15 @@ import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConn
|
|
|
2
2
|
import { getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
|
|
3
3
|
import { buildConversationResponseBlocks, buildFollowUpButton, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
|
|
4
4
|
import { checkUserIsChannelMember, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread, revokeSlackToken } from "./client.js";
|
|
5
|
-
import { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.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
|
-
import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
|
|
9
8
|
import { streamAgentResponse } from "./events/streaming.js";
|
|
10
9
|
import { handleAppMention } from "./events/app-mention.js";
|
|
11
10
|
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./events/block-actions.js";
|
|
12
11
|
import { handleFollowUpSubmission, handleModalSubmission } from "./events/modal-submission.js";
|
|
13
12
|
import "./events/index.js";
|
|
14
13
|
import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
|
|
14
|
+
import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
|
|
15
15
|
|
|
16
|
-
export { SlackErrorType, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, 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, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
|
|
16
|
+
export { SlackErrorType, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, 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, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
|
|
@@ -66,7 +66,7 @@ function buildAgentSelectorModal(params) {
|
|
|
66
66
|
}
|
|
67
67
|
}, {
|
|
68
68
|
type: "input",
|
|
69
|
-
block_id: "agent_select_block",
|
|
69
|
+
block_id: selectedProjectId ? `agent_select_block_${selectedProjectId}` : "agent_select_block",
|
|
70
70
|
element: {
|
|
71
71
|
type: "static_select",
|
|
72
72
|
action_id: "agent_select",
|
|
@@ -137,7 +137,7 @@ function buildAgentSelectorModal(params) {
|
|
|
137
137
|
type: "context",
|
|
138
138
|
elements: [{
|
|
139
139
|
type: "mrkdwn",
|
|
140
|
-
text:
|
|
140
|
+
text: `<${manageUiBaseUrl}${dashboardUrl}|Open Dashboard>`
|
|
141
141
|
}]
|
|
142
142
|
});
|
|
143
143
|
return {
|
|
@@ -283,7 +283,7 @@ function buildMessageShortcutModal(params) {
|
|
|
283
283
|
},
|
|
284
284
|
{
|
|
285
285
|
type: "input",
|
|
286
|
-
block_id: "agent_select_block",
|
|
286
|
+
block_id: selectedProjectId ? `agent_select_block_${selectedProjectId}` : "agent_select_block",
|
|
287
287
|
element: {
|
|
288
288
|
type: "static_select",
|
|
289
289
|
action_id: "agent_select",
|
|
@@ -325,7 +325,7 @@ function buildMessageShortcutModal(params) {
|
|
|
325
325
|
type: "context",
|
|
326
326
|
elements: [{
|
|
327
327
|
type: "mrkdwn",
|
|
328
|
-
text:
|
|
328
|
+
text: `<${manageUiBaseUrl}${dashboardUrl}|Open Dashboard>`
|
|
329
329
|
}]
|
|
330
330
|
});
|
|
331
331
|
return {
|
|
@@ -18,6 +18,7 @@ interface DefaultAgentConfig {
|
|
|
18
18
|
agentName?: string;
|
|
19
19
|
projectId: string;
|
|
20
20
|
projectName?: string;
|
|
21
|
+
grantAccessToMembers?: boolean;
|
|
21
22
|
}
|
|
22
23
|
interface SlackWorkspaceConnection {
|
|
23
24
|
connectionId: string;
|
|
@@ -30,6 +31,8 @@ interface SlackWorkspaceConnection {
|
|
|
30
31
|
/**
|
|
31
32
|
* Find a workspace connection by Slack team ID.
|
|
32
33
|
* Uses PostgreSQL first (O(1)) with in-memory caching, then falls back to Nango.
|
|
34
|
+
* In development mode with .slack-dev.json present, returns a local connection
|
|
35
|
+
* built from the dev config file instead of hitting Nango.
|
|
33
36
|
*
|
|
34
37
|
* Performance: This function is called on every @mention and command.
|
|
35
38
|
* The PostgreSQL-first approach with caching provides O(1) lookups.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { env } from "../../env.js";
|
|
2
2
|
import { getLogger } from "../../logger.js";
|
|
3
3
|
import runDbClient_default from "../../db/runDbClient.js";
|
|
4
|
+
import { getDevDefaultAgent, isSlackDevMode, loadSlackDevConfig, saveSlackDevConfig } from "./dev-config.js";
|
|
4
5
|
import { findWorkAppSlackWorkspaceBySlackTeamId } from "@inkeep/agents-core";
|
|
5
6
|
import { Nango } from "@nangohq/node";
|
|
6
7
|
|
|
@@ -78,6 +79,10 @@ function getSlackIntegrationId() {
|
|
|
78
79
|
return env.NANGO_SLACK_INTEGRATION_ID || "slack-agent";
|
|
79
80
|
}
|
|
80
81
|
async function createConnectSession(params) {
|
|
82
|
+
if (isSlackDevMode()) {
|
|
83
|
+
logger.debug({}, "Skipping Nango connect session in dev mode");
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
81
86
|
try {
|
|
82
87
|
const nango = getSlackNango();
|
|
83
88
|
const integrationId = getSlackIntegrationId();
|
|
@@ -105,6 +110,7 @@ async function createConnectSession(params) {
|
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
async function getConnectionAccessToken(connectionId) {
|
|
113
|
+
if (isSlackDevMode()) return loadSlackDevConfig()?.botToken ?? null;
|
|
108
114
|
try {
|
|
109
115
|
const nango = getSlackNango();
|
|
110
116
|
const integrationId = getSlackIntegrationId();
|
|
@@ -117,9 +123,27 @@ async function getConnectionAccessToken(connectionId) {
|
|
|
117
123
|
return null;
|
|
118
124
|
}
|
|
119
125
|
}
|
|
126
|
+
function buildDevWorkspaceConnection(devConfig, teamId) {
|
|
127
|
+
const connection = {
|
|
128
|
+
connectionId: `dev:${teamId}`,
|
|
129
|
+
teamId,
|
|
130
|
+
teamName: devConfig.teamName || "dev",
|
|
131
|
+
botToken: devConfig.botToken,
|
|
132
|
+
tenantId: "default",
|
|
133
|
+
defaultAgent: getDevDefaultAgent(devConfig) ?? void 0
|
|
134
|
+
};
|
|
135
|
+
evictWorkspaceCache();
|
|
136
|
+
workspaceConnectionCache.set(teamId, {
|
|
137
|
+
connection,
|
|
138
|
+
expiresAt: Date.now() + CACHE_TTL_MS
|
|
139
|
+
});
|
|
140
|
+
return connection;
|
|
141
|
+
}
|
|
120
142
|
/**
|
|
121
143
|
* Find a workspace connection by Slack team ID.
|
|
122
144
|
* Uses PostgreSQL first (O(1)) with in-memory caching, then falls back to Nango.
|
|
145
|
+
* In development mode with .slack-dev.json present, returns a local connection
|
|
146
|
+
* built from the dev config file instead of hitting Nango.
|
|
123
147
|
*
|
|
124
148
|
* Performance: This function is called on every @mention and command.
|
|
125
149
|
* The PostgreSQL-first approach with caching provides O(1) lookups.
|
|
@@ -130,6 +154,15 @@ async function findWorkspaceConnectionByTeamId(teamId) {
|
|
|
130
154
|
logger.debug({ teamId }, "Workspace connection cache hit");
|
|
131
155
|
return cached.connection;
|
|
132
156
|
}
|
|
157
|
+
if (isSlackDevMode()) {
|
|
158
|
+
const devConfig = loadSlackDevConfig();
|
|
159
|
+
if (devConfig) {
|
|
160
|
+
logger.debug({ teamId }, "Using .slack-dev.json for workspace connection");
|
|
161
|
+
return buildDevWorkspaceConnection(devConfig, teamId);
|
|
162
|
+
}
|
|
163
|
+
logger.debug({ teamId }, "No .slack-dev.json found returning null");
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
133
166
|
try {
|
|
134
167
|
const dbWorkspace = await findWorkAppSlackWorkspaceBySlackTeamId(runDbClient_default)(teamId);
|
|
135
168
|
if (dbWorkspace?.nangoConnectionId) {
|
|
@@ -155,7 +188,7 @@ async function findWorkspaceConnectionByTeamId(teamId) {
|
|
|
155
188
|
}
|
|
156
189
|
}
|
|
157
190
|
logger.debug({ teamId }, "PostgreSQL lookup failed, falling back to Nango iteration");
|
|
158
|
-
return findWorkspaceConnectionByTeamIdFromNango(teamId);
|
|
191
|
+
return await findWorkspaceConnectionByTeamIdFromNango(teamId);
|
|
159
192
|
} catch (error) {
|
|
160
193
|
logger.error({
|
|
161
194
|
error,
|
|
@@ -165,6 +198,7 @@ async function findWorkspaceConnectionByTeamId(teamId) {
|
|
|
165
198
|
}
|
|
166
199
|
}
|
|
167
200
|
async function getWorkspaceDefaultAgentFromNangoByConnectionId(connectionId) {
|
|
201
|
+
if (isSlackDevMode()) return getDevDefaultAgent(loadSlackDevConfig());
|
|
168
202
|
try {
|
|
169
203
|
const nango = getSlackNango();
|
|
170
204
|
const integrationId = getSlackIntegrationId();
|
|
@@ -234,10 +268,23 @@ function clearWorkspaceConnectionCache(teamId) {
|
|
|
234
268
|
else workspaceConnectionCache.clear();
|
|
235
269
|
}
|
|
236
270
|
async function updateConnectionMetadata(connectionId, metadata) {
|
|
271
|
+
if (isSlackDevMode()) {
|
|
272
|
+
const devConfig = loadSlackDevConfig();
|
|
273
|
+
if (!devConfig) return false;
|
|
274
|
+
devConfig.metadata = {
|
|
275
|
+
...devConfig.metadata,
|
|
276
|
+
...metadata
|
|
277
|
+
};
|
|
278
|
+
return saveSlackDevConfig(devConfig);
|
|
279
|
+
}
|
|
237
280
|
try {
|
|
238
281
|
const nango = getSlackNango();
|
|
239
282
|
const integrationId = getSlackIntegrationId();
|
|
240
|
-
|
|
283
|
+
const lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
284
|
+
await nango.updateMetadata(integrationId, connectionId, {
|
|
285
|
+
...metadata,
|
|
286
|
+
last_updated_at: lastUpdatedAt
|
|
287
|
+
});
|
|
241
288
|
return true;
|
|
242
289
|
} catch (error) {
|
|
243
290
|
logger.error({
|
|
@@ -248,6 +295,17 @@ async function updateConnectionMetadata(connectionId, metadata) {
|
|
|
248
295
|
}
|
|
249
296
|
}
|
|
250
297
|
async function setWorkspaceDefaultAgent(teamId, defaultAgent) {
|
|
298
|
+
if (isSlackDevMode()) {
|
|
299
|
+
const devConfig = loadSlackDevConfig();
|
|
300
|
+
if (!devConfig) return false;
|
|
301
|
+
devConfig.metadata = {
|
|
302
|
+
...devConfig.metadata,
|
|
303
|
+
default_agent: defaultAgent ? JSON.stringify(defaultAgent) : ""
|
|
304
|
+
};
|
|
305
|
+
const saved = saveSlackDevConfig(devConfig);
|
|
306
|
+
if (saved) clearWorkspaceConnectionCache(teamId);
|
|
307
|
+
return saved;
|
|
308
|
+
}
|
|
251
309
|
try {
|
|
252
310
|
const workspace = await findWorkspaceConnectionByTeamId(teamId);
|
|
253
311
|
if (!workspace) {
|
|
@@ -266,6 +324,7 @@ async function setWorkspaceDefaultAgent(teamId, defaultAgent) {
|
|
|
266
324
|
}
|
|
267
325
|
}
|
|
268
326
|
async function getWorkspaceDefaultAgentFromNango(teamId) {
|
|
327
|
+
if (isSlackDevMode()) return getDevDefaultAgent(loadSlackDevConfig());
|
|
269
328
|
try {
|
|
270
329
|
return (await findWorkspaceConnectionByTeamId(teamId))?.defaultAgent || null;
|
|
271
330
|
} catch (error) {
|
|
@@ -294,6 +353,13 @@ async function storeWorkspaceInstallation(data) {
|
|
|
294
353
|
teamId: data.teamId,
|
|
295
354
|
enterpriseId: data.enterpriseId
|
|
296
355
|
});
|
|
356
|
+
if (isSlackDevMode()) {
|
|
357
|
+
logger.debug({ connectionId }, "Skipping Nango store in dev mode");
|
|
358
|
+
return {
|
|
359
|
+
connectionId: `dev:${data.teamId}`,
|
|
360
|
+
success: true
|
|
361
|
+
};
|
|
362
|
+
}
|
|
297
363
|
try {
|
|
298
364
|
const integrationId = getSlackIntegrationId();
|
|
299
365
|
const secretKey = env.NANGO_SLACK_SECRET_KEY || env.NANGO_SECRET_KEY;
|
|
@@ -406,6 +472,18 @@ async function storeWorkspaceInstallation(data) {
|
|
|
406
472
|
* List all workspace installations from Nango.
|
|
407
473
|
*/
|
|
408
474
|
async function listWorkspaceInstallations() {
|
|
475
|
+
if (isSlackDevMode()) {
|
|
476
|
+
const devConfig = loadSlackDevConfig();
|
|
477
|
+
if (!devConfig) return [];
|
|
478
|
+
return [{
|
|
479
|
+
connectionId: `dev:${devConfig.teamId}`,
|
|
480
|
+
teamId: devConfig.teamId,
|
|
481
|
+
teamName: devConfig.teamName,
|
|
482
|
+
botToken: devConfig.botToken,
|
|
483
|
+
tenantId: "default",
|
|
484
|
+
defaultAgent: getDevDefaultAgent(devConfig) ?? void 0
|
|
485
|
+
}];
|
|
486
|
+
}
|
|
409
487
|
try {
|
|
410
488
|
const nango = getSlackNango();
|
|
411
489
|
const integrationId = getSlackIntegrationId();
|
|
@@ -445,6 +523,10 @@ async function listWorkspaceInstallations() {
|
|
|
445
523
|
* Delete a workspace installation from Nango.
|
|
446
524
|
*/
|
|
447
525
|
async function deleteWorkspaceInstallation(connectionId) {
|
|
526
|
+
if (isSlackDevMode()) {
|
|
527
|
+
logger.debug({ connectionId }, "Skipping Nango delete in dev mode");
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
448
530
|
try {
|
|
449
531
|
const nango = getSlackNango();
|
|
450
532
|
const integrationId = getSlackIntegrationId();
|