@inkeep/agents-work-apps 0.0.0-dev-20260220022607 → 0.0.0-dev-20260220220716
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/github/mcp/schemas.d.ts +1 -1
- package/dist/slack/dispatcher.js +24 -1
- package/dist/slack/i18n/strings.d.ts +1 -0
- package/dist/slack/i18n/strings.js +1 -0
- package/dist/slack/services/blocks/index.d.ts +47 -1
- package/dist/slack/services/blocks/index.js +93 -19
- package/dist/slack/services/events/app-mention.js +2 -2
- package/dist/slack/services/events/block-actions.d.ts +12 -1
- package/dist/slack/services/events/block-actions.js +126 -2
- package/dist/slack/services/events/index.d.ts +2 -2
- package/dist/slack/services/events/index.js +2 -2
- package/dist/slack/services/events/streaming.d.ts +1 -1
- package/dist/slack/services/events/streaming.js +71 -3
- package/dist/slack/services/events/utils.js +5 -2
- package/dist/slack/services/index.d.ts +3 -3
- package/dist/slack/services/index.js +3 -3
- package/dist/slack/tracer.d.ts +1 -0
- package/dist/slack/tracer.js +2 -1
- package/package.json +2 -2
package/dist/slack/dispatcher.js
CHANGED
|
@@ -4,7 +4,7 @@ import { getSlackClient } from "./services/client.js";
|
|
|
4
4
|
import { sendResponseUrlMessage } from "./services/events/utils.js";
|
|
5
5
|
import { SLACK_SPAN_KEYS } from "./tracer.js";
|
|
6
6
|
import { handleAppMention } from "./services/events/app-mention.js";
|
|
7
|
-
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./services/events/block-actions.js";
|
|
7
|
+
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleToolApproval } from "./services/events/block-actions.js";
|
|
8
8
|
import { handleFollowUpSubmission, handleModalSubmission } from "./services/events/modal-submission.js";
|
|
9
9
|
import "./services/events/index.js";
|
|
10
10
|
import "./services/index.js";
|
|
@@ -176,6 +176,29 @@ async function dispatchSlackEvent(eventType, payload, options, span) {
|
|
|
176
176
|
}
|
|
177
177
|
})());
|
|
178
178
|
}
|
|
179
|
+
if ((action.action_id === "tool_approval_approve" || action.action_id === "tool_approval_deny") && action.value) {
|
|
180
|
+
anyHandled = true;
|
|
181
|
+
const approved = action.action_id === "tool_approval_approve";
|
|
182
|
+
const slackUserId = payload.user?.id || "";
|
|
183
|
+
logger.info({
|
|
184
|
+
teamId,
|
|
185
|
+
actionId: action.action_id,
|
|
186
|
+
approved
|
|
187
|
+
}, `Handling block_action: ${action.action_id}`);
|
|
188
|
+
registerBackgroundWork(handleToolApproval({
|
|
189
|
+
actionValue: action.value,
|
|
190
|
+
approved,
|
|
191
|
+
teamId,
|
|
192
|
+
slackUserId,
|
|
193
|
+
responseUrl
|
|
194
|
+
}).catch((err) => {
|
|
195
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
196
|
+
logger.error({
|
|
197
|
+
errorMessage,
|
|
198
|
+
actionId: action.action_id
|
|
199
|
+
}, "Failed to handle tool approval");
|
|
200
|
+
}).finally(() => flushTraces()));
|
|
201
|
+
}
|
|
179
202
|
if (action.action_id === "open_follow_up_modal" && action.value && triggerId) {
|
|
180
203
|
anyHandled = true;
|
|
181
204
|
logger.info({
|
|
@@ -45,6 +45,7 @@ declare const SlackStrings: {
|
|
|
45
45
|
};
|
|
46
46
|
readonly status: {
|
|
47
47
|
readonly thinking: (agentName: string) => string;
|
|
48
|
+
readonly readingThread: (agentName: string) => string;
|
|
48
49
|
readonly noAgentsAvailable: "No agents available";
|
|
49
50
|
readonly noProjectsConfigured: "No projects configured. Set up projects in the dashboard.";
|
|
50
51
|
};
|
|
@@ -41,6 +41,7 @@ const SlackStrings = {
|
|
|
41
41
|
usage: { mentionEmpty: "*Include a message to use your Inkeep agent:*\n\n• `@Inkeep <message>` — Message the default agent (reply appears in a thread)\n• `@Inkeep <message>` in a thread — Includes thread as context\n• `@Inkeep` in a thread — Uses the full thread as context\n\nUse `/inkeep help` for all available commands." },
|
|
42
42
|
status: {
|
|
43
43
|
thinking: (agentName) => `_${agentName} is thinking..._`,
|
|
44
|
+
readingThread: (agentName) => `_${agentName} is reading this thread..._`,
|
|
44
45
|
noAgentsAvailable: "No agents available",
|
|
45
46
|
noProjectsConfigured: "No projects configured. Set up projects in the dashboard."
|
|
46
47
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
1
2
|
import * as slack_block_builder0 from "slack-block-builder";
|
|
2
3
|
|
|
3
4
|
//#region src/slack/services/blocks/index.d.ts
|
|
@@ -63,6 +64,51 @@ interface AgentConfigSources {
|
|
|
63
64
|
} | null;
|
|
64
65
|
}
|
|
65
66
|
declare function createStatusMessage(email: string, linkedAt: string, dashboardUrl: string, agentConfigs: AgentConfigSources): Readonly<slack_block_builder0.SlackMessageDto>;
|
|
67
|
+
interface ToolApprovalButtonValue {
|
|
68
|
+
toolCallId: string;
|
|
69
|
+
conversationId: string;
|
|
70
|
+
projectId: string;
|
|
71
|
+
agentId: string;
|
|
72
|
+
slackUserId: string;
|
|
73
|
+
channel: string;
|
|
74
|
+
threadTs: string;
|
|
75
|
+
toolName: string;
|
|
76
|
+
}
|
|
77
|
+
declare const ToolApprovalButtonValueSchema: z.ZodObject<{
|
|
78
|
+
toolCallId: z.ZodString;
|
|
79
|
+
conversationId: z.ZodString;
|
|
80
|
+
projectId: z.ZodString;
|
|
81
|
+
agentId: z.ZodString;
|
|
82
|
+
slackUserId: z.ZodString;
|
|
83
|
+
channel: z.ZodString;
|
|
84
|
+
threadTs: z.ZodString;
|
|
85
|
+
toolName: z.ZodString;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
declare function buildToolApprovalBlocks(params: {
|
|
88
|
+
toolName: string;
|
|
89
|
+
input?: Record<string, unknown>;
|
|
90
|
+
buttonValue: string;
|
|
91
|
+
}): any[];
|
|
92
|
+
declare function buildToolApprovalDoneBlocks(params: {
|
|
93
|
+
toolName: string;
|
|
94
|
+
approved: boolean;
|
|
95
|
+
actorUserId: string;
|
|
96
|
+
}): {
|
|
97
|
+
type: string;
|
|
98
|
+
elements: {
|
|
99
|
+
type: string;
|
|
100
|
+
text: string;
|
|
101
|
+
}[];
|
|
102
|
+
}[];
|
|
103
|
+
declare function buildToolApprovalExpiredBlocks(params: {
|
|
104
|
+
toolName: string;
|
|
105
|
+
}): {
|
|
106
|
+
type: string;
|
|
107
|
+
elements: {
|
|
108
|
+
type: string;
|
|
109
|
+
text: string;
|
|
110
|
+
}[];
|
|
111
|
+
}[];
|
|
66
112
|
declare function createJwtLinkMessage(linkUrl: string, expiresInMinutes: number): Readonly<slack_block_builder0.SlackMessageDto>;
|
|
67
113
|
//#endregion
|
|
68
|
-
export { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, buildConversationResponseBlocks, buildFollowUpButton, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
|
|
114
|
+
export { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SlackStrings } from "../../i18n/strings.js";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
import { Blocks, Elements, Md, Message } from "slack-block-builder";
|
|
3
4
|
|
|
4
5
|
//#region src/slack/services/blocks/index.ts
|
|
@@ -34,24 +35,14 @@ function buildFollowUpButton(params) {
|
|
|
34
35
|
* Shows the user's message, a divider, the agent response, context, and a Follow Up button.
|
|
35
36
|
*/
|
|
36
37
|
function buildConversationResponseBlocks(params) {
|
|
37
|
-
const {
|
|
38
|
-
const blocks = [
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
text: `*You:* ${userMessage.length > 200 ? `${userMessage.slice(0, 200)}...` : userMessage}`
|
|
44
|
-
}]
|
|
45
|
-
},
|
|
46
|
-
{ type: "divider" },
|
|
47
|
-
{
|
|
48
|
-
type: "section",
|
|
49
|
-
text: {
|
|
50
|
-
type: "mrkdwn",
|
|
51
|
-
text: responseText
|
|
52
|
-
}
|
|
38
|
+
const { responseText, agentName, isError, followUpParams } = params;
|
|
39
|
+
const blocks = [{
|
|
40
|
+
type: "section",
|
|
41
|
+
text: {
|
|
42
|
+
type: "mrkdwn",
|
|
43
|
+
text: responseText
|
|
53
44
|
}
|
|
54
|
-
];
|
|
45
|
+
}];
|
|
55
46
|
if (!isError) {
|
|
56
47
|
const contextBlock = createContextBlock({
|
|
57
48
|
agentName,
|
|
@@ -66,7 +57,7 @@ function buildConversationResponseBlocks(params) {
|
|
|
66
57
|
return blocks;
|
|
67
58
|
}
|
|
68
59
|
function createUpdatedHelpMessage() {
|
|
69
|
-
return Message().blocks(Blocks.
|
|
60
|
+
return Message().blocks(Blocks.Header().text(SlackStrings.help.title), Blocks.Section().text(SlackStrings.help.publicSection), Blocks.Divider(), Blocks.Section().text(SlackStrings.help.privateSection), Blocks.Divider(), Blocks.Section().text(SlackStrings.help.otherCommands), Blocks.Divider(), Blocks.Context().elements(SlackStrings.help.docsLink)).buildToObject();
|
|
70
61
|
}
|
|
71
62
|
function createAlreadyLinkedMessage(email, linkedAt, dashboardUrl) {
|
|
72
63
|
return Message().blocks(Blocks.Section().text(Md.bold("Already linked") + "\n\nYour Slack account is connected to Inkeep.\n\n" + Md.bold("Account:") + ` ${email}\n` + Md.bold("Linked:") + ` ${new Date(linkedAt).toLocaleDateString()}\n\nTo switch accounts, first run \`/inkeep unlink\``), Blocks.Actions().elements(Elements.Button().text(SlackStrings.buttons.openDashboard).url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
|
|
@@ -84,9 +75,92 @@ function createStatusMessage(email, linkedAt, dashboardUrl, agentConfigs) {
|
|
|
84
75
|
else agentLine = `${Md.bold("Agent:")} None configured\n${Md.italic("Ask your admin to set up an agent in the dashboard.")}`;
|
|
85
76
|
return Message().blocks(Blocks.Section().text(Md.bold("Connected to Inkeep") + `\n\n${Md.bold("Account:")} ${email}\n${Md.bold("Linked:")} ${new Date(linkedAt).toLocaleDateString()}\n` + agentLine), Blocks.Actions().elements(Elements.Button().text(SlackStrings.buttons.openDashboard).url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
|
|
86
77
|
}
|
|
78
|
+
const ToolApprovalButtonValueSchema = z.object({
|
|
79
|
+
toolCallId: z.string(),
|
|
80
|
+
conversationId: z.string(),
|
|
81
|
+
projectId: z.string(),
|
|
82
|
+
agentId: z.string(),
|
|
83
|
+
slackUserId: z.string(),
|
|
84
|
+
channel: z.string(),
|
|
85
|
+
threadTs: z.string(),
|
|
86
|
+
toolName: z.string()
|
|
87
|
+
});
|
|
88
|
+
function buildToolApprovalBlocks(params) {
|
|
89
|
+
const { toolName, input, buttonValue } = params;
|
|
90
|
+
const blocks = [{
|
|
91
|
+
type: "header",
|
|
92
|
+
text: {
|
|
93
|
+
type: "plain_text",
|
|
94
|
+
text: "Tool Approval Required",
|
|
95
|
+
emoji: false
|
|
96
|
+
}
|
|
97
|
+
}, {
|
|
98
|
+
type: "section",
|
|
99
|
+
text: {
|
|
100
|
+
type: "mrkdwn",
|
|
101
|
+
text: `The agent wants to use \`${toolName}\`.`
|
|
102
|
+
}
|
|
103
|
+
}];
|
|
104
|
+
if (input && Object.keys(input).length > 0) {
|
|
105
|
+
const jsonStr = JSON.stringify(input, null, 2);
|
|
106
|
+
const truncated = jsonStr.length > 2900 ? `${jsonStr.slice(0, 2900)}…` : jsonStr;
|
|
107
|
+
blocks.push({
|
|
108
|
+
type: "section",
|
|
109
|
+
text: {
|
|
110
|
+
type: "mrkdwn",
|
|
111
|
+
text: `\`\`\`json\n${truncated}\n\`\`\``
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
blocks.push({ type: "divider" });
|
|
116
|
+
blocks.push({
|
|
117
|
+
type: "actions",
|
|
118
|
+
elements: [{
|
|
119
|
+
type: "button",
|
|
120
|
+
text: {
|
|
121
|
+
type: "plain_text",
|
|
122
|
+
text: "Approve",
|
|
123
|
+
emoji: false
|
|
124
|
+
},
|
|
125
|
+
style: "primary",
|
|
126
|
+
action_id: "tool_approval_approve",
|
|
127
|
+
value: buttonValue
|
|
128
|
+
}, {
|
|
129
|
+
type: "button",
|
|
130
|
+
text: {
|
|
131
|
+
type: "plain_text",
|
|
132
|
+
text: "Deny",
|
|
133
|
+
emoji: false
|
|
134
|
+
},
|
|
135
|
+
style: "danger",
|
|
136
|
+
action_id: "tool_approval_deny",
|
|
137
|
+
value: buttonValue
|
|
138
|
+
}]
|
|
139
|
+
});
|
|
140
|
+
return blocks;
|
|
141
|
+
}
|
|
142
|
+
function buildToolApprovalDoneBlocks(params) {
|
|
143
|
+
const { toolName, approved, actorUserId } = params;
|
|
144
|
+
return [{
|
|
145
|
+
type: "context",
|
|
146
|
+
elements: [{
|
|
147
|
+
type: "mrkdwn",
|
|
148
|
+
text: approved ? `✅ Approved \`${toolName}\` · <@${actorUserId}>` : `❌ Denied \`${toolName}\` · <@${actorUserId}>`
|
|
149
|
+
}]
|
|
150
|
+
}];
|
|
151
|
+
}
|
|
152
|
+
function buildToolApprovalExpiredBlocks(params) {
|
|
153
|
+
return [{
|
|
154
|
+
type: "context",
|
|
155
|
+
elements: [{
|
|
156
|
+
type: "mrkdwn",
|
|
157
|
+
text: `⏱️ Expired · \`${params.toolName}\``
|
|
158
|
+
}]
|
|
159
|
+
}];
|
|
160
|
+
}
|
|
87
161
|
function createJwtLinkMessage(linkUrl, expiresInMinutes) {
|
|
88
162
|
return Message().blocks(Blocks.Section().text(`${Md.bold("Link your Inkeep account")}\n\nConnect your Slack and Inkeep accounts to use Inkeep agents.`), Blocks.Actions().elements(Elements.Button().text("Link Account").url(linkUrl).actionId("link_account").primary()), Blocks.Context().elements(`This link expires in ${expiresInMinutes} minutes.`)).buildToObject();
|
|
89
163
|
}
|
|
90
164
|
|
|
91
165
|
//#endregion
|
|
92
|
-
export { buildConversationResponseBlocks, buildFollowUpButton, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
|
|
166
|
+
export { ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
|
|
@@ -196,7 +196,7 @@ async function handleAppMention(params) {
|
|
|
196
196
|
thinkingMessageTs = (await slackClient.chat.postMessage({
|
|
197
197
|
channel,
|
|
198
198
|
thread_ts: threadTs,
|
|
199
|
-
text:
|
|
199
|
+
text: SlackStrings.status.readingThread(agentDisplayName)
|
|
200
200
|
})).ts || void 0;
|
|
201
201
|
const conversationId$1 = generateSlackConversationId({
|
|
202
202
|
teamId,
|
|
@@ -274,7 +274,7 @@ Respond naturally as if you're joining the conversation to help.`;
|
|
|
274
274
|
thinkingMessageTs = (await slackClient.chat.postMessage({
|
|
275
275
|
channel,
|
|
276
276
|
thread_ts: replyThreadTs,
|
|
277
|
-
text:
|
|
277
|
+
text: SlackStrings.status.thinking(agentDisplayName)
|
|
278
278
|
})).ts || void 0;
|
|
279
279
|
const conversationId = generateSlackConversationId({
|
|
280
280
|
teamId,
|
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
* Handlers for Slack block action events (button clicks, selections, etc.)
|
|
4
4
|
* and message shortcuts
|
|
5
5
|
*/
|
|
6
|
+
/**
|
|
7
|
+
* Handle tool approval/denial button clicks.
|
|
8
|
+
* Called when a user clicks "Approve" or "Deny" on a tool approval message.
|
|
9
|
+
*/
|
|
10
|
+
declare function handleToolApproval(params: {
|
|
11
|
+
actionValue: string;
|
|
12
|
+
approved: boolean;
|
|
13
|
+
teamId: string;
|
|
14
|
+
slackUserId: string;
|
|
15
|
+
responseUrl?: string;
|
|
16
|
+
}): Promise<void>;
|
|
6
17
|
/**
|
|
7
18
|
* Handle opening the agent selector modal when user clicks "Select Agent" button
|
|
8
19
|
*/
|
|
@@ -37,4 +48,4 @@ declare function handleMessageShortcut(params: {
|
|
|
37
48
|
responseUrl?: string;
|
|
38
49
|
}): Promise<void>;
|
|
39
50
|
//#endregion
|
|
40
|
-
export { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal };
|
|
51
|
+
export { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleToolApproval };
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { env } from "../../../env.js";
|
|
1
2
|
import { getLogger } from "../../../logger.js";
|
|
2
3
|
import { findWorkspaceConnectionByTeamId } from "../nango.js";
|
|
3
4
|
import { SlackStrings } from "../../i18n/strings.js";
|
|
5
|
+
import { ToolApprovalButtonValueSchema, buildToolApprovalDoneBlocks } from "../blocks/index.js";
|
|
4
6
|
import { getSlackClient } from "../client.js";
|
|
5
|
-
import { fetchAgentsForProject, fetchProjectsForTenant, getChannelAgentConfig, sendResponseUrlMessage } from "./utils.js";
|
|
7
|
+
import { fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, getChannelAgentConfig, sendResponseUrlMessage } from "./utils.js";
|
|
6
8
|
import { buildAgentSelectorModal, buildFollowUpModal, buildMessageShortcutModal } from "../modals.js";
|
|
7
9
|
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
10
|
+
import { getInProcessFetch, signSlackUserToken } from "@inkeep/agents-core";
|
|
8
11
|
|
|
9
12
|
//#region src/slack/services/events/block-actions.ts
|
|
10
13
|
/**
|
|
@@ -13,6 +16,127 @@ import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../
|
|
|
13
16
|
*/
|
|
14
17
|
const logger = getLogger("slack-block-actions");
|
|
15
18
|
/**
|
|
19
|
+
* Handle tool approval/denial button clicks.
|
|
20
|
+
* Called when a user clicks "Approve" or "Deny" on a tool approval message.
|
|
21
|
+
*/
|
|
22
|
+
async function handleToolApproval(params) {
|
|
23
|
+
return tracer.startActiveSpan(SLACK_SPAN_NAMES.TOOL_APPROVAL, async (span) => {
|
|
24
|
+
const { actionValue, approved, teamId, slackUserId, responseUrl } = params;
|
|
25
|
+
span.setAttribute(SLACK_SPAN_KEYS.TEAM_ID, teamId);
|
|
26
|
+
span.setAttribute(SLACK_SPAN_KEYS.USER_ID, slackUserId);
|
|
27
|
+
try {
|
|
28
|
+
const buttonValue = ToolApprovalButtonValueSchema.parse(JSON.parse(actionValue));
|
|
29
|
+
const { toolCallId, conversationId, projectId, agentId, toolName } = buttonValue;
|
|
30
|
+
span.setAttribute(SLACK_SPAN_KEYS.CONVERSATION_ID, conversationId);
|
|
31
|
+
const workspaceConnection = await findWorkspaceConnectionByTeamId(teamId);
|
|
32
|
+
if (!workspaceConnection?.botToken) {
|
|
33
|
+
logger.error({ teamId }, "No bot token for tool approval");
|
|
34
|
+
span.end();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const tenantId = workspaceConnection.tenantId;
|
|
38
|
+
const slackClient = getSlackClient(workspaceConnection.botToken);
|
|
39
|
+
if (slackUserId !== buttonValue.slackUserId) {
|
|
40
|
+
await slackClient.chat.postEphemeral({
|
|
41
|
+
channel: buttonValue.channel,
|
|
42
|
+
user: slackUserId,
|
|
43
|
+
thread_ts: buttonValue.threadTs,
|
|
44
|
+
text: "Only the user who started this conversation can approve or deny this action."
|
|
45
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to send ownership error notification"));
|
|
46
|
+
span.end();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const existingLink = await findCachedUserMapping(tenantId, slackUserId, teamId);
|
|
50
|
+
if (!existingLink) {
|
|
51
|
+
await slackClient.chat.postEphemeral({
|
|
52
|
+
channel: buttonValue.channel,
|
|
53
|
+
user: slackUserId,
|
|
54
|
+
thread_ts: buttonValue.threadTs,
|
|
55
|
+
text: "You need to link your Inkeep account first. Use `/inkeep link`."
|
|
56
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to send not-linked notification"));
|
|
57
|
+
span.end();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const slackUserToken = await signSlackUserToken({
|
|
61
|
+
inkeepUserId: existingLink.inkeepUserId,
|
|
62
|
+
tenantId,
|
|
63
|
+
slackTeamId: teamId,
|
|
64
|
+
slackUserId
|
|
65
|
+
});
|
|
66
|
+
const apiUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
|
|
67
|
+
const approvalResponse = await getInProcessFetch()(`${apiUrl}/run/api/chat`, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
Authorization: `Bearer ${slackUserToken}`,
|
|
72
|
+
"x-inkeep-project-id": projectId,
|
|
73
|
+
"x-inkeep-agent-id": agentId
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
conversationId,
|
|
77
|
+
messages: [{
|
|
78
|
+
role: "tool",
|
|
79
|
+
parts: [{
|
|
80
|
+
type: "tool-call",
|
|
81
|
+
toolCallId,
|
|
82
|
+
state: "approval-responded",
|
|
83
|
+
approval: {
|
|
84
|
+
id: toolCallId,
|
|
85
|
+
approved
|
|
86
|
+
}
|
|
87
|
+
}]
|
|
88
|
+
}]
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
if (!approvalResponse.ok) {
|
|
92
|
+
const errorBody = await approvalResponse.text().catch(() => "");
|
|
93
|
+
logger.error({
|
|
94
|
+
status: approvalResponse.status,
|
|
95
|
+
errorBody,
|
|
96
|
+
toolCallId,
|
|
97
|
+
conversationId
|
|
98
|
+
}, "Tool approval API call failed");
|
|
99
|
+
await slackClient.chat.postEphemeral({
|
|
100
|
+
channel: buttonValue.channel,
|
|
101
|
+
user: slackUserId,
|
|
102
|
+
thread_ts: buttonValue.threadTs,
|
|
103
|
+
text: `Failed to ${approved ? "approve" : "deny"} \`${toolName}\`. Please try again.`
|
|
104
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to send approval error notification"));
|
|
105
|
+
span.end();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
109
|
+
text: approved ? `✅ Approved \`${toolName}\`` : `❌ Denied \`${toolName}\``,
|
|
110
|
+
replace_original: true,
|
|
111
|
+
blocks: buildToolApprovalDoneBlocks({
|
|
112
|
+
toolName,
|
|
113
|
+
approved,
|
|
114
|
+
actorUserId: slackUserId
|
|
115
|
+
})
|
|
116
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to update approval message"));
|
|
117
|
+
logger.info({
|
|
118
|
+
toolCallId,
|
|
119
|
+
conversationId,
|
|
120
|
+
approved,
|
|
121
|
+
slackUserId
|
|
122
|
+
}, "Tool approval processed");
|
|
123
|
+
span.end();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (error instanceof Error) setSpanWithError(span, error);
|
|
126
|
+
logger.error({
|
|
127
|
+
error,
|
|
128
|
+
teamId,
|
|
129
|
+
slackUserId
|
|
130
|
+
}, "Failed to handle tool approval");
|
|
131
|
+
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
132
|
+
text: "Something went wrong processing your request. Please try again.",
|
|
133
|
+
response_type: "ephemeral"
|
|
134
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to send error notification"));
|
|
135
|
+
span.end();
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
16
140
|
* Handle opening the agent selector modal when user clicks "Select Agent" button
|
|
17
141
|
*/
|
|
18
142
|
async function handleOpenAgentSelectorModal(params) {
|
|
@@ -262,4 +386,4 @@ async function handleMessageShortcut(params) {
|
|
|
262
386
|
}
|
|
263
387
|
|
|
264
388
|
//#endregion
|
|
265
|
-
export { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal };
|
|
389
|
+
export { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleToolApproval };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InlineSelectorMetadata, handleAppMention } from "./app-mention.js";
|
|
2
|
-
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./block-actions.js";
|
|
2
|
+
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleToolApproval } from "./block-actions.js";
|
|
3
3
|
import { handleFollowUpSubmission, handleModalSubmission } from "./modal-submission.js";
|
|
4
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, extractApiErrorMessage, 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, handleToolApproval, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
2
2
|
import { streamAgentResponse } from "./streaming.js";
|
|
3
3
|
import { handleAppMention } from "./app-mention.js";
|
|
4
|
-
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./block-actions.js";
|
|
4
|
+
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleToolApproval } from "./block-actions.js";
|
|
5
5
|
import { handleFollowUpSubmission, handleModalSubmission } from "./modal-submission.js";
|
|
6
6
|
|
|
7
|
-
export { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, 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, handleToolApproval, markdownToMrkdwn, sendResponseUrlMessage, streamAgentResponse };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { env } from "../../../env.js";
|
|
2
2
|
import { getLogger } from "../../../logger.js";
|
|
3
|
-
import { createContextBlock } from "../blocks/index.js";
|
|
3
|
+
import { buildToolApprovalBlocks, buildToolApprovalExpiredBlocks, createContextBlock } from "../blocks/index.js";
|
|
4
4
|
import { SlackErrorType, classifyError, extractApiErrorMessage, getUserFriendlyErrorMessage } from "./utils.js";
|
|
5
5
|
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
6
6
|
import { getInProcessFetch } from "@inkeep/agents-core";
|
|
@@ -50,6 +50,10 @@ async function streamAgentResponse(params) {
|
|
|
50
50
|
projectId
|
|
51
51
|
}, "Starting streaming agent response");
|
|
52
52
|
const abortController = new AbortController();
|
|
53
|
+
const abortPromise = new Promise((_, reject) => {
|
|
54
|
+
abortController.signal.addEventListener("abort", () => reject(/* @__PURE__ */ new Error("Stream timeout")), { once: true });
|
|
55
|
+
});
|
|
56
|
+
let reader;
|
|
53
57
|
const timeoutId = setTimeout(() => {
|
|
54
58
|
logger.warn({
|
|
55
59
|
channel,
|
|
@@ -177,7 +181,7 @@ async function streamAgentResponse(params) {
|
|
|
177
181
|
errorMessage
|
|
178
182
|
};
|
|
179
183
|
}
|
|
180
|
-
|
|
184
|
+
reader = response.body.getReader();
|
|
181
185
|
const decoder = new TextDecoder();
|
|
182
186
|
let buffer = "";
|
|
183
187
|
let fullText = "";
|
|
@@ -187,10 +191,11 @@ async function streamAgentResponse(params) {
|
|
|
187
191
|
recipient_user_id: slackUserId,
|
|
188
192
|
thread_ts: threadTs
|
|
189
193
|
});
|
|
194
|
+
const pendingApprovalMessages = [];
|
|
190
195
|
try {
|
|
191
196
|
let agentCompleted = false;
|
|
192
197
|
while (true) {
|
|
193
|
-
const { done, value } = await reader.read();
|
|
198
|
+
const { done, value } = await Promise.race([reader.read(), abortPromise]);
|
|
194
199
|
if (done) break;
|
|
195
200
|
buffer += decoder.decode(value, { stream: true });
|
|
196
201
|
const lines = buffer.split("\n");
|
|
@@ -208,6 +213,43 @@ async function streamAgentResponse(params) {
|
|
|
208
213
|
}
|
|
209
214
|
continue;
|
|
210
215
|
}
|
|
216
|
+
if (data.type === "tool-approval-request" && conversationId) {
|
|
217
|
+
const toolName = data.toolName || "Tool";
|
|
218
|
+
const toolCallId = data.toolCallId;
|
|
219
|
+
const input = data.input;
|
|
220
|
+
const buttonValue = {
|
|
221
|
+
toolCallId,
|
|
222
|
+
conversationId,
|
|
223
|
+
projectId,
|
|
224
|
+
agentId,
|
|
225
|
+
slackUserId,
|
|
226
|
+
channel,
|
|
227
|
+
threadTs,
|
|
228
|
+
toolName
|
|
229
|
+
};
|
|
230
|
+
const approvalPost = await slackClient.chat.postMessage({
|
|
231
|
+
channel,
|
|
232
|
+
thread_ts: threadTs,
|
|
233
|
+
text: `Tool approval required: \`${toolName}\``,
|
|
234
|
+
blocks: buildToolApprovalBlocks({
|
|
235
|
+
toolName,
|
|
236
|
+
input,
|
|
237
|
+
buttonValue: JSON.stringify(buttonValue)
|
|
238
|
+
})
|
|
239
|
+
}).catch((e) => {
|
|
240
|
+
logger.warn({
|
|
241
|
+
error: e,
|
|
242
|
+
toolCallId
|
|
243
|
+
}, "Failed to post tool approval message");
|
|
244
|
+
return null;
|
|
245
|
+
});
|
|
246
|
+
if (approvalPost?.ts) pendingApprovalMessages.push({
|
|
247
|
+
messageTs: approvalPost.ts,
|
|
248
|
+
toolName
|
|
249
|
+
});
|
|
250
|
+
clearTimeout(timeoutId);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
211
253
|
if (data.type === "text-start" || data.type === "text-end") continue;
|
|
212
254
|
if (data.type === "text-delta" && data.delta) {
|
|
213
255
|
fullText += data.delta;
|
|
@@ -256,7 +298,17 @@ async function streamAgentResponse(params) {
|
|
|
256
298
|
return { success: true };
|
|
257
299
|
} catch (streamError) {
|
|
258
300
|
clearTimeout(timeoutId);
|
|
301
|
+
reader?.cancel().catch(() => {});
|
|
259
302
|
if (streamError instanceof Error) setSpanWithError(span, streamError);
|
|
303
|
+
for (const { messageTs, toolName } of pendingApprovalMessages) await slackClient.chat.update({
|
|
304
|
+
channel,
|
|
305
|
+
ts: messageTs,
|
|
306
|
+
text: `⏱️ Expired · \`${toolName}\``,
|
|
307
|
+
blocks: buildToolApprovalExpiredBlocks({ toolName })
|
|
308
|
+
}).catch((e) => logger.warn({
|
|
309
|
+
error: e,
|
|
310
|
+
messageTs
|
|
311
|
+
}, "Failed to expire approval message"));
|
|
260
312
|
if (fullText.length > 0) {
|
|
261
313
|
span.setAttribute(SLACK_SPAN_KEYS.CONTENT_ALREADY_DELIVERED, true);
|
|
262
314
|
logger.warn({
|
|
@@ -275,6 +327,22 @@ async function streamAgentResponse(params) {
|
|
|
275
327
|
span.end();
|
|
276
328
|
return { success: true };
|
|
277
329
|
}
|
|
330
|
+
if (pendingApprovalMessages.length > 0) {
|
|
331
|
+
for (const { toolName } of pendingApprovalMessages) await slackClient.chat.postMessage({
|
|
332
|
+
channel,
|
|
333
|
+
thread_ts: threadTs,
|
|
334
|
+
text: `Approval for \`${toolName}\` has expired.`
|
|
335
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to send approval expired notification"));
|
|
336
|
+
await withTimeout(streamer.stop(), CLEANUP_TIMEOUT_MS, "streamer.stop-cleanup").catch((e) => logger.warn({ error: e }, "Failed to stop streamer during error cleanup"));
|
|
337
|
+
if (thinkingMessageTs) try {
|
|
338
|
+
await slackClient.chat.delete({
|
|
339
|
+
channel,
|
|
340
|
+
ts: thinkingMessageTs
|
|
341
|
+
});
|
|
342
|
+
} catch {}
|
|
343
|
+
span.end();
|
|
344
|
+
return { success: true };
|
|
345
|
+
}
|
|
278
346
|
logger.error({ streamError }, "Error during Slack streaming");
|
|
279
347
|
await withTimeout(streamer.stop(), CLEANUP_TIMEOUT_MS, "streamer.stop-cleanup").catch((e) => logger.warn({ error: e }, "Failed to stop streamer during error cleanup"));
|
|
280
348
|
if (thinkingMessageTs) try {
|
|
@@ -239,9 +239,12 @@ async function resolveChannelAgentConfig(teamId, channelId, workspace) {
|
|
|
239
239
|
async function sendResponseUrlMessage(responseUrl, message) {
|
|
240
240
|
try {
|
|
241
241
|
const payload = { text: message.text };
|
|
242
|
-
if (message.replace_original) payload.replace_original = true;
|
|
242
|
+
if (message.replace_original === true) payload.replace_original = true;
|
|
243
243
|
else if (message.delete_original) payload.delete_original = true;
|
|
244
|
-
else
|
|
244
|
+
else {
|
|
245
|
+
payload.replace_original = false;
|
|
246
|
+
if (message.response_type) payload.response_type = message.response_type;
|
|
247
|
+
}
|
|
245
248
|
if (message.blocks) payload.blocks = message.blocks;
|
|
246
249
|
logger.info({
|
|
247
250
|
hasBlocks: !!message.blocks,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
|
|
2
|
-
import { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, buildConversationResponseBlocks, buildFollowUpButton, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
|
|
2
|
+
import { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
|
|
3
3
|
import { checkUserIsChannelMember, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread, revokeSlackToken } from "./client.js";
|
|
4
4
|
import { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
|
|
5
5
|
import { SlackCommandPayload, SlackCommandResponse } from "./types.js";
|
|
6
6
|
import { handleAgentPickerCommand, handleCommand, handleHelpCommand, handleLinkCommand, handleQuestionCommand, handleStatusCommand, handleUnlinkCommand } from "./commands/index.js";
|
|
7
7
|
import { InlineSelectorMetadata, handleAppMention } from "./events/app-mention.js";
|
|
8
|
-
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./events/block-actions.js";
|
|
8
|
+
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleToolApproval } 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
11
|
import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
|
|
@@ -13,4 +13,4 @@ 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, 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 };
|
|
16
|
+
export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, FollowUpButtonParams, FollowUpModalMetadata, InlineSelectorMetadata, ModalMetadata, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceInstallData, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, 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, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
|
|
2
2
|
import { getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
|
|
3
|
-
import { buildConversationResponseBlocks, buildFollowUpButton, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
|
|
3
|
+
import { ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, 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
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
8
|
import { streamAgentResponse } from "./events/streaming.js";
|
|
9
9
|
import { handleAppMention } from "./events/app-mention.js";
|
|
10
|
-
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal } from "./events/block-actions.js";
|
|
10
|
+
import { handleMessageShortcut, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleToolApproval } from "./events/block-actions.js";
|
|
11
11
|
import { handleFollowUpSubmission, handleModalSubmission } from "./events/modal-submission.js";
|
|
12
12
|
import "./events/index.js";
|
|
13
13
|
import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
|
|
14
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, 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 };
|
|
16
|
+
export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, 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, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
|
package/dist/slack/tracer.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ declare const SLACK_SPAN_NAMES: {
|
|
|
15
15
|
readonly OPEN_FOLLOW_UP_MODAL: "slack.open_follow_up_modal";
|
|
16
16
|
readonly PROJECT_SELECT_UPDATE: "slack.project_select_update";
|
|
17
17
|
readonly CALL_AGENT_API: "slack.call_agent_api";
|
|
18
|
+
readonly TOOL_APPROVAL: "slack.tool_approval";
|
|
18
19
|
};
|
|
19
20
|
declare const SLACK_SPAN_KEYS: {
|
|
20
21
|
readonly TEAM_ID: "slack.team_id";
|
package/dist/slack/tracer.js
CHANGED
|
@@ -13,7 +13,8 @@ const SLACK_SPAN_NAMES = {
|
|
|
13
13
|
OPEN_AGENT_SELECTOR_MODAL: "slack.open_agent_selector_modal",
|
|
14
14
|
OPEN_FOLLOW_UP_MODAL: "slack.open_follow_up_modal",
|
|
15
15
|
PROJECT_SELECT_UPDATE: "slack.project_select_update",
|
|
16
|
-
CALL_AGENT_API: "slack.call_agent_api"
|
|
16
|
+
CALL_AGENT_API: "slack.call_agent_api",
|
|
17
|
+
TOOL_APPROVAL: "slack.tool_approval"
|
|
17
18
|
};
|
|
18
19
|
const SLACK_SPAN_KEYS = {
|
|
19
20
|
TEAM_ID: "slack.team_id",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkeep/agents-work-apps",
|
|
3
|
-
"version": "0.0.0-dev-
|
|
3
|
+
"version": "0.0.0-dev-20260220220716",
|
|
4
4
|
"description": "First party integrations for Inkeep Agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"jose": "^6.1.0",
|
|
34
34
|
"minimatch": "^10.1.1",
|
|
35
35
|
"slack-block-builder": "^2.8.0",
|
|
36
|
-
"@inkeep/agents-core": "0.0.0-dev-
|
|
36
|
+
"@inkeep/agents-core": "0.0.0-dev-20260220220716"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@hono/zod-openapi": "^1.1.5",
|