@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,129 +0,0 @@
|
|
|
1
|
-
import { AgentOption } from "../modals.js";
|
|
2
|
-
import { DefaultAgentConfig } from "../nango.js";
|
|
3
|
-
|
|
4
|
-
//#region src/slack/services/events/utils.d.ts
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Convert standard Markdown to Slack's mrkdwn format
|
|
8
|
-
*
|
|
9
|
-
* Key differences:
|
|
10
|
-
* - **bold** or __bold__ → *bold*
|
|
11
|
-
* - *italic* (when not bold) → _italic_
|
|
12
|
-
* - # Header → *Header* (Slack has no headers)
|
|
13
|
-
* - [text](url) → <url|text>
|
|
14
|
-
* - Keeps code blocks, inline code, and lists as-is
|
|
15
|
-
*/
|
|
16
|
-
declare function markdownToMrkdwn(markdown: string): string;
|
|
17
|
-
/**
|
|
18
|
-
* Error types for user-friendly error messages
|
|
19
|
-
*/
|
|
20
|
-
declare enum SlackErrorType {
|
|
21
|
-
TIMEOUT = "timeout",
|
|
22
|
-
RATE_LIMIT = "rate_limit",
|
|
23
|
-
API_ERROR = "api_error",
|
|
24
|
-
AUTH_ERROR = "auth_error",
|
|
25
|
-
UNKNOWN = "unknown",
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Classify an error into a SlackErrorType for appropriate user messaging
|
|
29
|
-
*/
|
|
30
|
-
declare function classifyError(error: unknown, httpStatus?: number): SlackErrorType;
|
|
31
|
-
/**
|
|
32
|
-
* Get a user-friendly error message based on error type
|
|
33
|
-
*/
|
|
34
|
-
declare function getUserFriendlyErrorMessage(errorType: SlackErrorType, agentName?: string): string;
|
|
35
|
-
/**
|
|
36
|
-
* Post an error message to Slack (ephemeral if possible, thread fallback)
|
|
37
|
-
*/
|
|
38
|
-
declare function postErrorMessage(slackClient: {
|
|
39
|
-
chat: {
|
|
40
|
-
postEphemeral: (params: {
|
|
41
|
-
channel: string;
|
|
42
|
-
user: string;
|
|
43
|
-
text: string;
|
|
44
|
-
thread_ts?: string;
|
|
45
|
-
}) => Promise<unknown>;
|
|
46
|
-
postMessage: (params: {
|
|
47
|
-
channel: string;
|
|
48
|
-
text: string;
|
|
49
|
-
thread_ts?: string;
|
|
50
|
-
}) => Promise<unknown>;
|
|
51
|
-
};
|
|
52
|
-
}, params: {
|
|
53
|
-
channel: string;
|
|
54
|
-
slackUserId: string;
|
|
55
|
-
threadTs?: string;
|
|
56
|
-
errorType: SlackErrorType;
|
|
57
|
-
agentName?: string;
|
|
58
|
-
useEphemeral?: boolean;
|
|
59
|
-
}): Promise<void>;
|
|
60
|
-
type ProjectOption = {
|
|
61
|
-
id: string;
|
|
62
|
-
name: string;
|
|
63
|
-
};
|
|
64
|
-
declare function fetchProjectsForTenant(tenantId: string): Promise<ProjectOption[]>;
|
|
65
|
-
declare function fetchAgentsForProject(tenantId: string, projectId: string): Promise<AgentOption[]>;
|
|
66
|
-
declare function fetchAgentsForTenant(tenantId: string): Promise<AgentOption[]>;
|
|
67
|
-
declare function getWorkspaceDefaultAgent(teamId: string): Promise<DefaultAgentConfig | null>;
|
|
68
|
-
declare function getChannelAgentConfig(teamId: string, channelId: string): Promise<DefaultAgentConfig | null>;
|
|
69
|
-
declare function sendResponseUrlMessage(responseUrl: string, message: {
|
|
70
|
-
text: string;
|
|
71
|
-
response_type?: 'ephemeral' | 'in_channel';
|
|
72
|
-
replace_original?: boolean;
|
|
73
|
-
delete_original?: boolean;
|
|
74
|
-
blocks?: unknown[];
|
|
75
|
-
}): Promise<void>;
|
|
76
|
-
/**
|
|
77
|
-
* Generate a deterministic conversation ID for Slack threads/DMs.
|
|
78
|
-
* This ensures the same thread always gets the same conversation ID,
|
|
79
|
-
* allowing the agent to maintain conversation history.
|
|
80
|
-
*
|
|
81
|
-
* Format: slack-{teamId}-{identifier}
|
|
82
|
-
* - For threads: identifier = thread_ts (parent message timestamp)
|
|
83
|
-
* - For DMs: identifier = channel (DM channel ID)
|
|
84
|
-
*/
|
|
85
|
-
declare function generateSlackConversationId(params: {
|
|
86
|
-
teamId: string;
|
|
87
|
-
threadTs?: string;
|
|
88
|
-
channel: string;
|
|
89
|
-
isDM?: boolean;
|
|
90
|
-
}): string;
|
|
91
|
-
/**
|
|
92
|
-
* Check if a thread was initiated by the bot (i.e., the parent message is from the bot).
|
|
93
|
-
* This helps distinguish "bot threads" (where users are conversing with the bot)
|
|
94
|
-
* from "user threads" (where users are having their own conversation).
|
|
95
|
-
*
|
|
96
|
-
* Uses conversations.replies which returns thread messages with the parent as the first message.
|
|
97
|
-
*/
|
|
98
|
-
declare function checkIfBotThread(slackClient: {
|
|
99
|
-
conversations: {
|
|
100
|
-
replies: (params: {
|
|
101
|
-
channel: string;
|
|
102
|
-
ts: string;
|
|
103
|
-
limit?: number;
|
|
104
|
-
}) => Promise<{
|
|
105
|
-
messages?: Array<{
|
|
106
|
-
bot_id?: string;
|
|
107
|
-
user?: string;
|
|
108
|
-
text?: string;
|
|
109
|
-
}>;
|
|
110
|
-
}>;
|
|
111
|
-
};
|
|
112
|
-
}, channel: string, threadTs: string): Promise<boolean>;
|
|
113
|
-
declare function getThreadContext(slackClient: {
|
|
114
|
-
conversations: {
|
|
115
|
-
replies: (params: {
|
|
116
|
-
channel: string;
|
|
117
|
-
ts: string;
|
|
118
|
-
limit?: number;
|
|
119
|
-
}) => Promise<{
|
|
120
|
-
messages?: Array<{
|
|
121
|
-
bot_id?: string;
|
|
122
|
-
user?: string;
|
|
123
|
-
text?: string;
|
|
124
|
-
}>;
|
|
125
|
-
}>;
|
|
126
|
-
};
|
|
127
|
-
}, channel: string, threadTs: string): Promise<string>;
|
|
128
|
-
//#endregion
|
|
129
|
-
export { ProjectOption, SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, postErrorMessage, sendResponseUrlMessage };
|
|
@@ -1,315 +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, getWorkspaceDefaultAgentFromNango } from "../nango.js";
|
|
5
|
-
import { InternalServices, findWorkAppSlackChannelAgentConfig, generateInternalServiceToken } from "@inkeep/agents-core";
|
|
6
|
-
|
|
7
|
-
//#region src/slack/services/events/utils.ts
|
|
8
|
-
/**
|
|
9
|
-
* Shared utilities for Slack event handlers
|
|
10
|
-
*/
|
|
11
|
-
const logger = getLogger("slack-event-utils");
|
|
12
|
-
/**
|
|
13
|
-
* Convert standard Markdown to Slack's mrkdwn format
|
|
14
|
-
*
|
|
15
|
-
* Key differences:
|
|
16
|
-
* - **bold** or __bold__ → *bold*
|
|
17
|
-
* - *italic* (when not bold) → _italic_
|
|
18
|
-
* - # Header → *Header* (Slack has no headers)
|
|
19
|
-
* - [text](url) → <url|text>
|
|
20
|
-
* - Keeps code blocks, inline code, and lists as-is
|
|
21
|
-
*/
|
|
22
|
-
function markdownToMrkdwn(markdown) {
|
|
23
|
-
if (!markdown) return markdown;
|
|
24
|
-
let result = markdown;
|
|
25
|
-
result = result.replace(/^#{1,6}\s+(.+)$/gm, "*$1*");
|
|
26
|
-
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "<$2|$1>");
|
|
27
|
-
result = result.replace(/\*\*([^*]+)\*\*/g, "*$1*");
|
|
28
|
-
result = result.replace(/__([^_]+)__/g, "*$1*");
|
|
29
|
-
result = result.replace(/~~([^~]+)~~/g, "~$1~");
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Error types for user-friendly error messages
|
|
34
|
-
*/
|
|
35
|
-
let SlackErrorType = /* @__PURE__ */ function(SlackErrorType$1) {
|
|
36
|
-
SlackErrorType$1["TIMEOUT"] = "timeout";
|
|
37
|
-
SlackErrorType$1["RATE_LIMIT"] = "rate_limit";
|
|
38
|
-
SlackErrorType$1["API_ERROR"] = "api_error";
|
|
39
|
-
SlackErrorType$1["AUTH_ERROR"] = "auth_error";
|
|
40
|
-
SlackErrorType$1["UNKNOWN"] = "unknown";
|
|
41
|
-
return SlackErrorType$1;
|
|
42
|
-
}({});
|
|
43
|
-
/**
|
|
44
|
-
* Classify an error into a SlackErrorType for appropriate user messaging
|
|
45
|
-
*/
|
|
46
|
-
function classifyError(error, httpStatus) {
|
|
47
|
-
if (httpStatus === 429) return SlackErrorType.RATE_LIMIT;
|
|
48
|
-
if (httpStatus === 401 || httpStatus === 403) return SlackErrorType.AUTH_ERROR;
|
|
49
|
-
if (httpStatus && httpStatus >= 400) return SlackErrorType.API_ERROR;
|
|
50
|
-
const errorMessage = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
51
|
-
if (errorMessage.includes("timeout") || errorMessage.includes("timed out") || errorMessage.includes("aborted") || errorMessage.includes("econnreset")) return SlackErrorType.TIMEOUT;
|
|
52
|
-
if (errorMessage.includes("rate limit") || errorMessage.includes("too many requests")) return SlackErrorType.RATE_LIMIT;
|
|
53
|
-
if (errorMessage.includes("unauthorized") || errorMessage.includes("forbidden")) return SlackErrorType.AUTH_ERROR;
|
|
54
|
-
return SlackErrorType.UNKNOWN;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Get a user-friendly error message based on error type
|
|
58
|
-
*/
|
|
59
|
-
function getUserFriendlyErrorMessage(errorType, agentName) {
|
|
60
|
-
const agent = agentName || "The agent";
|
|
61
|
-
switch (errorType) {
|
|
62
|
-
case SlackErrorType.TIMEOUT: return `⏱️ *Request timed out*\n\n${agent} took too long to respond. This can happen with complex queries.\n\n*Try:*\n• Simplifying your question\n• Breaking it into smaller parts\n• Trying again in a moment`;
|
|
63
|
-
case SlackErrorType.RATE_LIMIT: return `⚠️ *Too many requests*\n\nYou've hit the rate limit. Please wait a moment before trying again.\n\n*Tip:* Space out your requests to avoid this.`;
|
|
64
|
-
case SlackErrorType.AUTH_ERROR: return `🔐 *Authentication issue*\n\nThere was a problem with your account connection.\n\n*Try:*\n• Running \`/inkeep link\` to re-link your account\n• Contacting your workspace admin if the issue persists`;
|
|
65
|
-
case SlackErrorType.API_ERROR: return `❌ *Something went wrong*\n\n${agent} encountered an error processing your request.\n\n*Try:*\n• Rephrasing your question\n• Trying again in a moment\n• Using \`/inkeep help\` for more options`;
|
|
66
|
-
default: return `❌ *Unexpected error*\n\nSomething went wrong while processing your request.\n\n*Try:*\n• Trying again in a moment\n• Using \`/inkeep help\` for more options`;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Post an error message to Slack (ephemeral if possible, thread fallback)
|
|
71
|
-
*/
|
|
72
|
-
async function postErrorMessage(slackClient, params) {
|
|
73
|
-
const { channel, slackUserId, threadTs, errorType, agentName, useEphemeral = true } = params;
|
|
74
|
-
const message = getUserFriendlyErrorMessage(errorType, agentName);
|
|
75
|
-
try {
|
|
76
|
-
if (useEphemeral) await slackClient.chat.postEphemeral({
|
|
77
|
-
channel,
|
|
78
|
-
user: slackUserId,
|
|
79
|
-
text: message,
|
|
80
|
-
thread_ts: threadTs
|
|
81
|
-
});
|
|
82
|
-
else await slackClient.chat.postMessage({
|
|
83
|
-
channel,
|
|
84
|
-
text: message,
|
|
85
|
-
thread_ts: threadTs
|
|
86
|
-
});
|
|
87
|
-
} catch (postError) {
|
|
88
|
-
logger.error({
|
|
89
|
-
postError,
|
|
90
|
-
channel,
|
|
91
|
-
errorType
|
|
92
|
-
}, "Failed to post error message to Slack");
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const workspaceSettings = /* @__PURE__ */ new Map();
|
|
96
|
-
async function fetchProjectsForTenant(tenantId) {
|
|
97
|
-
const apiUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
|
|
98
|
-
const token = await generateInternalServiceToken({
|
|
99
|
-
serviceId: InternalServices.INKEEP_AGENTS_MANAGE_API,
|
|
100
|
-
tenantId
|
|
101
|
-
});
|
|
102
|
-
try {
|
|
103
|
-
const response = await fetch(`${apiUrl}/manage/tenants/${tenantId}/projects?limit=50`, {
|
|
104
|
-
method: "GET",
|
|
105
|
-
headers: {
|
|
106
|
-
Authorization: `Bearer ${token}`,
|
|
107
|
-
"Content-Type": "application/json"
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
if (!response.ok) {
|
|
111
|
-
const errorBody = await response.text().catch(() => "");
|
|
112
|
-
logger.warn({
|
|
113
|
-
status: response.status,
|
|
114
|
-
tenantId,
|
|
115
|
-
errorBody
|
|
116
|
-
}, "Failed to fetch projects from API");
|
|
117
|
-
return [];
|
|
118
|
-
}
|
|
119
|
-
const result = await response.json();
|
|
120
|
-
logger.debug({
|
|
121
|
-
tenantId,
|
|
122
|
-
projectCount: result.data.length
|
|
123
|
-
}, "Fetched projects from API");
|
|
124
|
-
return result.data.map((p) => ({
|
|
125
|
-
id: p.id,
|
|
126
|
-
name: p.name || p.id
|
|
127
|
-
}));
|
|
128
|
-
} catch (error) {
|
|
129
|
-
logger.error({
|
|
130
|
-
error,
|
|
131
|
-
tenantId
|
|
132
|
-
}, "Error fetching projects from API");
|
|
133
|
-
return [];
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
async function fetchAgentsForProject(tenantId, projectId) {
|
|
137
|
-
const apiUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
|
|
138
|
-
const token = await generateInternalServiceToken({
|
|
139
|
-
serviceId: InternalServices.INKEEP_AGENTS_MANAGE_API,
|
|
140
|
-
tenantId,
|
|
141
|
-
projectId
|
|
142
|
-
});
|
|
143
|
-
try {
|
|
144
|
-
const response = await fetch(`${apiUrl}/manage/tenants/${tenantId}/projects/${projectId}/agents?limit=50`, {
|
|
145
|
-
method: "GET",
|
|
146
|
-
headers: {
|
|
147
|
-
Authorization: `Bearer ${token}`,
|
|
148
|
-
"Content-Type": "application/json",
|
|
149
|
-
"x-inkeep-project-id": projectId
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
if (!response.ok) {
|
|
153
|
-
const errorBody = await response.text().catch(() => "");
|
|
154
|
-
logger.warn({
|
|
155
|
-
status: response.status,
|
|
156
|
-
tenantId,
|
|
157
|
-
projectId,
|
|
158
|
-
errorBody
|
|
159
|
-
}, "Failed to fetch agents from API");
|
|
160
|
-
return [];
|
|
161
|
-
}
|
|
162
|
-
const result = await response.json();
|
|
163
|
-
logger.debug({
|
|
164
|
-
tenantId,
|
|
165
|
-
projectId,
|
|
166
|
-
agentCount: result.data.length
|
|
167
|
-
}, "Fetched agents from API");
|
|
168
|
-
return result.data.map((a) => ({
|
|
169
|
-
id: a.id,
|
|
170
|
-
name: a.name || a.id,
|
|
171
|
-
projectId,
|
|
172
|
-
projectName: projectId
|
|
173
|
-
}));
|
|
174
|
-
} catch (error) {
|
|
175
|
-
logger.error({
|
|
176
|
-
error,
|
|
177
|
-
tenantId,
|
|
178
|
-
projectId
|
|
179
|
-
}, "Error fetching agents from API");
|
|
180
|
-
return [];
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
async function fetchAgentsForTenant(tenantId) {
|
|
184
|
-
const projects = await fetchProjectsForTenant(tenantId);
|
|
185
|
-
return (await Promise.all(projects.map(async (project) => {
|
|
186
|
-
return (await fetchAgentsForProject(tenantId, project.id)).map((agent) => ({
|
|
187
|
-
...agent,
|
|
188
|
-
projectName: project.name
|
|
189
|
-
}));
|
|
190
|
-
}))).flat();
|
|
191
|
-
}
|
|
192
|
-
async function getWorkspaceDefaultAgent(teamId) {
|
|
193
|
-
const nangoDefault = await getWorkspaceDefaultAgentFromNango(teamId);
|
|
194
|
-
if (nangoDefault) {
|
|
195
|
-
logger.debug({ teamId }, "Found workspace default agent from Nango metadata");
|
|
196
|
-
return nangoDefault;
|
|
197
|
-
}
|
|
198
|
-
return workspaceSettings.get(teamId)?.defaultAgent || null;
|
|
199
|
-
}
|
|
200
|
-
async function getChannelAgentConfig(teamId, channelId) {
|
|
201
|
-
const tenantId = (await findWorkspaceConnectionByTeamId(teamId))?.tenantId || "default";
|
|
202
|
-
const channelConfig = await findWorkAppSlackChannelAgentConfig(runDbClient_default)(tenantId, teamId, channelId);
|
|
203
|
-
if (channelConfig?.enabled) return {
|
|
204
|
-
projectId: channelConfig.projectId,
|
|
205
|
-
agentId: channelConfig.agentId,
|
|
206
|
-
agentName: channelConfig.agentName || channelConfig.agentId,
|
|
207
|
-
projectName: channelConfig.projectId
|
|
208
|
-
};
|
|
209
|
-
return getWorkspaceDefaultAgent(teamId);
|
|
210
|
-
}
|
|
211
|
-
async function sendResponseUrlMessage(responseUrl, message) {
|
|
212
|
-
try {
|
|
213
|
-
const payload = { text: message.text };
|
|
214
|
-
if (message.replace_original) payload.replace_original = true;
|
|
215
|
-
else if (message.delete_original) payload.delete_original = true;
|
|
216
|
-
else if (message.response_type) payload.response_type = message.response_type;
|
|
217
|
-
if (message.blocks) payload.blocks = message.blocks;
|
|
218
|
-
logger.info({
|
|
219
|
-
hasBlocks: !!message.blocks,
|
|
220
|
-
blockCount: Array.isArray(message.blocks) ? message.blocks.length : 0,
|
|
221
|
-
replace: !!message.replace_original
|
|
222
|
-
}, "Sending response_url message");
|
|
223
|
-
const response = await fetch(responseUrl, {
|
|
224
|
-
method: "POST",
|
|
225
|
-
headers: { "Content-Type": "application/json" },
|
|
226
|
-
body: JSON.stringify(payload)
|
|
227
|
-
});
|
|
228
|
-
const responseBody = await response.text().catch(() => "");
|
|
229
|
-
logger.info({
|
|
230
|
-
status: response.status,
|
|
231
|
-
responseBody: responseBody.slice(0, 300)
|
|
232
|
-
}, "response_url response received");
|
|
233
|
-
if (!response.ok) logger.error({
|
|
234
|
-
status: response.status,
|
|
235
|
-
errorBody: responseBody
|
|
236
|
-
}, "response_url request failed");
|
|
237
|
-
} catch (error) {
|
|
238
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
239
|
-
logger.error({ errorMessage }, "Failed to send response_url message");
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Generate a deterministic conversation ID for Slack threads/DMs.
|
|
244
|
-
* This ensures the same thread always gets the same conversation ID,
|
|
245
|
-
* allowing the agent to maintain conversation history.
|
|
246
|
-
*
|
|
247
|
-
* Format: slack-{teamId}-{identifier}
|
|
248
|
-
* - For threads: identifier = thread_ts (parent message timestamp)
|
|
249
|
-
* - For DMs: identifier = channel (DM channel ID)
|
|
250
|
-
*/
|
|
251
|
-
function generateSlackConversationId(params) {
|
|
252
|
-
const { teamId, threadTs, channel, isDM } = params;
|
|
253
|
-
if (isDM) return `slack-dm-${teamId}-${channel}`;
|
|
254
|
-
return `slack-thread-${teamId}-${threadTs || channel}`;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Check if a thread was initiated by the bot (i.e., the parent message is from the bot).
|
|
258
|
-
* This helps distinguish "bot threads" (where users are conversing with the bot)
|
|
259
|
-
* from "user threads" (where users are having their own conversation).
|
|
260
|
-
*
|
|
261
|
-
* Uses conversations.replies which returns thread messages with the parent as the first message.
|
|
262
|
-
*/
|
|
263
|
-
async function checkIfBotThread(slackClient, channel, threadTs) {
|
|
264
|
-
try {
|
|
265
|
-
const parentMessage = (await slackClient.conversations.replies({
|
|
266
|
-
channel,
|
|
267
|
-
ts: threadTs,
|
|
268
|
-
limit: 1
|
|
269
|
-
})).messages?.[0];
|
|
270
|
-
if (!parentMessage) {
|
|
271
|
-
logger.debug({
|
|
272
|
-
channel,
|
|
273
|
-
threadTs
|
|
274
|
-
}, "No parent message found for thread");
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
const isBotThread = Boolean(parentMessage.bot_id);
|
|
278
|
-
logger.debug({
|
|
279
|
-
channel,
|
|
280
|
-
threadTs,
|
|
281
|
-
isBotThread,
|
|
282
|
-
botId: parentMessage.bot_id
|
|
283
|
-
}, "Checked if thread is bot-owned");
|
|
284
|
-
return isBotThread;
|
|
285
|
-
} catch (error) {
|
|
286
|
-
logger.warn({
|
|
287
|
-
error,
|
|
288
|
-
channel,
|
|
289
|
-
threadTs
|
|
290
|
-
}, "Failed to check if thread is bot-owned");
|
|
291
|
-
return false;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
async function getThreadContext(slackClient, channel, threadTs) {
|
|
295
|
-
try {
|
|
296
|
-
const threadMessages = await slackClient.conversations.replies({
|
|
297
|
-
channel,
|
|
298
|
-
ts: threadTs,
|
|
299
|
-
limit: 20
|
|
300
|
-
});
|
|
301
|
-
if (threadMessages.messages && threadMessages.messages.length > 1) return threadMessages.messages.slice(0, -1).filter((msg) => !msg.bot_id || msg.text?.includes("Powered by")).map((msg) => {
|
|
302
|
-
return `${!!msg.bot_id ? "Assistant" : `<@${msg.user}>`}: ${msg.text || ""}`;
|
|
303
|
-
}).join("\n").trim();
|
|
304
|
-
} catch (threadError) {
|
|
305
|
-
logger.warn({
|
|
306
|
-
threadError,
|
|
307
|
-
channel,
|
|
308
|
-
threadTs
|
|
309
|
-
}, "Failed to fetch thread context");
|
|
310
|
-
}
|
|
311
|
-
return "";
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
//#endregion
|
|
315
|
-
export { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, postErrorMessage, sendResponseUrlMessage };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
|
|
2
|
-
import { Agent, AgentWithProject, ApiKey, ApiKeyCreationResponse, ChatCompletionResponse, ChatMessage, PaginatedResponse, Project, SlackApiClient, SlackApiClientConfig, SlackApiError, createSlackApiClient, sendDeferredResponse } from "./api-client.js";
|
|
3
|
-
import { ChatCompletionOptions, ChatCompletionResult, SlackAccessTokenPayload, SlackJwtAuthError, SlackJwtResult, SlackUserContext, executeAgentWithSlackJwt, getSlackUserJwt, streamAgentWithSlackJwt, verifySlackJwt } from "./auth/index.js";
|
|
4
|
-
import { AgentConfigSources, createAgentListMessage, createAgentResponseMessage, createAlreadyConnectedMessage, createAlreadyLinkedMessage, createDeviceCodeMessage, createErrorMessage, createHelpMessage, createJwtLinkMessage, createLinkExpiredMessage, createLinkMessage, createLinkSuccessMessage, createLogoutSuccessMessage, createNoDefaultAgentMessage, createNoProjectsMessage, createNotLinkedMessage, createProjectListMessage, createSettingsMessage, createSettingsUpdatedMessage, createStatusConnectedMessage, createStatusMessage, createStatusNotConnectedMessage, createThinkingMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
|
|
5
|
-
import { getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread } from "./client.js";
|
|
6
|
-
import { SlackCommandPayload, SlackCommandResponse } from "./types.js";
|
|
7
|
-
import { handleAgentListCommand, handleCommand, handleHelpCommand, handleLinkCommand, handleLogoutCommand, handleQuestionCommand, handleRunCommand, handleSettingsCommand, handleStatusCommand, handleUnlinkCommand } from "./commands/index.js";
|
|
8
|
-
import { InlineSelectorMetadata, handleAppMention } from "./events/app-mention.js";
|
|
9
|
-
import { AgentOption, BuildAgentSelectorModalParams, ModalMetadata, ModalSubmissionData, buildAgentSelectorModal, parseModalSubmission } from "./modals.js";
|
|
10
|
-
import { handleModalProjectSelect, handleOpenAgentSelectorModal, handleShareToChannel, handleShareToThread } from "./events/block-actions.js";
|
|
11
|
-
import { handleModalSubmission } from "./events/modal-submission.js";
|
|
12
|
-
import { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
|
|
13
|
-
import { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
14
|
-
import { StreamResult, streamAgentResponse } from "./events/streaming.js";
|
|
15
|
-
import "./events/index.js";
|
|
16
|
-
import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
|
|
17
|
-
import { clearBotTokenForTeam, getAllWorkspaceTokens, getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
|
|
18
|
-
export { Agent, AgentConfigSources, AgentOption, AgentResolutionParams, AgentWithProject, ApiKey, ApiKeyCreationResponse, BuildAgentSelectorModalParams, ChatCompletionOptions, ChatCompletionResponse, ChatCompletionResult, ChatMessage, DefaultAgentConfig, InlineSelectorMetadata, ModalMetadata, ModalSubmissionData, PaginatedResponse, Project, ResolvedAgentConfig, SlackAccessTokenPayload, SlackApiClient, SlackApiClientConfig, SlackApiError, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackJwtAuthError, SlackJwtResult, SlackUserContext, SlackWorkspaceConnection, StreamResult, WorkspaceInstallData, buildAgentSelectorModal, checkIfBotThread, classifyError, clearBotTokenForTeam, computeWorkspaceConnectionId, createAgentListMessage, createAgentResponseMessage, createAlreadyConnectedMessage, createAlreadyLinkedMessage, createConnectSession, createDeviceCodeMessage, createErrorMessage, createHelpMessage, createJwtLinkMessage, createLinkExpiredMessage, createLinkMessage, createLinkSuccessMessage, createLogoutSuccessMessage, createNoDefaultAgentMessage, createNoProjectsMessage, createNotLinkedMessage, createProjectListMessage, createSettingsMessage, createSettingsUpdatedMessage, createSlackApiClient, createStatusConnectedMessage, createStatusMessage, createStatusNotConnectedMessage, createThinkingMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentWithSlackJwt, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getAllWorkspaceTokens, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getSlackUserJwt, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentListCommand, handleAppMention, handleCommand, handleHelpCommand, handleLinkCommand, handleLogoutCommand, handleModalProjectSelect, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleRunCommand, handleSettingsCommand, handleShareToChannel, handleShareToThread, handleStatusCommand, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseModalSubmission, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, sendDeferredResponse, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, streamAgentWithSlackJwt, updateConnectionMetadata, verifySlackJwt, verifySlackRequest };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
|
|
2
|
-
import { getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
|
|
3
|
-
import { SlackApiClient, SlackApiError, createSlackApiClient, sendDeferredResponse } from "./api-client.js";
|
|
4
|
-
import { SlackJwtAuthError, executeAgentWithSlackJwt, getSlackUserJwt, streamAgentWithSlackJwt, verifySlackJwt } from "./auth/index.js";
|
|
5
|
-
import { createAgentListMessage, createAgentResponseMessage, createAlreadyConnectedMessage, createAlreadyLinkedMessage, createDeviceCodeMessage, createErrorMessage, createHelpMessage, createJwtLinkMessage, createLinkExpiredMessage, createLinkMessage, createLinkSuccessMessage, createLogoutSuccessMessage, createNoDefaultAgentMessage, createNoProjectsMessage, createNotLinkedMessage, createProjectListMessage, createSettingsMessage, createSettingsUpdatedMessage, createStatusConnectedMessage, createStatusMessage, createStatusNotConnectedMessage, createThinkingMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
|
|
6
|
-
import { getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread } from "./client.js";
|
|
7
|
-
import { handleAgentListCommand, handleCommand, handleHelpCommand, handleLinkCommand, handleLogoutCommand, handleQuestionCommand, handleRunCommand, handleSettingsCommand, handleStatusCommand, handleUnlinkCommand } from "./commands/index.js";
|
|
8
|
-
import { clearBotTokenForTeam, getAllWorkspaceTokens, getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
|
|
9
|
-
import { SlackErrorType, checkIfBotThread, classifyError, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
10
|
-
import { streamAgentResponse } from "./events/streaming.js";
|
|
11
|
-
import { handleAppMention } from "./events/app-mention.js";
|
|
12
|
-
import { buildAgentSelectorModal, parseModalSubmission } from "./modals.js";
|
|
13
|
-
import { handleModalProjectSelect, handleOpenAgentSelectorModal, handleShareToChannel, handleShareToThread } from "./events/block-actions.js";
|
|
14
|
-
import { handleModalSubmission } from "./events/modal-submission.js";
|
|
15
|
-
import "./events/index.js";
|
|
16
|
-
import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
|
|
17
|
-
|
|
18
|
-
export { SlackApiClient, SlackApiError, SlackErrorType, SlackJwtAuthError, buildAgentSelectorModal, checkIfBotThread, classifyError, clearBotTokenForTeam, computeWorkspaceConnectionId, createAgentListMessage, createAgentResponseMessage, createAlreadyConnectedMessage, createAlreadyLinkedMessage, createConnectSession, createDeviceCodeMessage, createErrorMessage, createHelpMessage, createJwtLinkMessage, createLinkExpiredMessage, createLinkMessage, createLinkSuccessMessage, createLogoutSuccessMessage, createNoDefaultAgentMessage, createNoProjectsMessage, createNotLinkedMessage, createProjectListMessage, createSettingsMessage, createSettingsUpdatedMessage, createSlackApiClient, createStatusConnectedMessage, createStatusMessage, createStatusNotConnectedMessage, createThinkingMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentWithSlackJwt, fetchAgentsForProject, fetchAgentsForTenant, fetchProjectsForTenant, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getAllWorkspaceTokens, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getSlackUserJwt, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentListCommand, handleAppMention, handleCommand, handleHelpCommand, handleLinkCommand, handleLogoutCommand, handleModalProjectSelect, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleRunCommand, handleSettingsCommand, handleShareToChannel, handleShareToThread, handleStatusCommand, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseModalSubmission, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, sendDeferredResponse, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, streamAgentWithSlackJwt, updateConnectionMetadata, verifySlackJwt, verifySlackRequest };
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { ModalView } from "@slack/web-api";
|
|
2
|
-
|
|
3
|
-
//#region src/slack/services/modals.d.ts
|
|
4
|
-
|
|
5
|
-
/** Agent option for dropdown selection */
|
|
6
|
-
interface AgentOption {
|
|
7
|
-
id: string;
|
|
8
|
-
name: string | null;
|
|
9
|
-
projectId: string;
|
|
10
|
-
projectName: string | null;
|
|
11
|
-
}
|
|
12
|
-
interface ModalMetadata {
|
|
13
|
-
channel: string;
|
|
14
|
-
threadTs?: string;
|
|
15
|
-
messageTs: string;
|
|
16
|
-
teamId: string;
|
|
17
|
-
slackUserId: string;
|
|
18
|
-
tenantId: string;
|
|
19
|
-
isInThread: boolean;
|
|
20
|
-
threadMessageCount?: number;
|
|
21
|
-
buttonResponseUrl?: string;
|
|
22
|
-
}
|
|
23
|
-
interface BuildAgentSelectorModalParams {
|
|
24
|
-
projects: Array<{
|
|
25
|
-
id: string;
|
|
26
|
-
name: string;
|
|
27
|
-
}>;
|
|
28
|
-
agents: AgentOption[];
|
|
29
|
-
metadata: ModalMetadata;
|
|
30
|
-
selectedProjectId?: string;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Build the agent selector modal for thread context.
|
|
34
|
-
*
|
|
35
|
-
* Shows:
|
|
36
|
-
* - Project dropdown
|
|
37
|
-
* - Agent dropdown (updates based on project selection)
|
|
38
|
-
* - Include thread context checkbox (if in thread)
|
|
39
|
-
* - Question/instructions input
|
|
40
|
-
* - Private response checkbox
|
|
41
|
-
*
|
|
42
|
-
* @param params - Modal configuration parameters
|
|
43
|
-
* @returns Slack ModalView object ready for views.open()
|
|
44
|
-
*/
|
|
45
|
-
declare function buildAgentSelectorModal(params: BuildAgentSelectorModalParams): ModalView;
|
|
46
|
-
interface ModalSubmissionData {
|
|
47
|
-
agentId: string;
|
|
48
|
-
projectId: string;
|
|
49
|
-
question: string;
|
|
50
|
-
isEphemeral: boolean;
|
|
51
|
-
metadata: ModalMetadata;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Parse the modal submission payload from Slack.
|
|
55
|
-
* Extracts agent selection, question, and visibility settings.
|
|
56
|
-
*
|
|
57
|
-
* @param view - The view object from view_submission event
|
|
58
|
-
* @returns Parsed submission data, or null if parsing fails
|
|
59
|
-
*/
|
|
60
|
-
declare function parseModalSubmission(view: {
|
|
61
|
-
private_metadata?: string;
|
|
62
|
-
state?: {
|
|
63
|
-
values?: Record<string, Record<string, unknown>>;
|
|
64
|
-
};
|
|
65
|
-
}): ModalSubmissionData | null;
|
|
66
|
-
//#endregion
|
|
67
|
-
export { AgentOption, BuildAgentSelectorModalParams, ModalMetadata, ModalSubmissionData, buildAgentSelectorModal, parseModalSubmission };
|