@inkeep/agents-work-apps 0.69.0 → 0.70.0
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/index.d.ts +3 -3
- package/dist/github/mcp/auth.d.ts +2 -2
- package/dist/github/mcp/index.d.ts +2 -2
- package/dist/github/routes/setup.d.ts +2 -2
- package/dist/github/routes/webhooks.d.ts +2 -2
- package/dist/slack/mcp/auth.d.ts +2 -2
- package/dist/slack/services/events/block-actions.d.ts +22 -5
- package/dist/slack/services/events/block-actions.js +163 -12
- package/dist/slack/services/events/streaming.js +1 -0
- package/dist/slack/services/events/utils.d.ts +1 -1
- package/package.json +2 -2
package/dist/github/index.d.ts
CHANGED
|
@@ -4,10 +4,10 @@ import "./routes/setup.js";
|
|
|
4
4
|
import "./routes/tokenExchange.js";
|
|
5
5
|
import { WebhookVerificationResult, verifyWebhookSignature } from "./routes/webhooks.js";
|
|
6
6
|
import { Hono } from "hono";
|
|
7
|
-
import * as
|
|
7
|
+
import * as hono_types6 from "hono/types";
|
|
8
8
|
|
|
9
9
|
//#region src/github/index.d.ts
|
|
10
|
-
declare function createGithubRoutes(): Hono<
|
|
11
|
-
declare const githubRoutes: Hono<
|
|
10
|
+
declare function createGithubRoutes(): Hono<hono_types6.BlankEnv, hono_types6.BlankSchema, "/">;
|
|
11
|
+
declare const githubRoutes: Hono<hono_types6.BlankEnv, hono_types6.BlankSchema, "/">;
|
|
12
12
|
//#endregion
|
|
13
13
|
export { GenerateInstallationAccessTokenResult, GenerateTokenError, GenerateTokenResult, GitHubAppConfig, InstallationAccessToken, InstallationInfo, LookupInstallationError, LookupInstallationForRepoResult, LookupInstallationResult, WebhookVerificationResult, clearConfigCache, createAppJwt, createGithubRoutes, determineStatus, fetchInstallationDetails, fetchInstallationRepositories, generateInstallationAccessToken, getGitHubAppConfig, getGitHubAppName, getStateSigningSecret, getWebhookSecret, githubRoutes, isGitHubAppConfigured, isGitHubAppNameConfigured, isStateSigningConfigured, isWebhookConfigured, lookupInstallationForRepo, validateGitHubAppConfigOnStartup, validateGitHubInstallFlowConfigOnStartup, validateGitHubWebhookConfigOnStartup, verifyWebhookSignature };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as hono2 from "hono";
|
|
2
2
|
|
|
3
3
|
//#region src/github/mcp/auth.d.ts
|
|
4
|
-
declare const githubMcpAuth: () =>
|
|
4
|
+
declare const githubMcpAuth: () => hono2.MiddlewareHandler<{
|
|
5
5
|
Variables: {
|
|
6
6
|
toolId: string;
|
|
7
7
|
tenantId: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types1 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/mcp/index.d.ts
|
|
5
5
|
declare const app: Hono<{
|
|
@@ -8,6 +8,6 @@ declare const app: Hono<{
|
|
|
8
8
|
tenantId: string;
|
|
9
9
|
projectId: string;
|
|
10
10
|
};
|
|
11
|
-
},
|
|
11
|
+
}, hono_types1.BlankSchema, "/">;
|
|
12
12
|
//#endregion
|
|
13
13
|
export { app as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types2 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/routes/setup.d.ts
|
|
5
|
-
declare const app: Hono<
|
|
5
|
+
declare const app: Hono<hono_types2.BlankEnv, hono_types2.BlankSchema, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types0 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/routes/webhooks.d.ts
|
|
5
5
|
interface WebhookVerificationResult {
|
|
@@ -7,6 +7,6 @@ interface WebhookVerificationResult {
|
|
|
7
7
|
error?: string;
|
|
8
8
|
}
|
|
9
9
|
declare function verifyWebhookSignature(payload: string, signature: string | undefined, secret: string): WebhookVerificationResult;
|
|
10
|
-
declare const app: Hono<
|
|
10
|
+
declare const app: Hono<hono_types0.BlankEnv, hono_types0.BlankSchema, "/">;
|
|
11
11
|
//#endregion
|
|
12
12
|
export { WebhookVerificationResult, app as default, verifyWebhookSignature };
|
package/dist/slack/mcp/auth.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as hono0 from "hono";
|
|
2
2
|
|
|
3
3
|
//#region src/slack/mcp/auth.d.ts
|
|
4
|
-
declare const slackMcpAuth: () =>
|
|
4
|
+
declare const slackMcpAuth: () => hono0.MiddlewareHandler<{
|
|
5
5
|
Variables: {
|
|
6
6
|
toolId: string;
|
|
7
7
|
tenantId: string;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { getSlackClient } from "../client.js";
|
|
2
|
+
|
|
1
3
|
//#region src/slack/services/events/block-actions.d.ts
|
|
2
|
-
|
|
3
|
-
* Handlers for Slack block action events (button clicks, selections, etc.)
|
|
4
|
-
* and message shortcuts
|
|
5
|
-
*/
|
|
4
|
+
|
|
6
5
|
/**
|
|
7
6
|
* Handle tool approval/denial button clicks.
|
|
8
7
|
* Called when a user clicks "Approve" or "Deny" on a tool approval message.
|
|
@@ -37,5 +36,23 @@ declare function handleMessageShortcut(params: {
|
|
|
37
36
|
threadTs?: string;
|
|
38
37
|
responseUrl?: string;
|
|
39
38
|
}): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Consume the SSE continuation stream returned after a durable tool approval.
|
|
41
|
+
* Accumulates text-delta events and posts the final result to the Slack thread.
|
|
42
|
+
* If the continuation triggers another tool approval (chained/delegated), posts
|
|
43
|
+
* the approval buttons — the next button click will recursively enter this flow.
|
|
44
|
+
*/
|
|
45
|
+
declare function consumeApprovalContinuationStream(params: {
|
|
46
|
+
response: Response;
|
|
47
|
+
slackClient: ReturnType<typeof getSlackClient>;
|
|
48
|
+
channel: string;
|
|
49
|
+
threadTs?: string;
|
|
50
|
+
agentName: string;
|
|
51
|
+
conversationId: string;
|
|
52
|
+
projectId: string;
|
|
53
|
+
agentId: string;
|
|
54
|
+
slackUserId: string;
|
|
55
|
+
thinkingMessageTs?: string;
|
|
56
|
+
}): Promise<void>;
|
|
40
57
|
//#endregion
|
|
41
|
-
export { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval };
|
|
58
|
+
export { consumeApprovalContinuationStream, handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { env } from "../../../env.js";
|
|
2
2
|
import { getLogger } from "../../../logger.js";
|
|
3
3
|
import { findWorkspaceConnectionByTeamId } from "../nango.js";
|
|
4
|
-
import { fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, getChannelAgentConfig, sendResponseUrlMessage } from "./utils.js";
|
|
4
|
+
import { fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, getChannelAgentConfig, markdownToMrkdwn, sendResponseUrlMessage } from "./utils.js";
|
|
5
|
+
import { lookupAgentName } from "../agent-resolution.js";
|
|
5
6
|
import { SlackStrings } from "../../i18n/strings.js";
|
|
6
|
-
import { ToolApprovalButtonValueSchema, buildToolApprovalDoneBlocks } from "../blocks/index.js";
|
|
7
|
+
import { ToolApprovalButtonValueSchema, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, createContextBlock, createContextBlockFromText } from "../blocks/index.js";
|
|
7
8
|
import { getSlackClient } from "../client.js";
|
|
8
9
|
import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../../tracer.js";
|
|
9
10
|
import { buildAgentSelectorModal, buildMessageShortcutModal } from "../modals.js";
|
|
@@ -64,6 +65,15 @@ async function handleToolApproval(params) {
|
|
|
64
65
|
slackTeamId: teamId,
|
|
65
66
|
slackUserId
|
|
66
67
|
});
|
|
68
|
+
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
69
|
+
text: approved ? `✅ Approved \`${toolName}\`` : `❌ Denied \`${toolName}\``,
|
|
70
|
+
replace_original: true,
|
|
71
|
+
blocks: buildToolApprovalDoneBlocks({
|
|
72
|
+
toolName,
|
|
73
|
+
approved,
|
|
74
|
+
actorUserId: slackUserId
|
|
75
|
+
})
|
|
76
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to update approval message"));
|
|
67
77
|
const apiUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
|
|
68
78
|
const approvalResponse = await getInProcessFetch()(`${apiUrl}/run/api/chat`, {
|
|
69
79
|
method: "POST",
|
|
@@ -108,21 +118,38 @@ async function handleToolApproval(params) {
|
|
|
108
118
|
span.end();
|
|
109
119
|
return;
|
|
110
120
|
}
|
|
111
|
-
if (responseUrl) await sendResponseUrlMessage(responseUrl, {
|
|
112
|
-
text: approved ? `✅ Approved \`${toolName}\`` : `❌ Denied \`${toolName}\``,
|
|
113
|
-
replace_original: true,
|
|
114
|
-
blocks: buildToolApprovalDoneBlocks({
|
|
115
|
-
toolName,
|
|
116
|
-
approved,
|
|
117
|
-
actorUserId: slackUserId
|
|
118
|
-
})
|
|
119
|
-
}).catch((e) => logger.warn({ error: e }, "Failed to update approval message"));
|
|
120
121
|
logger.info({
|
|
121
122
|
toolCallId,
|
|
122
123
|
conversationId,
|
|
123
124
|
approved,
|
|
124
125
|
slackUserId
|
|
125
126
|
}, "Tool approval processed");
|
|
127
|
+
const contentType = approvalResponse.headers.get("content-type") || "";
|
|
128
|
+
if (approvalResponse.body && contentType.includes("text/event-stream")) {
|
|
129
|
+
const agentName = await lookupAgentName(tenantId, projectId, agentId) || agentId;
|
|
130
|
+
const thinkingText = SlackStrings.status.thinking(agentName);
|
|
131
|
+
const thinkingMsg = await slackClient.chat.postMessage({
|
|
132
|
+
channel: buttonValue.channel,
|
|
133
|
+
...approvalThreadParam,
|
|
134
|
+
blocks: [createContextBlockFromText(thinkingText)],
|
|
135
|
+
text: thinkingText
|
|
136
|
+
}).catch((e) => {
|
|
137
|
+
logger.warn({ error: e }, "Failed to post thinking message");
|
|
138
|
+
return null;
|
|
139
|
+
});
|
|
140
|
+
await consumeApprovalContinuationStream({
|
|
141
|
+
response: approvalResponse,
|
|
142
|
+
slackClient,
|
|
143
|
+
channel: buttonValue.channel,
|
|
144
|
+
threadTs: buttonValue.threadTs,
|
|
145
|
+
agentName,
|
|
146
|
+
conversationId,
|
|
147
|
+
projectId,
|
|
148
|
+
agentId,
|
|
149
|
+
slackUserId,
|
|
150
|
+
thinkingMessageTs: thinkingMsg?.ts
|
|
151
|
+
});
|
|
152
|
+
}
|
|
126
153
|
span.end();
|
|
127
154
|
} catch (error) {
|
|
128
155
|
if (error instanceof Error) setSpanWithError(span, error);
|
|
@@ -343,6 +370,130 @@ async function handleMessageShortcut(params) {
|
|
|
343
370
|
}
|
|
344
371
|
});
|
|
345
372
|
}
|
|
373
|
+
const CONTINUATION_TIMEOUT_MS = 12e4;
|
|
374
|
+
/**
|
|
375
|
+
* Consume the SSE continuation stream returned after a durable tool approval.
|
|
376
|
+
* Accumulates text-delta events and posts the final result to the Slack thread.
|
|
377
|
+
* If the continuation triggers another tool approval (chained/delegated), posts
|
|
378
|
+
* the approval buttons — the next button click will recursively enter this flow.
|
|
379
|
+
*/
|
|
380
|
+
async function consumeApprovalContinuationStream(params) {
|
|
381
|
+
const { response, slackClient, channel, threadTs, agentName, conversationId, projectId, agentId, slackUserId, thinkingMessageTs } = params;
|
|
382
|
+
const threadParam = threadTs ? { thread_ts: threadTs } : {};
|
|
383
|
+
if (!response.body) return;
|
|
384
|
+
const reader = response.body.getReader();
|
|
385
|
+
const decoder = new TextDecoder();
|
|
386
|
+
let buffer = "";
|
|
387
|
+
let fullText = "";
|
|
388
|
+
let chainedApprovalPosted = false;
|
|
389
|
+
const toolCallIdToName = /* @__PURE__ */ new Map();
|
|
390
|
+
const toolCallIdToInput = /* @__PURE__ */ new Map();
|
|
391
|
+
const timeoutId = setTimeout(() => {
|
|
392
|
+
reader.cancel().catch(() => {});
|
|
393
|
+
}, CONTINUATION_TIMEOUT_MS);
|
|
394
|
+
try {
|
|
395
|
+
while (true) {
|
|
396
|
+
const { done, value } = await reader.read();
|
|
397
|
+
if (done) break;
|
|
398
|
+
buffer += decoder.decode(value, { stream: true });
|
|
399
|
+
const lines = buffer.split("\n");
|
|
400
|
+
buffer = lines.pop() || "";
|
|
401
|
+
for (const line of lines) {
|
|
402
|
+
if (!line.startsWith("data: ")) continue;
|
|
403
|
+
const jsonStr = line.slice(6).trim();
|
|
404
|
+
if (!jsonStr || jsonStr === "[DONE]") continue;
|
|
405
|
+
try {
|
|
406
|
+
const data = JSON.parse(jsonStr);
|
|
407
|
+
if (data.type === "text-delta" && data.delta) fullText += data.delta;
|
|
408
|
+
else if (data.type === "tool-input-available" && data.toolCallId && data.toolName) {
|
|
409
|
+
toolCallIdToName.set(String(data.toolCallId), String(data.toolName));
|
|
410
|
+
if (data.input && typeof data.input === "object") toolCallIdToInput.set(String(data.toolCallId), data.input);
|
|
411
|
+
} else if (data.type === "tool-approval-request" && data.toolCallId && conversationId) {
|
|
412
|
+
const toolCallId = data.toolCallId;
|
|
413
|
+
const toolName = toolCallIdToName.get(toolCallId) || "Tool";
|
|
414
|
+
const input = toolCallIdToInput.get(toolCallId);
|
|
415
|
+
const buttonValue = {
|
|
416
|
+
toolCallId,
|
|
417
|
+
conversationId,
|
|
418
|
+
projectId,
|
|
419
|
+
agentId,
|
|
420
|
+
slackUserId,
|
|
421
|
+
channel,
|
|
422
|
+
threadTs,
|
|
423
|
+
toolName
|
|
424
|
+
};
|
|
425
|
+
await slackClient.chat.postMessage({
|
|
426
|
+
channel,
|
|
427
|
+
...threadParam,
|
|
428
|
+
text: `Tool approval required: \`${toolName}\``,
|
|
429
|
+
blocks: buildToolApprovalBlocks({
|
|
430
|
+
toolName,
|
|
431
|
+
input,
|
|
432
|
+
buttonValue: JSON.stringify(buttonValue)
|
|
433
|
+
})
|
|
434
|
+
}).catch((e) => logger.warn({
|
|
435
|
+
error: e,
|
|
436
|
+
toolCallId
|
|
437
|
+
}, "Failed to post chained approval message"));
|
|
438
|
+
chainedApprovalPosted = true;
|
|
439
|
+
clearTimeout(timeoutId);
|
|
440
|
+
}
|
|
441
|
+
} catch {}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
} catch (error) {
|
|
445
|
+
logger.warn({
|
|
446
|
+
error: error instanceof Error ? error.message : String(error),
|
|
447
|
+
channel,
|
|
448
|
+
threadTs,
|
|
449
|
+
conversationId,
|
|
450
|
+
agentId
|
|
451
|
+
}, "Error reading approval continuation stream");
|
|
452
|
+
if (fullText.length === 0) await slackClient.chat.postMessage({
|
|
453
|
+
channel,
|
|
454
|
+
...threadParam,
|
|
455
|
+
text: "_Something went wrong while processing the tool result. Please try again._"
|
|
456
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to post continuation error message"));
|
|
457
|
+
} finally {
|
|
458
|
+
clearTimeout(timeoutId);
|
|
459
|
+
reader.cancel().catch(() => {});
|
|
460
|
+
}
|
|
461
|
+
if (thinkingMessageTs) await slackClient.chat.delete({
|
|
462
|
+
channel,
|
|
463
|
+
ts: thinkingMessageTs
|
|
464
|
+
}).catch((e) => logger.warn({ error: e }, "Failed to delete thinking message"));
|
|
465
|
+
if (fullText.length > 0) {
|
|
466
|
+
const slackText = markdownToMrkdwn(fullText);
|
|
467
|
+
const SLACK_SECTION_LIMIT = 3e3;
|
|
468
|
+
const truncatedText = slackText.length > SLACK_SECTION_LIMIT ? `${slackText.slice(0, SLACK_SECTION_LIMIT - 3)}...` : slackText;
|
|
469
|
+
await slackClient.chat.postMessage({
|
|
470
|
+
channel,
|
|
471
|
+
...threadParam,
|
|
472
|
+
text: slackText,
|
|
473
|
+
blocks: [{
|
|
474
|
+
type: "section",
|
|
475
|
+
text: {
|
|
476
|
+
type: "mrkdwn",
|
|
477
|
+
text: truncatedText
|
|
478
|
+
}
|
|
479
|
+
}, createContextBlock({ agentName })]
|
|
480
|
+
}).catch((e) => logger.warn({
|
|
481
|
+
error: e,
|
|
482
|
+
channel,
|
|
483
|
+
threadTs
|
|
484
|
+
}, "Failed to post approval continuation result"));
|
|
485
|
+
logger.info({
|
|
486
|
+
channel,
|
|
487
|
+
threadTs,
|
|
488
|
+
conversationId,
|
|
489
|
+
responseLength: fullText.length
|
|
490
|
+
}, "Approval continuation stream completed");
|
|
491
|
+
} else if (!chainedApprovalPosted) logger.warn({
|
|
492
|
+
channel,
|
|
493
|
+
threadTs,
|
|
494
|
+
conversationId
|
|
495
|
+
}, "Approval continuation stream completed with no text and no chained approval");
|
|
496
|
+
}
|
|
346
497
|
|
|
347
498
|
//#endregion
|
|
348
|
-
export { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval };
|
|
499
|
+
export { consumeApprovalContinuationStream, handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval };
|
|
@@ -10,9 +10,9 @@ import { AgentOption } from "../modals.js";
|
|
|
10
10
|
*/
|
|
11
11
|
declare function findCachedUserMapping(tenantId: string, slackUserId: string, teamId: string, clientId?: string): Promise<{
|
|
12
12
|
slackUserId: string;
|
|
13
|
-
id: string;
|
|
14
13
|
createdAt: string;
|
|
15
14
|
updatedAt: string;
|
|
15
|
+
id: string;
|
|
16
16
|
tenantId: string;
|
|
17
17
|
clientId: string;
|
|
18
18
|
slackTeamId: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkeep/agents-work-apps",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.70.0",
|
|
4
4
|
"description": "First party integrations for Inkeep Agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"minimatch": "^10.2.1",
|
|
36
36
|
"oxfmt": "^0.42.0",
|
|
37
37
|
"slack-block-builder": "^2.8.0",
|
|
38
|
-
"@inkeep/agents-core": "0.
|
|
38
|
+
"@inkeep/agents-core": "0.70.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@hono/zod-openapi": "^1.1.5",
|