@inkeep/agents-work-apps 0.48.1 → 0.48.2
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/index.d.ts +2 -2
- package/dist/github/routes/setup.d.ts +2 -2
- package/dist/github/routes/tokenExchange.d.ts +2 -2
- package/dist/github/routes/webhooks.d.ts +2 -2
- package/dist/slack/routes/events.js +13 -0
- package/dist/slack/services/events/streaming.js +41 -3
- package/dist/slack/tracer.d.ts +3 -1
- package/dist/slack/tracer.js +3 -1
- package/package.json +2 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types3 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/mcp/index.d.ts
|
|
5
5
|
declare const app: Hono<{
|
|
6
6
|
Variables: {
|
|
7
7
|
toolId: string;
|
|
8
8
|
};
|
|
9
|
-
},
|
|
9
|
+
}, hono_types3.BlankSchema, "/">;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { app as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types4 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_types4.BlankEnv, hono_types4.BlankSchema, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types6 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/routes/tokenExchange.d.ts
|
|
5
|
-
declare const app: Hono<
|
|
5
|
+
declare const app: Hono<hono_types6.BlankEnv, hono_types6.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_types8 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_types8.BlankEnv, hono_types8.BlankSchema, "/">;
|
|
11
11
|
//#endregion
|
|
12
12
|
export { WebhookVerificationResult, app as default, verifyWebhookSignature };
|
|
@@ -63,6 +63,19 @@ app.post("/commands", async (c) => {
|
|
|
63
63
|
return c.json(response);
|
|
64
64
|
});
|
|
65
65
|
app.post("/events", async (c) => {
|
|
66
|
+
const retryNum = c.req.header("x-slack-retry-num");
|
|
67
|
+
const retryReason = c.req.header("x-slack-retry-reason");
|
|
68
|
+
if (retryNum) return tracer.startActiveSpan(`${SLACK_SPAN_NAMES.WEBHOOK} retry`, (span) => {
|
|
69
|
+
span.setAttribute(SLACK_SPAN_KEYS.OUTCOME, "ignored_slack_retry");
|
|
70
|
+
span.setAttribute("slack.retry_num", retryNum);
|
|
71
|
+
if (retryReason) span.setAttribute("slack.retry_reason", retryReason);
|
|
72
|
+
logger.info({
|
|
73
|
+
retryNum,
|
|
74
|
+
retryReason
|
|
75
|
+
}, "Acknowledging Slack retry without re-processing");
|
|
76
|
+
span.end();
|
|
77
|
+
return c.json({ ok: true });
|
|
78
|
+
});
|
|
66
79
|
return tracer.startActiveSpan(SLACK_SPAN_NAMES.WEBHOOK, async (span) => {
|
|
67
80
|
let outcome = "ignored_unknown_event";
|
|
68
81
|
try {
|
|
@@ -14,6 +14,8 @@ import { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, setSpanWithError, tracer } from "../
|
|
|
14
14
|
const logger = getLogger("slack-streaming");
|
|
15
15
|
const STREAM_TIMEOUT_MS = 12e4;
|
|
16
16
|
const CHATSTREAM_OP_TIMEOUT_MS = 1e4;
|
|
17
|
+
/** Shorter timeout for best-effort cleanup in error paths to bound total error handling time. */
|
|
18
|
+
const CLEANUP_TIMEOUT_MS = 3e3;
|
|
17
19
|
/**
|
|
18
20
|
* Wrap a promise with a timeout to prevent indefinite blocking on Slack API calls.
|
|
19
21
|
*/
|
|
@@ -184,6 +186,7 @@ async function streamAgentResponse(params) {
|
|
|
184
186
|
thread_ts: threadTs
|
|
185
187
|
});
|
|
186
188
|
try {
|
|
189
|
+
let agentCompleted = false;
|
|
187
190
|
while (true) {
|
|
188
191
|
const { done, value } = await reader.read();
|
|
189
192
|
if (done) break;
|
|
@@ -196,7 +199,13 @@ async function streamAgentResponse(params) {
|
|
|
196
199
|
if (!jsonStr || jsonStr === "[DONE]") continue;
|
|
197
200
|
try {
|
|
198
201
|
const data = JSON.parse(jsonStr);
|
|
199
|
-
if (data.type === "data-operation")
|
|
202
|
+
if (data.type === "data-operation") {
|
|
203
|
+
if (data.data?.type === "completion") {
|
|
204
|
+
agentCompleted = true;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
200
209
|
if (data.type === "text-start" || data.type === "text-end") continue;
|
|
201
210
|
if (data.type === "text-delta" && data.delta) {
|
|
202
211
|
fullText += data.delta;
|
|
@@ -211,10 +220,21 @@ async function streamAgentResponse(params) {
|
|
|
211
220
|
}
|
|
212
221
|
} catch {}
|
|
213
222
|
}
|
|
223
|
+
if (agentCompleted) break;
|
|
214
224
|
}
|
|
215
225
|
clearTimeout(timeoutId);
|
|
216
226
|
const contextBlock = createContextBlock({ agentName });
|
|
217
|
-
|
|
227
|
+
try {
|
|
228
|
+
await withTimeout(streamer.stop({ blocks: [contextBlock] }), CHATSTREAM_OP_TIMEOUT_MS, "streamer.stop");
|
|
229
|
+
} catch (stopError) {
|
|
230
|
+
span.setAttribute(SLACK_SPAN_KEYS.STREAM_FINALIZATION_FAILED, true);
|
|
231
|
+
logger.warn({
|
|
232
|
+
stopError,
|
|
233
|
+
channel,
|
|
234
|
+
threadTs,
|
|
235
|
+
responseLength: fullText.length
|
|
236
|
+
}, "Failed to finalize chatStream — content was already delivered");
|
|
237
|
+
}
|
|
218
238
|
if (thinkingMessageTs) try {
|
|
219
239
|
await slackClient.chat.delete({
|
|
220
240
|
channel,
|
|
@@ -235,8 +255,26 @@ async function streamAgentResponse(params) {
|
|
|
235
255
|
} catch (streamError) {
|
|
236
256
|
clearTimeout(timeoutId);
|
|
237
257
|
if (streamError instanceof Error) setSpanWithError(span, streamError);
|
|
258
|
+
if (fullText.length > 0) {
|
|
259
|
+
span.setAttribute(SLACK_SPAN_KEYS.CONTENT_ALREADY_DELIVERED, true);
|
|
260
|
+
logger.warn({
|
|
261
|
+
streamError,
|
|
262
|
+
channel,
|
|
263
|
+
threadTs,
|
|
264
|
+
responseLength: fullText.length
|
|
265
|
+
}, "Error during Slack streaming after content was already delivered — suppressing user-facing error");
|
|
266
|
+
await withTimeout(streamer.stop(), CLEANUP_TIMEOUT_MS, "streamer.stop-cleanup").catch((e) => logger.warn({ error: e }, "Failed to stop streamer during error cleanup"));
|
|
267
|
+
if (thinkingMessageTs) try {
|
|
268
|
+
await slackClient.chat.delete({
|
|
269
|
+
channel,
|
|
270
|
+
ts: thinkingMessageTs
|
|
271
|
+
});
|
|
272
|
+
} catch {}
|
|
273
|
+
span.end();
|
|
274
|
+
return { success: true };
|
|
275
|
+
}
|
|
238
276
|
logger.error({ streamError }, "Error during Slack streaming");
|
|
239
|
-
await withTimeout(streamer.stop(),
|
|
277
|
+
await withTimeout(streamer.stop(), CLEANUP_TIMEOUT_MS, "streamer.stop-cleanup").catch((e) => logger.warn({ error: e }, "Failed to stop streamer during error cleanup"));
|
|
240
278
|
if (thinkingMessageTs) try {
|
|
241
279
|
await slackClient.chat.delete({
|
|
242
280
|
channel,
|
package/dist/slack/tracer.d.ts
CHANGED
|
@@ -34,7 +34,9 @@ declare const SLACK_SPAN_KEYS: {
|
|
|
34
34
|
readonly IS_BOT_MESSAGE: "slack.is_bot_message";
|
|
35
35
|
readonly HAS_QUERY: "slack.has_query";
|
|
36
36
|
readonly IS_IN_THREAD: "slack.is_in_thread";
|
|
37
|
+
readonly STREAM_FINALIZATION_FAILED: "slack.stream_finalization_failed";
|
|
38
|
+
readonly CONTENT_ALREADY_DELIVERED: "slack.content_already_delivered";
|
|
37
39
|
};
|
|
38
|
-
type SlackOutcome = 'handled' | 'ignored_bot_message' | 'ignored_unknown_event' | 'ignored_no_action_match' | 'url_verification' | 'validation_error' | 'signature_invalid' | 'error';
|
|
40
|
+
type SlackOutcome = 'handled' | 'ignored_bot_message' | 'ignored_unknown_event' | 'ignored_no_action_match' | 'ignored_slack_retry' | 'url_verification' | 'validation_error' | 'signature_invalid' | 'error';
|
|
39
41
|
//#endregion
|
|
40
42
|
export { SLACK_SPAN_KEYS, SLACK_SPAN_NAMES, SlackOutcome, setSpanWithError, tracer };
|
package/dist/slack/tracer.js
CHANGED
|
@@ -32,7 +32,9 @@ const SLACK_SPAN_KEYS = {
|
|
|
32
32
|
OUTCOME: "slack.outcome",
|
|
33
33
|
IS_BOT_MESSAGE: "slack.is_bot_message",
|
|
34
34
|
HAS_QUERY: "slack.has_query",
|
|
35
|
-
IS_IN_THREAD: "slack.is_in_thread"
|
|
35
|
+
IS_IN_THREAD: "slack.is_in_thread",
|
|
36
|
+
STREAM_FINALIZATION_FAILED: "slack.stream_finalization_failed",
|
|
37
|
+
CONTENT_ALREADY_DELIVERED: "slack.content_already_delivered"
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkeep/agents-work-apps",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.2",
|
|
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.48.
|
|
36
|
+
"@inkeep/agents-core": "0.48.2"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@hono/zod-openapi": "^1.1.5",
|