@desplega.ai/agent-swarm 1.152.1 → 1.152.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/README.md +1 -0
- package/dist/{acp-adapter-4s7q25ft.js → acp-adapter-pfeje2v5.js} +1 -1
- package/dist/{actions-cs6rhmvc.js → actions-0sttc7f5.js} +12 -12
- package/dist/{app-j54aq0dj.js → app-p8teva95.js} +3 -3
- package/dist/{assistant-w1pgn7vf.js → assistant-r45jnsrt.js} +15 -15
- package/dist/{boot-reembed-42vgkrrj.js → boot-reembed-1qmybsd4.js} +4 -4
- package/dist/{boot-reembed-smy30z32.js → boot-reembed-je26h5y7.js} +3 -3
- package/dist/{boot-scrub-logs-b6s72fsw.js → boot-scrub-logs-gte3h1mm.js} +2 -2
- package/dist/{claude-adapter-fh7rmcj9.js → claude-adapter-csc1mzka.js} +3 -3
- package/dist/{claude-sdk-session-xhynatn9.js → claude-sdk-session-fcd6f078.js} +3 -3
- package/dist/{cli-7bwaerjt.js → cli-2nnd56zt.js} +1 -1
- package/dist/{cli-b4dyetqt.js → cli-3bpzj8me.js} +2 -2
- package/dist/{cli-sqmh7jj1.js → cli-4ahpr4sw.js} +1 -1
- package/dist/{cli-vbk025fm.js → cli-56h18ng2.js} +1 -1
- package/dist/{cli-kf8qp2vf.js → cli-b9dd0h3k.js} +2 -2
- package/dist/{cli-ng4q6a9t.js → cli-ckz5t2hb.js} +7 -7
- package/dist/{cli-dsyg66vt.js → cli-fmy65jdn.js} +3 -3
- package/dist/{cli-y8tayczk.js → cli-gphgnvpf.js} +2 -2
- package/dist/{cli-gxf2ebyz.js → cli-gpqcs935.js} +2 -2
- package/dist/{cli-3g61md6v.js → cli-jbmc0r7r.js} +1 -1
- package/dist/{cli-jtvs5m8q.js → cli-jew3jda5.js} +1 -1
- package/dist/{cli-3pft2z6r.js → cli-jvy9qgjs.js} +12 -10
- package/dist/{cli-ftdjz1mk.js → cli-qd65dvr6.js} +8 -8
- package/dist/{cli-wfve107r.js → cli-qn042eh7.js} +8 -8
- package/dist/{cli-jytf5mw9.js → cli-r84ctdxn.js} +1 -1
- package/dist/{cli-ks8a1cgq.js → cli-wpv5rgg2.js} +2 -2
- package/dist/{cli-sakxd2rg.js → cli-xw7vak96.js} +2 -2
- package/dist/{cli-v9sk4dzw.js → cli-xy1cchaf.js} +1 -1
- package/dist/{cli-72tgtzr1.js → cli-z3wkng35.js} +18 -18
- package/dist/{cli-bdt7w021.js → cli-zvgj5zg8.js} +1 -1
- package/dist/{cli-gfez0qmk.js → cli-zvkq5csn.js} +1 -1
- package/dist/cli.js +11 -11
- package/dist/{codex-adapter-k6yq95sn.js → codex-adapter-fxmpsabw.js} +2 -2
- package/dist/{codex-session-runner-3rp84pk8.js → codex-session-runner-rr1e47ea.js} +2 -2
- package/dist/{commands-pbr5jzy5.js → commands-0f5rxz51.js} +2 -2
- package/dist/{db-z0xaa59a.js → db-r3jxf3wy.js} +2 -2
- package/dist/{dispatcher-pwpgsj0x.js → dispatcher-06vph6q4.js} +11 -11
- package/dist/{handlers-5mzk4mbg.js → handlers-0hgtc910.js} +14 -14
- package/dist/{hook-8bz33zee.js → hook-9kvrv1er.js} +1 -1
- package/dist/{hook-kbh84zb1.js → hook-fbfhkat3.js} +2 -2
- package/dist/{http-pppxg5vr.js → http-xbyx8k5j.js} +27 -27
- package/dist/{index-y0te09pn.js → index-gpfn1741.js} +3 -3
- package/dist/{index-z0zwjtkn.js → index-jsw3aynb.js} +11 -11
- package/dist/{index-68bd9b5f.js → index-rnyahfn5.js} +11 -11
- package/dist/{index-mjpxsr6k.js → index-sgk50mbg.js} +12 -12
- package/dist/{index-k1hq1qt6.js → index-tfsdxyv6.js} +7 -7
- package/dist/{keepalive-xvmwnh1d.js → keepalive-s3xpr7sw.js} +4 -4
- package/dist/{lead-pf8nvxt8.js → lead-rq4n5r16.js} +15 -15
- package/dist/{maintenance-jk4q0wgg.js → maintenance-f0atj1ab.js} +4 -4
- package/dist/{oauth-refresh-sweep-6207x9sj.js → oauth-refresh-sweep-q0t3bxre.js} +3 -3
- package/dist/{onboard-b0csgm0q.js → onboard-br5j1kch.js} +2 -2
- package/dist/{otel-impl-b6rfehth.js → otel-impl-vdqge2nt.js} +1 -1
- package/dist/{pricing-refresh-4e201wtd.js → pricing-refresh-hb3691fd.js} +4 -4
- package/dist/{rbac-roles-mkc5n5qa.js → rbac-roles-jh280k9g.js} +3 -3
- package/dist/{rbac-roles-zp6e4geh.js → rbac-roles-t78xt39b.js} +2 -2
- package/dist/{render-v2-4fazz9tf.js → render-v2-7p8r2ymg.js} +3 -3
- package/dist/{seed-pricing-thxpn9vn.js → seed-pricing-hf889enh.js} +3 -3
- package/dist/{setup-wb0z8cat.js → setup-w6mb03jv.js} +2 -2
- package/dist/{work-objects-h3498kwe.js → work-objects-nt8gy1kj.js} +14 -14
- package/dist/{worker-2m2tzxp3.js → worker-dwy617t0.js} +15 -15
- package/openapi.json +1 -1
- package/package.json +1 -1
- package/src/slack/assistant.ts +10 -1
- package/src/slack/handlers.ts +10 -1
- package/src/slack/thread-buffer.ts +14 -3
- package/src/tests/slack-assistant.test.ts +134 -0
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
processSlackRenderV2,
|
|
10
10
|
renderThreadTree,
|
|
11
11
|
streamOutcomeCard
|
|
12
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-qn042eh7.js";
|
|
13
13
|
import"./cli-q51yprfq.js";
|
|
14
14
|
import"./cli-yatxqynm.js";
|
|
15
15
|
import"./cli-2658f6at.js";
|
|
16
|
-
import"./cli-
|
|
16
|
+
import"./cli-zvgj5zg8.js";
|
|
17
17
|
import"./cli-ht5rs63n.js";
|
|
18
18
|
import"./cli-z61ykvam.js";
|
|
19
19
|
import"./cli-dv6cdjs2.js";
|
|
@@ -21,7 +21,7 @@ import"./cli-c2mk1kgf.js";
|
|
|
21
21
|
import"./cli-ej6gbxfb.js";
|
|
22
22
|
import"./cli-sd0mxa3c.js";
|
|
23
23
|
import"./cli-w5e1d1vv.js";
|
|
24
|
-
import"./cli-
|
|
24
|
+
import"./cli-zvkq5csn.js";
|
|
25
25
|
import"./cli-r2ap2czm.js";
|
|
26
26
|
import"./cli-pzxba7gw.js";
|
|
27
27
|
import"./cli-zf8jjwex.js";
|
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
buildModelsDevSeedRows,
|
|
3
3
|
buildPricingSeedRows,
|
|
4
4
|
seedPricingFromModelsDev
|
|
5
|
-
} from "./cli-
|
|
6
|
-
import"./cli-
|
|
5
|
+
} from "./cli-2nnd56zt.js";
|
|
6
|
+
import"./cli-zvgj5zg8.js";
|
|
7
7
|
import"./cli-ht5rs63n.js";
|
|
8
8
|
import"./cli-z61ykvam.js";
|
|
9
9
|
import"./cli-dv6cdjs2.js";
|
|
@@ -11,7 +11,7 @@ import"./cli-c2mk1kgf.js";
|
|
|
11
11
|
import"./cli-ej6gbxfb.js";
|
|
12
12
|
import"./cli-sd0mxa3c.js";
|
|
13
13
|
import"./cli-w5e1d1vv.js";
|
|
14
|
-
import"./cli-
|
|
14
|
+
import"./cli-zvkq5csn.js";
|
|
15
15
|
import"./cli-r2ap2czm.js";
|
|
16
16
|
import"./cli-zf8jjwex.js";
|
|
17
17
|
import"./cli-bc05qbss.js";
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
createDefaultMcpJson,
|
|
5
5
|
createDefaultSettingsLocal,
|
|
6
6
|
createHooksConfig
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-jbmc0r7r.js";
|
|
8
8
|
import {
|
|
9
9
|
require_jsx_dev_runtime
|
|
10
10
|
} from "./cli-s2qjdd6z.js";
|
|
11
11
|
import {
|
|
12
12
|
getApiKey
|
|
13
13
|
} from "./cli-f14fvzag.js";
|
|
14
|
-
import"./cli-
|
|
14
|
+
import"./cli-zvkq5csn.js";
|
|
15
15
|
import {
|
|
16
16
|
Box_default,
|
|
17
17
|
Spinner,
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isUserAllowed
|
|
3
|
-
} from "./cli-
|
|
4
|
-
import"./cli-
|
|
5
|
-
import"./cli-
|
|
6
|
-
import"./cli-
|
|
3
|
+
} from "./cli-ckz5t2hb.js";
|
|
4
|
+
import"./cli-jvy9qgjs.js";
|
|
5
|
+
import"./cli-3bpzj8me.js";
|
|
6
|
+
import"./cli-z3wkng35.js";
|
|
7
7
|
import"./cli-0z2v4nhw.js";
|
|
8
8
|
import"./cli-4wppfkcm.js";
|
|
9
9
|
import"./cli-e7d20cty.js";
|
|
10
10
|
import"./cli-re8z5p8p.js";
|
|
11
11
|
import"./cli-3dpj7atn.js";
|
|
12
|
-
import"./cli-
|
|
13
|
-
import"./cli-
|
|
12
|
+
import"./cli-b9dd0h3k.js";
|
|
13
|
+
import"./cli-r84ctdxn.js";
|
|
14
14
|
import"./cli-zfzznn7c.js";
|
|
15
|
-
import"./cli-
|
|
15
|
+
import"./cli-fmy65jdn.js";
|
|
16
16
|
import"./cli-epan13p1.js";
|
|
17
17
|
import"./cli-y89t4nca.js";
|
|
18
18
|
import"./cli-f14fvzag.js";
|
|
19
19
|
import"./cli-fad8m16k.js";
|
|
20
|
-
import"./cli-
|
|
21
|
-
import"./cli-
|
|
20
|
+
import"./cli-56h18ng2.js";
|
|
21
|
+
import"./cli-2nnd56zt.js";
|
|
22
22
|
import"./cli-bsakbbkm.js";
|
|
23
|
-
import"./cli-
|
|
23
|
+
import"./cli-gpqcs935.js";
|
|
24
24
|
import"./cli-51tf7ac3.js";
|
|
25
25
|
import {
|
|
26
26
|
getTaskUrl,
|
|
27
27
|
slackTaskOutput
|
|
28
|
-
} from "./cli-
|
|
28
|
+
} from "./cli-qn042eh7.js";
|
|
29
29
|
import"./cli-q51yprfq.js";
|
|
30
30
|
import"./cli-yatxqynm.js";
|
|
31
|
-
import"./cli-
|
|
31
|
+
import"./cli-jew3jda5.js";
|
|
32
32
|
import"./cli-fm4ytsdk.js";
|
|
33
33
|
import"./cli-aehm1rbq.js";
|
|
34
34
|
import"./cli-2658f6at.js";
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
getAgentById,
|
|
38
38
|
getTaskById,
|
|
39
39
|
init_db
|
|
40
|
-
} from "./cli-
|
|
40
|
+
} from "./cli-zvgj5zg8.js";
|
|
41
41
|
import"./cli-ht5rs63n.js";
|
|
42
42
|
import"./cli-z61ykvam.js";
|
|
43
43
|
import"./cli-dv6cdjs2.js";
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
} from "./cli-ej6gbxfb.js";
|
|
49
49
|
import"./cli-sd0mxa3c.js";
|
|
50
50
|
import"./cli-w5e1d1vv.js";
|
|
51
|
-
import"./cli-
|
|
51
|
+
import"./cli-zvkq5csn.js";
|
|
52
52
|
import"./cli-r2ap2czm.js";
|
|
53
53
|
import"./cli-pzxba7gw.js";
|
|
54
54
|
import"./cli-f7kvq46p.js";
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runAgent
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-qd65dvr6.js";
|
|
4
4
|
import"./cli-pgj4a5fb.js";
|
|
5
5
|
import"./cli-kj76p1ez.js";
|
|
6
6
|
import"./cli-9b13ggd1.js";
|
|
7
7
|
import"./cli-d3p82erb.js";
|
|
8
|
-
import"./cli-
|
|
9
|
-
import"./cli-
|
|
8
|
+
import"./cli-xw7vak96.js";
|
|
9
|
+
import"./cli-4ahpr4sw.js";
|
|
10
10
|
import"./cli-wbyk465z.js";
|
|
11
11
|
import"./cli-tng3131n.js";
|
|
12
12
|
import"./cli-5bfdm1ah.js";
|
|
13
|
-
import"./cli-
|
|
13
|
+
import"./cli-xy1cchaf.js";
|
|
14
14
|
import"./cli-hsxj0yar.js";
|
|
15
15
|
import"./cli-r94z9p1z.js";
|
|
16
16
|
import"./cli-b5b30yzk.js";
|
|
@@ -25,34 +25,34 @@ import"./cli-eree7rnv.js";
|
|
|
25
25
|
import"./cli-4yc5d8fk.js";
|
|
26
26
|
import {
|
|
27
27
|
getEnabledCapabilities
|
|
28
|
-
} from "./cli-
|
|
28
|
+
} from "./cli-z3wkng35.js";
|
|
29
29
|
import"./cli-0z2v4nhw.js";
|
|
30
30
|
import"./cli-4wppfkcm.js";
|
|
31
31
|
import"./cli-e7d20cty.js";
|
|
32
32
|
import"./cli-re8z5p8p.js";
|
|
33
33
|
import"./cli-3dpj7atn.js";
|
|
34
|
-
import"./cli-
|
|
35
|
-
import"./cli-
|
|
34
|
+
import"./cli-b9dd0h3k.js";
|
|
35
|
+
import"./cli-r84ctdxn.js";
|
|
36
36
|
import"./cli-zfzznn7c.js";
|
|
37
|
-
import"./cli-
|
|
37
|
+
import"./cli-fmy65jdn.js";
|
|
38
38
|
import"./cli-epan13p1.js";
|
|
39
39
|
import"./cli-y89t4nca.js";
|
|
40
40
|
import"./cli-f14fvzag.js";
|
|
41
41
|
import"./cli-fad8m16k.js";
|
|
42
|
-
import"./cli-
|
|
43
|
-
import"./cli-
|
|
42
|
+
import"./cli-56h18ng2.js";
|
|
43
|
+
import"./cli-2nnd56zt.js";
|
|
44
44
|
import"./cli-bsakbbkm.js";
|
|
45
|
-
import"./cli-
|
|
45
|
+
import"./cli-gpqcs935.js";
|
|
46
46
|
import"./cli-51tf7ac3.js";
|
|
47
|
-
import"./cli-
|
|
47
|
+
import"./cli-qn042eh7.js";
|
|
48
48
|
import"./cli-q51yprfq.js";
|
|
49
49
|
import"./cli-yatxqynm.js";
|
|
50
|
-
import"./cli-
|
|
50
|
+
import"./cli-jew3jda5.js";
|
|
51
51
|
import"./cli-fm4ytsdk.js";
|
|
52
52
|
import"./cli-aehm1rbq.js";
|
|
53
53
|
import"./cli-2658f6at.js";
|
|
54
54
|
import"./cli-jsp14b6c.js";
|
|
55
|
-
import"./cli-
|
|
55
|
+
import"./cli-zvgj5zg8.js";
|
|
56
56
|
import"./cli-ht5rs63n.js";
|
|
57
57
|
import"./cli-z61ykvam.js";
|
|
58
58
|
import"./cli-dv6cdjs2.js";
|
|
@@ -60,7 +60,7 @@ import"./cli-c2mk1kgf.js";
|
|
|
60
60
|
import"./cli-ej6gbxfb.js";
|
|
61
61
|
import"./cli-sd0mxa3c.js";
|
|
62
62
|
import"./cli-w5e1d1vv.js";
|
|
63
|
-
import"./cli-
|
|
63
|
+
import"./cli-zvkq5csn.js";
|
|
64
64
|
import"./cli-r2ap2czm.js";
|
|
65
65
|
import"./cli-pzxba7gw.js";
|
|
66
66
|
import"./cli-f7kvq46p.js";
|
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Swarm API",
|
|
5
|
-
"version": "1.152.
|
|
5
|
+
"version": "1.152.2",
|
|
6
6
|
"description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.152.
|
|
3
|
+
"version": "1.152.2",
|
|
4
4
|
"description": "agent-swarm.dev — an open-source operating system for AI work: a lead agent breaks goals into tasks, routes them to specialized workers such as Claude Code or Codex, runs each worker in an isolated container, and preserves shared memory, tools, schedules, and review gates so delegated work compounds across sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-swarm.dev",
|
package/src/slack/assistant.ts
CHANGED
|
@@ -129,7 +129,15 @@ export function createAssistant(): Assistant {
|
|
|
129
129
|
|
|
130
130
|
// Follow-up message → buffer text and file metadata until the flush.
|
|
131
131
|
if (workingAgent && workingAgent.status !== "offline" && isAdditiveSlack()) {
|
|
132
|
-
bufferThreadMessage(
|
|
132
|
+
bufferThreadMessage(
|
|
133
|
+
channelId,
|
|
134
|
+
threadTs,
|
|
135
|
+
messageText,
|
|
136
|
+
userId,
|
|
137
|
+
message.ts,
|
|
138
|
+
files,
|
|
139
|
+
cachedBotUserId ?? undefined,
|
|
140
|
+
);
|
|
133
141
|
const count = getBufferMessageCount(`${channelId}:${threadTs}`);
|
|
134
142
|
const event = count === 1 ? "accepted" : "buffered";
|
|
135
143
|
await ackSlackMessage(client, channelId, message.ts, reactionName(event), event);
|
|
@@ -147,6 +155,7 @@ export function createAssistant(): Assistant {
|
|
|
147
155
|
// raw `messageText`, not this rendered copy.
|
|
148
156
|
const renderedMessageText = await rewriteSlackMentions(
|
|
149
157
|
buildEffectiveText(messageText, inbound.files, inbound.failed),
|
|
158
|
+
cachedBotUserId ?? undefined,
|
|
150
159
|
);
|
|
151
160
|
|
|
152
161
|
if (workingAgent && workingAgent.status !== "offline") {
|
package/src/slack/handlers.ts
CHANGED
|
@@ -523,7 +523,15 @@ export function registerMessageHandler(app: App): void {
|
|
|
523
523
|
);
|
|
524
524
|
|
|
525
525
|
if (nowMessage || msg.files?.length) {
|
|
526
|
-
bufferThreadMessage(
|
|
526
|
+
bufferThreadMessage(
|
|
527
|
+
msg.channel,
|
|
528
|
+
msg.thread_ts,
|
|
529
|
+
nowMessage,
|
|
530
|
+
msg.user,
|
|
531
|
+
msg.ts,
|
|
532
|
+
msg.files,
|
|
533
|
+
botUserId,
|
|
534
|
+
);
|
|
527
535
|
}
|
|
528
536
|
|
|
529
537
|
// Instant flush — no dependency
|
|
@@ -563,6 +571,7 @@ export function registerMessageHandler(app: App): void {
|
|
|
563
571
|
msg.user,
|
|
564
572
|
msg.ts,
|
|
565
573
|
msg.files,
|
|
574
|
+
botUserId,
|
|
566
575
|
);
|
|
567
576
|
|
|
568
577
|
// Slack feedback: react with the accepted reaction on first buffer, buffered on appends
|
|
@@ -30,6 +30,7 @@ interface BufferedMessage {
|
|
|
30
30
|
channelId: string;
|
|
31
31
|
threadTs: string;
|
|
32
32
|
files?: SlackFile[];
|
|
33
|
+
botUserId?: string;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
const BUFFER_TIMEOUT_MS = Number(process.env.ADDITIVE_SLACK_BUFFER_MS) || 10_000;
|
|
@@ -62,6 +63,7 @@ export function bufferThreadMessage(
|
|
|
62
63
|
userId: string,
|
|
63
64
|
ts: string,
|
|
64
65
|
files?: SlackFile[],
|
|
66
|
+
botUserId?: string,
|
|
65
67
|
): void {
|
|
66
68
|
slackBuffer.enqueue(makeKey(channelId, threadTs), {
|
|
67
69
|
text,
|
|
@@ -70,6 +72,7 @@ export function bufferThreadMessage(
|
|
|
70
72
|
channelId,
|
|
71
73
|
threadTs,
|
|
72
74
|
files,
|
|
75
|
+
botUserId,
|
|
73
76
|
});
|
|
74
77
|
}
|
|
75
78
|
|
|
@@ -98,7 +101,11 @@ export async function instantFlush(key: string): Promise<void> {
|
|
|
98
101
|
/**
|
|
99
102
|
* Fetch thread context from Slack for the buffer flush task description.
|
|
100
103
|
*/
|
|
101
|
-
async function getThreadContextForBuffer(
|
|
104
|
+
async function getThreadContextForBuffer(
|
|
105
|
+
channelId: string,
|
|
106
|
+
threadTs: string,
|
|
107
|
+
botUserId?: string,
|
|
108
|
+
): Promise<string> {
|
|
102
109
|
const app = getSlackApp();
|
|
103
110
|
if (!app) return "";
|
|
104
111
|
|
|
@@ -126,7 +133,7 @@ async function getThreadContextForBuffer(channelId: string, threadTs: string): P
|
|
|
126
133
|
})
|
|
127
134
|
.join("\n");
|
|
128
135
|
|
|
129
|
-
return await rewriteSlackMentions(formatted);
|
|
136
|
+
return await rewriteSlackMentions(formatted, botUserId);
|
|
130
137
|
} catch (error) {
|
|
131
138
|
console.error("[Slack] Failed to fetch thread context for buffer:", error);
|
|
132
139
|
return "";
|
|
@@ -153,6 +160,9 @@ async function slackFlush(
|
|
|
153
160
|
// Buffer is guaranteed to have at least one item — the first carries the
|
|
154
161
|
// original requester's userId (same semantics as the pre-refactor version).
|
|
155
162
|
const originalRequesterId = items[0]!.userId;
|
|
163
|
+
// Every buffered item is resolved from the same bot's auth.test() cache —
|
|
164
|
+
// any item carrying it is representative of the whole flush.
|
|
165
|
+
const botUserId = items.find((item) => item.botUserId)?.botUserId;
|
|
156
166
|
|
|
157
167
|
console.log(`[Slack] Flushing buffer: ${key} (${items.length} messages, immediate=${immediate})`);
|
|
158
168
|
|
|
@@ -182,6 +192,7 @@ async function slackFlush(
|
|
|
182
192
|
),
|
|
183
193
|
)
|
|
184
194
|
.join("\n---\n"),
|
|
195
|
+
botUserId,
|
|
185
196
|
);
|
|
186
197
|
const description = `[Thread follow-up — ${items.length} message(s) buffered]\n\n${combinedText}`;
|
|
187
198
|
|
|
@@ -234,7 +245,7 @@ async function slackFlush(
|
|
|
234
245
|
const lead = await getLeadAgent();
|
|
235
246
|
|
|
236
247
|
// Thread context for the task
|
|
237
|
-
const threadContext = await getThreadContextForBuffer(channelId, threadTs);
|
|
248
|
+
const threadContext = await getThreadContextForBuffer(channelId, threadTs, botUserId);
|
|
238
249
|
const fullDescription = threadContext
|
|
239
250
|
? `<thread_context>\n${threadContext}\n</thread_context>\n\n${description}`
|
|
240
251
|
: description;
|
|
@@ -6,9 +6,15 @@ import {
|
|
|
6
6
|
createTaskExtended,
|
|
7
7
|
getAgentWorkingOnThread,
|
|
8
8
|
getLeadAgent,
|
|
9
|
+
getMostRecentTaskInThread,
|
|
9
10
|
getTaskById,
|
|
10
11
|
initDb,
|
|
11
12
|
} from "../be/db";
|
|
13
|
+
import { createAssistant } from "../slack/assistant";
|
|
14
|
+
import { getBufferMessageCount, instantFlush } from "../slack/thread-buffer";
|
|
15
|
+
|
|
16
|
+
/** The single function Bolt's `Assistant` stores for the `message` event — not part of its public type. */
|
|
17
|
+
type AssistantUserMessageHandler = (args: Record<string, unknown>) => Promise<void>;
|
|
12
18
|
|
|
13
19
|
process.env.SLACK_RENDER_V2 = "false";
|
|
14
20
|
|
|
@@ -121,6 +127,134 @@ describe("assistant userMessage routing — follow-up (working agent exists)", (
|
|
|
121
127
|
});
|
|
122
128
|
});
|
|
123
129
|
|
|
130
|
+
describe("assistant DM path self-mention rendering — production ingestion path", () => {
|
|
131
|
+
// Drives `createAssistant()`'s real `userMessage` handler end-to-end (the
|
|
132
|
+
// production DM path), rather than calling `rewriteSlackMentions` in
|
|
133
|
+
// isolation. It must fail if the fix at src/slack/assistant.ts (the
|
|
134
|
+
// `cachedBotUserId ?? undefined` argument to `rewriteSlackMentions`) is
|
|
135
|
+
// reverted.
|
|
136
|
+
const BOT_USER_ID = "U0PRODBOT99";
|
|
137
|
+
const OTHER_USER_ID = "U0PRODOTHR1";
|
|
138
|
+
const CHANNEL_ID = "D_PROD_DM_SELF_MENTION";
|
|
139
|
+
const THREAD_TS = "5551112223.000001";
|
|
140
|
+
|
|
141
|
+
test("resolves the bot's own mention and leaves another user's mention correct", async () => {
|
|
142
|
+
const assistant = createAssistant();
|
|
143
|
+
const userMessage = (assistant as unknown as { userMessage: AssistantUserMessageHandler[] })
|
|
144
|
+
.userMessage[0];
|
|
145
|
+
|
|
146
|
+
const client = {
|
|
147
|
+
auth: { test: async () => ({ user_id: BOT_USER_ID }) },
|
|
148
|
+
reactions: { add: async () => ({}) },
|
|
149
|
+
chat: { postMessage: async () => ({}) },
|
|
150
|
+
users: { info: async () => ({ user: undefined }) },
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const message = {
|
|
154
|
+
channel: CHANNEL_ID,
|
|
155
|
+
ts: THREAD_TS,
|
|
156
|
+
thread_ts: THREAD_TS,
|
|
157
|
+
text: `<@${BOT_USER_ID}> can you loop in <@${OTHER_USER_ID}> on this?`,
|
|
158
|
+
user: "U_PROD_REQUESTER",
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
await userMessage({
|
|
162
|
+
message,
|
|
163
|
+
body: { event_id: "Ev_PROD_DM_SELF_MENTION_1" },
|
|
164
|
+
say: async () => {},
|
|
165
|
+
setStatus: async () => ({}),
|
|
166
|
+
setTitle: async () => ({}),
|
|
167
|
+
getThreadContext: async () => undefined,
|
|
168
|
+
client,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const task = await getMostRecentTaskInThread(CHANNEL_ID, THREAD_TS);
|
|
172
|
+
expect(task).toBeDefined();
|
|
173
|
+
expect(task!.task).toBe(
|
|
174
|
+
`<@${BOT_USER_ID}> (that's you) can you loop in <@${OTHER_USER_ID}> (unknown user) on this?`,
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe("assistant DM path self-mention rendering — buffered follow-up path (ADDITIVE_SLACK)", () => {
|
|
180
|
+
// With ADDITIVE_SLACK=true and an active agent already on the DM thread,
|
|
181
|
+
// userMessage buffers the message and returns before the direct
|
|
182
|
+
// rewriteSlackMentions(..., cachedBotUserId) call runs. The bot ID must
|
|
183
|
+
// still reach the later flush in thread-buffer.ts, or the bot's own
|
|
184
|
+
// mention renders as "(unknown user)" instead of "(that's you)".
|
|
185
|
+
// `cachedBotUserId` in assistant.ts is a module-level singleton resolved
|
|
186
|
+
// once per process, so this must reuse the ID the earlier describe block
|
|
187
|
+
// already cached via auth.test() — a fresh ID here would make this
|
|
188
|
+
// message look like it mentions "someone else" and never reach the
|
|
189
|
+
// buffered branch at all.
|
|
190
|
+
const BOT_USER_ID = "U0PRODBOT99";
|
|
191
|
+
const OTHER_USER_ID = "U0BUFOTHR01";
|
|
192
|
+
const CHANNEL_ID = "D_BUF_DM_SELF_MENTION";
|
|
193
|
+
const THREAD_TS = "5552223334.000001";
|
|
194
|
+
|
|
195
|
+
const originalAdditiveSlack = process.env.ADDITIVE_SLACK;
|
|
196
|
+
|
|
197
|
+
beforeAll(() => {
|
|
198
|
+
process.env.ADDITIVE_SLACK = "true";
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
afterAll(() => {
|
|
202
|
+
if (originalAdditiveSlack === undefined) delete process.env.ADDITIVE_SLACK;
|
|
203
|
+
else process.env.ADDITIVE_SLACK = originalAdditiveSlack;
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("bot's own mention resolves through the buffered flush", async () => {
|
|
207
|
+
const worker = await createAgent({ name: "BufferedDmWorker", isLead: false, status: "idle" });
|
|
208
|
+
await createTaskExtended("original task in buffered DM thread", {
|
|
209
|
+
agentId: worker.id,
|
|
210
|
+
source: "slack",
|
|
211
|
+
slackChannelId: CHANNEL_ID,
|
|
212
|
+
slackThreadTs: THREAD_TS,
|
|
213
|
+
slackUserId: "U_BUF_REQUESTER",
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const assistant = createAssistant();
|
|
217
|
+
const userMessage = (assistant as unknown as { userMessage: AssistantUserMessageHandler[] })
|
|
218
|
+
.userMessage[0];
|
|
219
|
+
|
|
220
|
+
const client = {
|
|
221
|
+
auth: { test: async () => ({ user_id: BOT_USER_ID }) },
|
|
222
|
+
reactions: { add: async () => ({}) },
|
|
223
|
+
chat: { postMessage: async () => ({}) },
|
|
224
|
+
users: { info: async () => ({ user: undefined }) },
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const message = {
|
|
228
|
+
channel: CHANNEL_ID,
|
|
229
|
+
ts: "5552223334.000002",
|
|
230
|
+
thread_ts: THREAD_TS,
|
|
231
|
+
text: `<@${BOT_USER_ID}> can you loop in <@${OTHER_USER_ID}> on this?`,
|
|
232
|
+
user: "U_BUF_REQUESTER",
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
await userMessage({
|
|
236
|
+
message,
|
|
237
|
+
body: { event_id: "Ev_BUF_DM_SELF_MENTION_1" },
|
|
238
|
+
say: async () => {},
|
|
239
|
+
setStatus: async () => ({}),
|
|
240
|
+
setTitle: async () => ({}),
|
|
241
|
+
getThreadContext: async () => undefined,
|
|
242
|
+
client,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Buffered, not turned into a task synchronously.
|
|
246
|
+
expect(getBufferMessageCount(`${CHANNEL_ID}:${THREAD_TS}`)).toBe(1);
|
|
247
|
+
|
|
248
|
+
await instantFlush(`${CHANNEL_ID}:${THREAD_TS}`);
|
|
249
|
+
|
|
250
|
+
const flushed = await getMostRecentTaskInThread(CHANNEL_ID, THREAD_TS);
|
|
251
|
+
expect(flushed).toBeDefined();
|
|
252
|
+
expect(flushed!.task).toContain(`<@${BOT_USER_ID}> (that's you)`);
|
|
253
|
+
expect(flushed!.task).not.toContain(`<@${BOT_USER_ID}> (unknown user)`);
|
|
254
|
+
expect(flushed!.task).toContain(`<@${OTHER_USER_ID}> (unknown user)`);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
124
258
|
describe("assistant thread title truncation", () => {
|
|
125
259
|
test("short messages stay as-is", () => {
|
|
126
260
|
const text = "Check agent status";
|