@desplega.ai/agent-swarm 1.123.0 → 1.124.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/README.md +2 -1
- package/dist/{actions-e4c9f0xy.js → actions-z3d0fk7z.js} +6 -6
- package/dist/{app-vmvmj2v3.js → app-q2rc9tdr.js} +4 -4
- package/dist/{assistant-yn7a792a.js → assistant-3stjq7fz.js} +9 -9
- package/dist/{boot-reembed-xg1r86h2.js → boot-reembed-5867whnb.js} +3 -3
- package/dist/{boot-reembed-chxty50a.js → boot-reembed-v6r1df32.js} +4 -4
- package/dist/{boot-scrub-logs-exwddvp5.js → boot-scrub-logs-8b8jegk3.js} +2 -2
- package/dist/{cli-1592nfd6.js → cli-0925phzv.js} +1 -1
- package/dist/{cli-hbbxmhec.js → cli-2yr6edr7.js} +4 -4
- package/dist/{cli-8cq4z4x7.js → cli-3z4q09tn.js} +182 -19
- package/dist/{cli-vz9drmce.js → cli-5jn6wnd9.js} +17 -8
- package/dist/{cli-5arfywtm.js → cli-5ncdb7ff.js} +19 -9
- package/dist/{cli-3tv9z4wx.js → cli-92bqgbgy.js} +1 -1
- package/dist/{cli-fjf04hpa.js → cli-dq2ssyf0.js} +48 -56
- package/dist/{cli-mngsj9fx.js → cli-gkvf8d83.js} +1 -1
- package/dist/{cli-mepk1j0t.js → cli-gzjsamwc.js} +2 -2
- package/dist/{cli-c9m59f83.js → cli-h89g0qrd.js} +1 -1
- package/dist/{cli-n8mf7x4b.js → cli-jp4mdj9d.js} +2 -2
- package/dist/{cli-822d4bjk.js → cli-kk58tg33.js} +7 -7
- package/dist/{cli-9hj1adgp.js → cli-mcez7z4p.js} +1 -1
- package/dist/{cli-byv3720g.js → cli-mmk5vagg.js} +2 -2
- package/dist/{cli-zdp11t8m.js → cli-p0ec4vv6.js} +1 -1
- package/dist/{cli-h2say6xk.js → cli-p0zgv8pj.js} +3 -1
- package/dist/{cli-8ef5ky75.js → cli-perb20ma.js} +1 -1
- package/dist/{cli-zkj6f2sk.js → cli-qf7acvyr.js} +90 -4
- package/dist/{cli-kmm1rwmp.js → cli-qwsagsmg.js} +1 -1
- package/dist/{cli-we91ywvy.js → cli-sqv6c9b8.js} +6 -6
- package/dist/{cli-np0yhmmk.js → cli-vm20sh8d.js} +3 -3
- package/dist/{cli-p11rf59d.js → cli-wn3m6q54.js} +3 -3
- package/dist/{cli-mkpf4ndf.js → cli-x268say8.js} +2976 -5621
- package/dist/{cli-ngbsk4yx.js → cli-y43n987v.js} +1 -1
- package/dist/{cli-4509mwm5.js → cli-ykthjw29.js} +8 -8
- package/dist/{cli-9eka6jwv.js → cli-zxb72ctk.js} +2 -2
- package/dist/cli.js +12 -10
- package/dist/{commands-sjk3zfyr.js → commands-sda76yn8.js} +2 -2
- package/dist/{db-2je5agjb.js → db-vn9e4rqj.js} +6 -2
- package/dist/{e2b-2s4psnbf.js → e2b-q345y8s4.js} +0 -4
- package/dist/{handlers-yzv369hf.js → handlers-xfja18ac.js} +9 -9
- package/dist/{hook-rfsj2r8x.js → hook-2medrp47.js} +1 -40
- package/dist/{http-v9rr144m.js → http-937pyjfc.js} +99 -44
- package/dist/{index-nr2199m6.js → index-2bqd2q9v.js} +11 -11
- package/dist/{index-3xtk777g.js → index-gw4en7jg.js} +9 -9
- package/dist/{index-c3tan44f.js → index-knqczmnm.js} +10 -10
- package/dist/{index-smjdc3h9.js → index-vah60vxp.js} +8 -8
- package/dist/{keepalive-5ds53bjd.js → keepalive-20rd6hxh.js} +5 -5
- package/dist/{lead-5xhez25b.js → lead-7w2k3a49.js} +21 -21
- package/dist/{maintenance-b43d24q6.js → maintenance-p3x918yw.js} +4 -4
- package/dist/{oauth-refresh-sweep-qe286vn2.js → oauth-refresh-sweep-shm0nzm4.js} +4 -4
- package/dist/{onboard-c4r3ds3z.js → onboard-py9dnf54.js} +6 -2
- package/dist/{otel-impl-nv3rjw61.js → otel-impl-7yjkfg68.js} +1 -1
- package/dist/{pi-mono-adapter-2syx1x4d.js → pi-mono-adapter-z6h98fva.js} +4 -38
- package/dist/{pricing-refresh-5ct2wp4k.js → pricing-refresh-3snb6370.js} +4 -4
- package/dist/{rbac-roles-m502w0qv.js → rbac-roles-5e72bbpk.js} +3 -3
- package/dist/{rbac-roles-b82cxpxn.js → rbac-roles-gqxdp8st.js} +4 -4
- package/dist/{seed-pricing-jhjphbf0.js → seed-pricing-bg42d7h2.js} +3 -3
- package/dist/{setup-zbaspydq.js → setup-nzk3kbbq.js} +2 -2
- package/dist/{worker-snvhpax5.js → worker-0p1jdzkm.js} +21 -21
- package/openapi.json +146 -1
- package/package.json +3 -1
- package/src/be/db.ts +81 -4
- package/src/be/models-catalog.ts +156 -0
- package/src/be/modelsdev-cache.ts +14 -1
- package/src/be/pricing-refresh.ts +2 -0
- package/src/be/scripts/typecheck.ts +17 -4
- package/src/be/seed-scripts/catalog/task-context-gathering.ts +1 -1
- package/src/commands/onboard/env-generator.ts +12 -0
- package/src/e2b/env.ts +0 -4
- package/src/hooks/hook.ts +0 -67
- package/src/http/all-routes.ts +1 -0
- package/src/http/index.ts +2 -0
- package/src/http/models-catalog.ts +65 -0
- package/src/http/workflows.ts +16 -4
- package/src/prompts/base-prompt.ts +8 -7
- package/src/prompts/session-templates.ts +106 -12
- package/src/providers/pi-mono-adapter.ts +12 -2
- package/src/providers/pi-mono-extension.ts +0 -64
- package/src/providers/pricing-sources.md +16 -1
- package/src/scripts-runtime/eval-harness.ts +18 -1
- package/src/scripts-runtime/swarm-sdk.ts +10 -0
- package/src/scripts-runtime/types/stdlib.d.ts +13 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +13 -0
- package/src/server-user.ts +4 -7
- package/src/slack/blocks.ts +21 -8
- package/src/slack/responses.ts +27 -51
- package/src/slack/watcher.ts +22 -5
- package/src/telemetry.ts +169 -3
- package/src/tests/base-prompt.test.ts +79 -0
- package/src/tests/mcp-tools-user.test.ts +62 -16
- package/src/tests/mcp-tools.test.ts +6 -3
- package/src/tests/memory-edit.test.ts +21 -4
- package/src/tests/model-groups-live-catalog.test.ts +65 -0
- package/src/tests/models-catalog.test.ts +119 -0
- package/src/tests/oauth-access-token-tool.test.ts +71 -1
- package/src/tests/pricing-refresh.test.ts +25 -0
- package/src/tests/prompt-template-session.test.ts +142 -5
- package/src/tests/rbac-charact-skills.test.ts +81 -14
- package/src/tests/script-apis-mcp.test.ts +56 -8
- package/src/tests/scripts-mcp-e2e.test.ts +157 -8
- package/src/tests/scripts-typecheck.test.ts +17 -0
- package/src/tests/sdk-allowlist.test.ts +34 -1
- package/src/tests/seed-scripts.test.ts +43 -0
- package/src/tests/slack-blocks.test.ts +2 -1
- package/src/tests/slack-inline-output.test.ts +24 -30
- package/src/tests/slack-watcher.test.ts +42 -0
- package/src/tests/steer-task-tool.test.ts +37 -8
- package/src/tests/steering-transport.test.ts +18 -3
- package/src/tests/swarm-tool-result-gate.test.ts +399 -0
- package/src/tests/task-tools-ctx.test.ts +49 -17
- package/src/tests/task-tools-ownership.test.ts +41 -13
- package/src/tests/telemetry-init.test.ts +376 -2
- package/src/tests/tool-output-agent-id.test.ts +14 -2
- package/src/tests/workflow-http-v2.test.ts +116 -0
- package/src/tools/accept-steer.ts +45 -53
- package/src/tools/cancel-task.ts +31 -41
- package/src/tools/context-diff.ts +19 -63
- package/src/tools/context-history.ts +22 -51
- package/src/tools/create-channel.ts +24 -39
- package/src/tools/create-metric.ts +19 -82
- package/src/tools/create-page.ts +20 -81
- package/src/tools/credential-bindings/tool.ts +125 -246
- package/src/tools/db-query.ts +13 -24
- package/src/tools/delete-channel.ts +25 -71
- package/src/tools/delete-page.ts +27 -75
- package/src/tools/get-metrics.ts +29 -22
- package/src/tools/get-swarm.ts +44 -15
- package/src/tools/get-task-details.ts +150 -32
- package/src/tools/get-tasks.ts +63 -29
- package/src/tools/inject-learning.ts +8 -38
- package/src/tools/join-swarm.ts +45 -47
- package/src/tools/kv/kv-delete.ts +13 -37
- package/src/tools/kv/kv-get.ts +38 -29
- package/src/tools/kv/kv-incr.ts +28 -56
- package/src/tools/kv/kv-list.ts +40 -31
- package/src/tools/kv/kv-set.ts +34 -76
- package/src/tools/list-channels.ts +24 -17
- package/src/tools/list-services.ts +37 -45
- package/src/tools/manage-user.ts +53 -66
- package/src/tools/mcp-servers/mcp-server-create.ts +19 -55
- package/src/tools/mcp-servers/mcp-server-delete.ts +9 -39
- package/src/tools/mcp-servers/mcp-server-get.ts +9 -35
- package/src/tools/mcp-servers/mcp-server-install.ts +13 -60
- package/src/tools/mcp-servers/mcp-server-list.ts +28 -26
- package/src/tools/mcp-servers/mcp-server-uninstall.ts +10 -36
- package/src/tools/mcp-servers/mcp-server-update.ts +13 -57
- package/src/tools/memory-delete.ts +16 -46
- package/src/tools/memory-edit.ts +48 -49
- package/src/tools/memory-get.ts +40 -36
- package/src/tools/memory-rate.ts +14 -44
- package/src/tools/memory-search.ts +46 -52
- package/src/tools/my-agent-info.ts +39 -33
- package/src/tools/oauth-access-token.ts +9 -24
- package/src/tools/poll-task.ts +50 -77
- package/src/tools/post-message.ts +24 -38
- package/src/tools/prompt-templates/delete.ts +16 -48
- package/src/tools/prompt-templates/get.ts +45 -42
- package/src/tools/prompt-templates/list.ts +29 -44
- package/src/tools/prompt-templates/preview.ts +14 -40
- package/src/tools/prompt-templates/set.ts +30 -52
- package/src/tools/read-messages.ts +45 -54
- package/src/tools/register-agentmail-inbox.ts +28 -84
- package/src/tools/register-kapso-number.ts +20 -50
- package/src/tools/register-service.ts +36 -44
- package/src/tools/repos/get-repos.ts +29 -21
- package/src/tools/repos/update-repo.ts +30 -27
- package/src/tools/request-human-input.ts +10 -33
- package/src/tools/resolve-user.ts +59 -16
- package/src/tools/schedules/create-schedule.ts +58 -173
- package/src/tools/schedules/delete-schedule.ts +16 -56
- package/src/tools/schedules/list-schedules.ts +41 -67
- package/src/tools/schedules/patch-schedule.ts +57 -153
- package/src/tools/schedules/run-schedule-now.ts +18 -59
- package/src/tools/schedules/update-schedule.ts +57 -153
- package/src/tools/script-apis.ts +46 -28
- package/src/tools/script-common.ts +129 -34
- package/src/tools/script-connections/tool.ts +59 -154
- package/src/tools/script-query-types.ts +43 -3
- package/src/tools/script-run.ts +41 -2
- package/src/tools/script-runs.ts +69 -1
- package/src/tools/script-search.ts +24 -1
- package/src/tools/script-upsert.ts +18 -3
- package/src/tools/send-task.ts +32 -81
- package/src/tools/skills/skill-create.ts +14 -39
- package/src/tools/skills/skill-delete.ts +14 -42
- package/src/tools/skills/skill-get-file.ts +10 -43
- package/src/tools/skills/skill-get.ts +9 -32
- package/src/tools/skills/skill-install-remote.ts +16 -52
- package/src/tools/skills/skill-install.ts +14 -52
- package/src/tools/skills/skill-list.ts +24 -26
- package/src/tools/skills/skill-publish.ts +18 -54
- package/src/tools/skills/skill-search.ts +21 -18
- package/src/tools/skills/skill-sync-remote.ts +12 -24
- package/src/tools/skills/skill-uninstall.ts +10 -26
- package/src/tools/skills/skill-update.ts +24 -81
- package/src/tools/slack-delete.ts +8 -32
- package/src/tools/slack-download-file.ts +17 -57
- package/src/tools/slack-list-channels.ts +16 -43
- package/src/tools/slack-post.ts +11 -40
- package/src/tools/slack-read.ts +33 -103
- package/src/tools/slack-reply.ts +16 -53
- package/src/tools/slack-start-thread.ts +14 -55
- package/src/tools/slack-update.ts +8 -35
- package/src/tools/slack-upload-file.ts +22 -122
- package/src/tools/steer-task.ts +22 -35
- package/src/tools/store-progress.ts +11 -26
- package/src/tools/swarm-config/delete-config.ts +19 -57
- package/src/tools/swarm-config/get-config.ts +36 -44
- package/src/tools/swarm-config/list-config.ts +36 -44
- package/src/tools/swarm-config/set-config.ts +35 -73
- package/src/tools/swarm-x.ts +20 -26
- package/src/tools/task-action.ts +26 -46
- package/src/tools/task-tool-ctx.ts +5 -13
- package/src/tools/tracker/tracker-link-task.ts +8 -22
- package/src/tools/tracker/tracker-map-agent.ts +8 -22
- package/src/tools/tracker/tracker-status.ts +27 -19
- package/src/tools/tracker/tracker-sync-status.ts +8 -18
- package/src/tools/tracker/tracker-unlink.ts +4 -16
- package/src/tools/unregister-service.ts +19 -59
- package/src/tools/update-profile.ts +60 -100
- package/src/tools/update-service-status.ts +42 -67
- package/src/tools/utils.ts +189 -8
- package/src/tools/whatsapp-message.ts +19 -32
- package/src/tools/workflows/cancel-workflow-run.ts +4 -16
- package/src/tools/workflows/create-workflow.ts +9 -38
- package/src/tools/workflows/delete-workflow.ts +5 -17
- package/src/tools/workflows/get-workflow-run.ts +41 -31
- package/src/tools/workflows/get-workflow.ts +10 -21
- package/src/tools/workflows/list-workflow-runs.ts +107 -34
- package/src/tools/workflows/list-workflows.ts +5 -17
- package/src/tools/workflows/patch-workflow-node.ts +11 -39
- package/src/tools/workflows/patch-workflow.ts +11 -36
- package/src/tools/workflows/retry-workflow-run.ts +4 -16
- package/src/tools/workflows/trigger-workflow.ts +22 -58
- package/src/tools/workflows/update-workflow.ts +10 -42
- package/templates/skills/swarm-scripts/SKILL.md +1 -1
|
@@ -4,7 +4,7 @@ import { getAgentById } from "@/be/db";
|
|
|
4
4
|
import { can } from "@/rbac";
|
|
5
5
|
import { getSlackApp } from "@/slack/app";
|
|
6
6
|
import { parseSlackTs } from "@/slack/message-text";
|
|
7
|
-
import { createToolRegistrar } from "@/tools/utils";
|
|
7
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
8
8
|
|
|
9
9
|
export const registerSlackDeleteTool = (server: McpServer) => {
|
|
10
10
|
createToolRegistrar(server)(
|
|
@@ -24,25 +24,16 @@ export const registerSlackDeleteTool = (server: McpServer) => {
|
|
|
24
24
|
"Timestamp of the message to delete. Accepts the dotted form (1783411554.596189), the 'p' deep-link form (p1783411554596189), or a full Slack permalink URL.",
|
|
25
25
|
),
|
|
26
26
|
}),
|
|
27
|
-
outputSchema:
|
|
28
|
-
success: z.boolean(),
|
|
29
|
-
message: z.string(),
|
|
30
|
-
}),
|
|
27
|
+
outputSchema: swarmToolOutputSchema(),
|
|
31
28
|
},
|
|
32
29
|
async ({ channelId, messageTs }, requestInfo, _meta) => {
|
|
33
30
|
if (!requestInfo.agentId) {
|
|
34
|
-
return
|
|
35
|
-
content: [{ type: "text", text: "Agent ID not found." }],
|
|
36
|
-
structuredContent: { success: false, message: "Agent ID not found." },
|
|
37
|
-
};
|
|
31
|
+
return toolErr("Agent ID not found.");
|
|
38
32
|
}
|
|
39
33
|
|
|
40
34
|
const agent = getAgentById(requestInfo.agentId);
|
|
41
35
|
if (!agent) {
|
|
42
|
-
return
|
|
43
|
-
content: [{ type: "text", text: "Agent not found." }],
|
|
44
|
-
structuredContent: { success: false, message: "Agent not found." },
|
|
45
|
-
};
|
|
36
|
+
return toolErr("Agent not found.");
|
|
46
37
|
}
|
|
47
38
|
|
|
48
39
|
const decision = can({
|
|
@@ -52,31 +43,19 @@ export const registerSlackDeleteTool = (server: McpServer) => {
|
|
|
52
43
|
source: "mcp",
|
|
53
44
|
});
|
|
54
45
|
if (!decision.allow) {
|
|
55
|
-
return
|
|
56
|
-
content: [{ type: "text", text: "Deleting Slack messages requires lead privileges." }],
|
|
57
|
-
structuredContent: {
|
|
58
|
-
success: false,
|
|
59
|
-
message: "Deleting Slack messages requires lead privileges.",
|
|
60
|
-
},
|
|
61
|
-
};
|
|
46
|
+
return toolErr("Deleting Slack messages requires lead privileges.");
|
|
62
47
|
}
|
|
63
48
|
|
|
64
49
|
const app = getSlackApp();
|
|
65
50
|
if (!app) {
|
|
66
|
-
return
|
|
67
|
-
content: [{ type: "text", text: "Slack not configured." }],
|
|
68
|
-
structuredContent: { success: false, message: "Slack not configured." },
|
|
69
|
-
};
|
|
51
|
+
return toolErr("Slack not configured.");
|
|
70
52
|
}
|
|
71
53
|
|
|
72
54
|
try {
|
|
73
55
|
const ts = parseSlackTs(messageTs);
|
|
74
56
|
await app.client.chat.delete({ channel: channelId, ts });
|
|
75
57
|
|
|
76
|
-
return
|
|
77
|
-
content: [{ type: "text", text: "Message deleted successfully." }],
|
|
78
|
-
structuredContent: { success: true, message: "Message deleted successfully." },
|
|
79
|
-
};
|
|
58
|
+
return toolOk("Message deleted successfully.");
|
|
80
59
|
} catch (error) {
|
|
81
60
|
const errorCode = (error as { data?: { error?: string } } | undefined)?.data?.error;
|
|
82
61
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
@@ -99,10 +78,7 @@ export const registerSlackDeleteTool = (server: McpServer) => {
|
|
|
99
78
|
message = `Failed to delete message: ${errorMsg}`;
|
|
100
79
|
}
|
|
101
80
|
|
|
102
|
-
return
|
|
103
|
-
content: [{ type: "text", text: message }],
|
|
104
|
-
structuredContent: { success: false, message },
|
|
105
|
-
};
|
|
81
|
+
return toolErr(message);
|
|
106
82
|
}
|
|
107
83
|
},
|
|
108
84
|
);
|
|
@@ -3,7 +3,7 @@ import * as z from "zod";
|
|
|
3
3
|
import { getAgentById } from "@/be/db";
|
|
4
4
|
import { getSlackApp } from "@/slack/app";
|
|
5
5
|
import { DEFAULT_DOWNLOAD_DIR, downloadFile, getFileInfo } from "@/slack/files";
|
|
6
|
-
import { createToolRegistrar } from "@/tools/utils";
|
|
6
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
7
7
|
|
|
8
8
|
export const registerSlackDownloadFileTool = (server: McpServer) => {
|
|
9
9
|
createToolRegistrar(server)(
|
|
@@ -35,58 +35,41 @@ export const registerSlackDownloadFileTool = (server: McpServer) => {
|
|
|
35
35
|
.optional()
|
|
36
36
|
.describe("Filename to use when saving. Only used if savePath is a directory."),
|
|
37
37
|
}),
|
|
38
|
-
outputSchema:
|
|
39
|
-
success: z.boolean(),
|
|
40
|
-
message: z.string(),
|
|
38
|
+
outputSchema: swarmToolOutputSchema({
|
|
41
39
|
savedPath: z.string().optional(),
|
|
42
40
|
fileInfo: z
|
|
43
|
-
.
|
|
44
|
-
id: z.string(),
|
|
45
|
-
name: z.string(),
|
|
46
|
-
mimetype: z.string(),
|
|
47
|
-
size: z.number(),
|
|
41
|
+
.looseObject({
|
|
42
|
+
id: z.string().optional(),
|
|
43
|
+
name: z.string().optional(),
|
|
44
|
+
mimetype: z.string().optional(),
|
|
45
|
+
size: z.number().optional(),
|
|
48
46
|
})
|
|
49
47
|
.optional(),
|
|
50
48
|
}),
|
|
51
49
|
},
|
|
52
50
|
async ({ fileId, url, savePath, filename }, requestInfo, _meta) => {
|
|
53
51
|
if (!requestInfo.agentId) {
|
|
54
|
-
return
|
|
55
|
-
content: [{ type: "text", text: "Agent ID not found." }],
|
|
56
|
-
structuredContent: { success: false, message: "Agent ID not found." },
|
|
57
|
-
};
|
|
52
|
+
return toolErr("Agent ID not found.");
|
|
58
53
|
}
|
|
59
54
|
|
|
60
55
|
const agent = getAgentById(requestInfo.agentId);
|
|
61
56
|
if (!agent) {
|
|
62
|
-
return
|
|
63
|
-
content: [{ type: "text", text: "Agent not found." }],
|
|
64
|
-
structuredContent: { success: false, message: "Agent not found." },
|
|
65
|
-
};
|
|
57
|
+
return toolErr("Agent not found.");
|
|
66
58
|
}
|
|
67
59
|
|
|
68
60
|
// Must provide either fileId or url
|
|
69
61
|
if (!fileId && !url) {
|
|
70
|
-
return
|
|
71
|
-
content: [{ type: "text", text: "Must provide either fileId or url." }],
|
|
72
|
-
structuredContent: { success: false, message: "Must provide either fileId or url." },
|
|
73
|
-
};
|
|
62
|
+
return toolErr("Must provide either fileId or url.");
|
|
74
63
|
}
|
|
75
64
|
|
|
76
65
|
const app = getSlackApp();
|
|
77
66
|
if (!app) {
|
|
78
|
-
return
|
|
79
|
-
content: [{ type: "text", text: "Slack not configured." }],
|
|
80
|
-
structuredContent: { success: false, message: "Slack not configured." },
|
|
81
|
-
};
|
|
67
|
+
return toolErr("Slack not configured.");
|
|
82
68
|
}
|
|
83
69
|
|
|
84
70
|
const token = process.env.SLACK_BOT_TOKEN;
|
|
85
71
|
if (!token) {
|
|
86
|
-
return
|
|
87
|
-
content: [{ type: "text", text: "Slack bot token not configured." }],
|
|
88
|
-
structuredContent: { success: false, message: "Slack bot token not configured." },
|
|
89
|
-
};
|
|
72
|
+
return toolErr("Slack bot token not configured.");
|
|
90
73
|
}
|
|
91
74
|
|
|
92
75
|
try {
|
|
@@ -104,10 +87,7 @@ export const registerSlackDownloadFileTool = (server: McpServer) => {
|
|
|
104
87
|
if (fileId) {
|
|
105
88
|
const info = await getFileInfo(app.client, fileId);
|
|
106
89
|
if (!info) {
|
|
107
|
-
return {
|
|
108
|
-
content: [{ type: "text", text: `File not found: ${fileId}` }],
|
|
109
|
-
structuredContent: { success: false, message: `File not found: ${fileId}` },
|
|
110
|
-
};
|
|
90
|
+
return toolErr(`File not found: ${fileId}`);
|
|
111
91
|
}
|
|
112
92
|
|
|
113
93
|
downloadUrl = info.url_private_download;
|
|
@@ -120,10 +100,7 @@ export const registerSlackDownloadFileTool = (server: McpServer) => {
|
|
|
120
100
|
}
|
|
121
101
|
|
|
122
102
|
if (!downloadUrl) {
|
|
123
|
-
return
|
|
124
|
-
content: [{ type: "text", text: "No download URL available." }],
|
|
125
|
-
structuredContent: { success: false, message: "No download URL available." },
|
|
126
|
-
};
|
|
103
|
+
return toolErr("No download URL available.");
|
|
127
104
|
}
|
|
128
105
|
|
|
129
106
|
// Determine save path
|
|
@@ -145,31 +122,14 @@ export const registerSlackDownloadFileTool = (server: McpServer) => {
|
|
|
145
122
|
});
|
|
146
123
|
|
|
147
124
|
if (!result.success) {
|
|
148
|
-
return {
|
|
149
|
-
content: [{ type: "text", text: `Failed to download file: ${result.error}` }],
|
|
150
|
-
structuredContent: {
|
|
151
|
-
success: false,
|
|
152
|
-
message: `Failed to download file: ${result.error}`,
|
|
153
|
-
},
|
|
154
|
-
};
|
|
125
|
+
return toolErr(`Failed to download file: ${result.error}`);
|
|
155
126
|
}
|
|
156
127
|
|
|
157
128
|
const successMsg = `File downloaded successfully to ${result.savedPath}`;
|
|
158
|
-
return {
|
|
159
|
-
content: [{ type: "text", text: successMsg }],
|
|
160
|
-
structuredContent: {
|
|
161
|
-
success: true,
|
|
162
|
-
message: successMsg,
|
|
163
|
-
savedPath: result.savedPath,
|
|
164
|
-
fileInfo,
|
|
165
|
-
},
|
|
166
|
-
};
|
|
129
|
+
return toolOk(successMsg, { data: { savedPath: result.savedPath, fileInfo } });
|
|
167
130
|
} catch (error) {
|
|
168
131
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
169
|
-
return {
|
|
170
|
-
content: [{ type: "text", text: `Failed to download file: ${errorMsg}` }],
|
|
171
|
-
structuredContent: { success: false, message: `Failed to download file: ${errorMsg}` },
|
|
172
|
-
};
|
|
132
|
+
return toolErr(`Failed to download file: ${errorMsg}`);
|
|
173
133
|
}
|
|
174
134
|
},
|
|
175
135
|
);
|
|
@@ -2,13 +2,13 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import { getAgentById } from "@/be/db";
|
|
4
4
|
import { getSlackApp } from "@/slack/app";
|
|
5
|
-
import { createToolRegistrar } from "@/tools/utils";
|
|
5
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
6
6
|
|
|
7
|
-
const SlackChannelSchema = z.
|
|
8
|
-
id: z.string(),
|
|
9
|
-
name: z.string(),
|
|
10
|
-
type: z.enum(["public", "private", "dm", "mpim"]),
|
|
11
|
-
isMember: z.boolean(),
|
|
7
|
+
const SlackChannelSchema = z.looseObject({
|
|
8
|
+
id: z.string().optional(),
|
|
9
|
+
name: z.string().optional(),
|
|
10
|
+
type: z.enum(["public", "private", "dm", "mpim"]).optional(),
|
|
11
|
+
isMember: z.boolean().optional(),
|
|
12
12
|
numMembers: z.number().optional(),
|
|
13
13
|
});
|
|
14
14
|
|
|
@@ -36,34 +36,23 @@ export const registerSlackListChannelsTool = (server: McpServer) => {
|
|
|
36
36
|
.default(100)
|
|
37
37
|
.describe("Maximum number of channels to retrieve (default: 100, max: 200)."),
|
|
38
38
|
}),
|
|
39
|
-
outputSchema:
|
|
40
|
-
|
|
41
|
-
message: z.string(),
|
|
42
|
-
channels: z.array(SlackChannelSchema),
|
|
39
|
+
outputSchema: swarmToolOutputSchema({
|
|
40
|
+
channels: z.array(SlackChannelSchema).optional(),
|
|
43
41
|
}),
|
|
44
42
|
},
|
|
45
43
|
async ({ types, limit = 100 }, requestInfo, _meta) => {
|
|
46
44
|
if (!requestInfo.agentId) {
|
|
47
|
-
return {
|
|
48
|
-
content: [{ type: "text", text: "Agent ID not found." }],
|
|
49
|
-
structuredContent: { success: false, message: "Agent ID not found.", channels: [] },
|
|
50
|
-
};
|
|
45
|
+
return toolErr("Agent ID not found.", { data: { channels: [] } });
|
|
51
46
|
}
|
|
52
47
|
|
|
53
48
|
const agent = getAgentById(requestInfo.agentId);
|
|
54
49
|
if (!agent) {
|
|
55
|
-
return {
|
|
56
|
-
content: [{ type: "text", text: "Agent not found." }],
|
|
57
|
-
structuredContent: { success: false, message: "Agent not found.", channels: [] },
|
|
58
|
-
};
|
|
50
|
+
return toolErr("Agent not found.", { data: { channels: [] } });
|
|
59
51
|
}
|
|
60
52
|
|
|
61
53
|
const app = getSlackApp();
|
|
62
54
|
if (!app) {
|
|
63
|
-
return {
|
|
64
|
-
content: [{ type: "text", text: "Slack not configured." }],
|
|
65
|
-
structuredContent: { success: false, message: "Slack not configured.", channels: [] },
|
|
66
|
-
};
|
|
55
|
+
return toolErr("Slack not configured.", { data: { channels: [] } });
|
|
67
56
|
}
|
|
68
57
|
|
|
69
58
|
try {
|
|
@@ -141,29 +130,13 @@ export const registerSlackListChannelsTool = (server: McpServer) => {
|
|
|
141
130
|
})
|
|
142
131
|
.join("\n");
|
|
143
132
|
|
|
144
|
-
return {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
text: `Found ${channels.length} channel(s):\n\n${textOutput}`,
|
|
149
|
-
},
|
|
150
|
-
],
|
|
151
|
-
structuredContent: {
|
|
152
|
-
success: true,
|
|
153
|
-
message: `Found ${channels.length} channel(s).`,
|
|
154
|
-
channels,
|
|
155
|
-
},
|
|
156
|
-
};
|
|
133
|
+
return toolOk(`Found ${channels.length} channel(s).`, {
|
|
134
|
+
details: textOutput || undefined,
|
|
135
|
+
data: { channels },
|
|
136
|
+
});
|
|
157
137
|
} catch (error) {
|
|
158
138
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
159
|
-
return {
|
|
160
|
-
content: [{ type: "text", text: `Failed to list Slack channels: ${errorMsg}` }],
|
|
161
|
-
structuredContent: {
|
|
162
|
-
success: false,
|
|
163
|
-
message: `Failed to list Slack channels: ${errorMsg}`,
|
|
164
|
-
channels: [],
|
|
165
|
-
},
|
|
166
|
-
};
|
|
139
|
+
return toolErr(`Failed to list Slack channels: ${errorMsg}`, { data: { channels: [] } });
|
|
167
140
|
}
|
|
168
141
|
},
|
|
169
142
|
);
|
package/src/tools/slack-post.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { can } from "@/rbac";
|
|
|
5
5
|
import { getSlackApp } from "@/slack/app";
|
|
6
6
|
import { withAutoJoin } from "@/slack/channel-join";
|
|
7
7
|
import { markdownToSlack } from "@/slack/responses";
|
|
8
|
-
import { createToolRegistrar } from "@/tools/utils";
|
|
8
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
9
9
|
|
|
10
10
|
export const registerSlackPostTool = (server: McpServer) => {
|
|
11
11
|
createToolRegistrar(server)(
|
|
@@ -26,26 +26,18 @@ export const registerSlackPostTool = (server: McpServer) => {
|
|
|
26
26
|
"Optional parent message ts to thread under. Obtain via `slack-start-thread`. When omitted, posts as a new top-level message.",
|
|
27
27
|
),
|
|
28
28
|
}),
|
|
29
|
-
outputSchema:
|
|
30
|
-
success: z.boolean(),
|
|
31
|
-
message: z.string(),
|
|
29
|
+
outputSchema: swarmToolOutputSchema({
|
|
32
30
|
messageTs: z.string().optional(),
|
|
33
31
|
}),
|
|
34
32
|
},
|
|
35
33
|
async ({ channelId, message, threadTs }, requestInfo, _meta) => {
|
|
36
34
|
if (!requestInfo.agentId) {
|
|
37
|
-
return
|
|
38
|
-
content: [{ type: "text", text: "Agent ID not found." }],
|
|
39
|
-
structuredContent: { success: false, message: "Agent ID not found." },
|
|
40
|
-
};
|
|
35
|
+
return toolErr("Agent ID not found.");
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
const agent = getAgentById(requestInfo.agentId);
|
|
44
39
|
if (!agent) {
|
|
45
|
-
return
|
|
46
|
-
content: [{ type: "text", text: "Agent not found." }],
|
|
47
|
-
structuredContent: { success: false, message: "Agent not found." },
|
|
48
|
-
};
|
|
40
|
+
return toolErr("Agent not found.");
|
|
49
41
|
}
|
|
50
42
|
|
|
51
43
|
// Require lead privileges to post directly to channels
|
|
@@ -56,21 +48,12 @@ export const registerSlackPostTool = (server: McpServer) => {
|
|
|
56
48
|
source: "mcp",
|
|
57
49
|
});
|
|
58
50
|
if (!decision.allow) {
|
|
59
|
-
return
|
|
60
|
-
content: [{ type: "text", text: "Posting to Slack channels requires lead privileges." }],
|
|
61
|
-
structuredContent: {
|
|
62
|
-
success: false,
|
|
63
|
-
message: "Posting to Slack channels requires lead privileges.",
|
|
64
|
-
},
|
|
65
|
-
};
|
|
51
|
+
return toolErr("Posting to Slack channels requires lead privileges.");
|
|
66
52
|
}
|
|
67
53
|
|
|
68
54
|
const app = getSlackApp();
|
|
69
55
|
if (!app) {
|
|
70
|
-
return
|
|
71
|
-
content: [{ type: "text", text: "Slack not configured." }],
|
|
72
|
-
structuredContent: { success: false, message: "Slack not configured." },
|
|
73
|
-
};
|
|
56
|
+
return toolErr("Slack not configured.");
|
|
74
57
|
}
|
|
75
58
|
|
|
76
59
|
try {
|
|
@@ -97,25 +80,13 @@ export const registerSlackPostTool = (server: McpServer) => {
|
|
|
97
80
|
|
|
98
81
|
const messageTs = result.ts;
|
|
99
82
|
|
|
100
|
-
return {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
text: `Message posted successfully.${messageTs ? ` Message timestamp: ${messageTs}` : ""}`,
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
structuredContent: {
|
|
108
|
-
success: true,
|
|
109
|
-
message: "Message posted successfully.",
|
|
110
|
-
messageTs,
|
|
111
|
-
},
|
|
112
|
-
};
|
|
83
|
+
return toolOk("Message posted successfully.", {
|
|
84
|
+
details: messageTs ? `Message timestamp: ${messageTs}` : undefined,
|
|
85
|
+
data: { messageTs },
|
|
86
|
+
});
|
|
113
87
|
} catch (error) {
|
|
114
88
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
115
|
-
return {
|
|
116
|
-
content: [{ type: "text", text: `Failed to post message: ${errorMsg}` }],
|
|
117
|
-
structuredContent: { success: false, message: `Failed to post message: ${errorMsg}` },
|
|
118
|
-
};
|
|
89
|
+
return toolErr(`Failed to post message: ${errorMsg}`);
|
|
119
90
|
}
|
|
120
91
|
},
|
|
121
92
|
);
|
package/src/tools/slack-read.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { getSlackApp } from "@/slack/app";
|
|
|
6
6
|
import { withAutoJoin } from "@/slack/channel-join";
|
|
7
7
|
import { downloadFile } from "@/slack/files";
|
|
8
8
|
import { extractSlackMessageText } from "@/slack/message-text";
|
|
9
|
-
import { createToolRegistrar } from "@/tools/utils";
|
|
9
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Default download directory for auto-downloaded Slack files (inside MCP container).
|
|
@@ -14,22 +14,22 @@ import { createToolRegistrar } from "@/tools/utils";
|
|
|
14
14
|
*/
|
|
15
15
|
const AUTO_DOWNLOAD_DIR = "/app/shared/downloads/slack";
|
|
16
16
|
|
|
17
|
-
const SlackFileSchema = z.
|
|
18
|
-
id: z.string(),
|
|
19
|
-
name: z.string(),
|
|
20
|
-
mimetype: z.string(),
|
|
21
|
-
filetype: z.string(),
|
|
22
|
-
size: z.number(),
|
|
23
|
-
url_private_download: z.string(),
|
|
17
|
+
const SlackFileSchema = z.looseObject({
|
|
18
|
+
id: z.string().optional(),
|
|
19
|
+
name: z.string().optional(),
|
|
20
|
+
mimetype: z.string().optional(),
|
|
21
|
+
filetype: z.string().optional(),
|
|
22
|
+
size: z.number().optional(),
|
|
23
|
+
url_private_download: z.string().optional(),
|
|
24
24
|
localPath: z.string().optional(),
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
const SlackMessageSchema = z.
|
|
27
|
+
const SlackMessageSchema = z.looseObject({
|
|
28
28
|
user: z.string().optional(),
|
|
29
29
|
username: z.string().optional(),
|
|
30
|
-
isBot: z.boolean(),
|
|
31
|
-
text: z.string(),
|
|
32
|
-
ts: z.string(),
|
|
30
|
+
isBot: z.boolean().optional(),
|
|
31
|
+
text: z.string().optional(),
|
|
32
|
+
ts: z.string().optional(),
|
|
33
33
|
files: z.array(SlackFileSchema).optional(),
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -65,12 +65,10 @@ export const registerSlackReadTool = (server: McpServer) => {
|
|
|
65
65
|
.default(true)
|
|
66
66
|
.describe("Include file attachments in the response (default: true)."),
|
|
67
67
|
}),
|
|
68
|
-
outputSchema:
|
|
69
|
-
success: z.boolean(),
|
|
70
|
-
message: z.string(),
|
|
68
|
+
outputSchema: swarmToolOutputSchema({
|
|
71
69
|
channelId: z.string().optional(),
|
|
72
70
|
threadTs: z.string().optional(),
|
|
73
|
-
messages: z.array(SlackMessageSchema),
|
|
71
|
+
messages: z.array(SlackMessageSchema).optional(),
|
|
74
72
|
}),
|
|
75
73
|
},
|
|
76
74
|
async (
|
|
@@ -79,18 +77,12 @@ export const registerSlackReadTool = (server: McpServer) => {
|
|
|
79
77
|
_meta,
|
|
80
78
|
) => {
|
|
81
79
|
if (!requestInfo.agentId) {
|
|
82
|
-
return {
|
|
83
|
-
content: [{ type: "text", text: "Agent ID not found." }],
|
|
84
|
-
structuredContent: { success: false, message: "Agent ID not found.", messages: [] },
|
|
85
|
-
};
|
|
80
|
+
return toolErr("Agent ID not found.", { data: { messages: [] } });
|
|
86
81
|
}
|
|
87
82
|
|
|
88
83
|
const agent = getAgentById(requestInfo.agentId);
|
|
89
84
|
if (!agent) {
|
|
90
|
-
return {
|
|
91
|
-
content: [{ type: "text", text: "Agent not found." }],
|
|
92
|
-
structuredContent: { success: false, message: "Agent not found.", messages: [] },
|
|
93
|
-
};
|
|
85
|
+
return toolErr("Agent not found.", { data: { messages: [] } });
|
|
94
86
|
}
|
|
95
87
|
|
|
96
88
|
let slackChannelId: string | undefined = channelId;
|
|
@@ -100,45 +92,21 @@ export const registerSlackReadTool = (server: McpServer) => {
|
|
|
100
92
|
if (inboxMessageId) {
|
|
101
93
|
const inboxMsg = getInboxMessageById(inboxMessageId);
|
|
102
94
|
if (!inboxMsg) {
|
|
103
|
-
return {
|
|
104
|
-
content: [{ type: "text", text: "Inbox message not found." }],
|
|
105
|
-
structuredContent: {
|
|
106
|
-
success: false,
|
|
107
|
-
message: "Inbox message not found.",
|
|
108
|
-
messages: [],
|
|
109
|
-
},
|
|
110
|
-
};
|
|
95
|
+
return toolErr("Inbox message not found.", { data: { messages: [] } });
|
|
111
96
|
}
|
|
112
97
|
if (inboxMsg.agentId !== requestInfo.agentId) {
|
|
113
|
-
return {
|
|
114
|
-
content: [{ type: "text", text: "This inbox message is not yours." }],
|
|
115
|
-
structuredContent: {
|
|
116
|
-
success: false,
|
|
117
|
-
message: "This inbox message is not yours.",
|
|
118
|
-
messages: [],
|
|
119
|
-
},
|
|
120
|
-
};
|
|
98
|
+
return toolErr("This inbox message is not yours.", { data: { messages: [] } });
|
|
121
99
|
}
|
|
122
100
|
slackChannelId = inboxMsg.slackChannelId;
|
|
123
101
|
slackThreadTs = inboxMsg.slackThreadTs;
|
|
124
102
|
} else if (taskId) {
|
|
125
103
|
const task = getTaskById(taskId);
|
|
126
104
|
if (!task) {
|
|
127
|
-
return {
|
|
128
|
-
content: [{ type: "text", text: "Task not found." }],
|
|
129
|
-
structuredContent: { success: false, message: "Task not found.", messages: [] },
|
|
130
|
-
};
|
|
105
|
+
return toolErr("Task not found.", { data: { messages: [] } });
|
|
131
106
|
}
|
|
132
107
|
// Verify agent has context for this task
|
|
133
108
|
if (task.agentId !== requestInfo.agentId && task.creatorAgentId !== requestInfo.agentId) {
|
|
134
|
-
return {
|
|
135
|
-
content: [{ type: "text", text: "You don't have context for this task." }],
|
|
136
|
-
structuredContent: {
|
|
137
|
-
success: false,
|
|
138
|
-
message: "You don't have context for this task.",
|
|
139
|
-
messages: [],
|
|
140
|
-
},
|
|
141
|
-
};
|
|
109
|
+
return toolErr("You don't have context for this task.", { data: { messages: [] } });
|
|
142
110
|
}
|
|
143
111
|
slackChannelId = task.slackChannelId;
|
|
144
112
|
slackThreadTs = task.slackThreadTs;
|
|
@@ -151,45 +119,25 @@ export const registerSlackReadTool = (server: McpServer) => {
|
|
|
151
119
|
source: "mcp",
|
|
152
120
|
});
|
|
153
121
|
if (!decision.allow) {
|
|
154
|
-
return {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
success: false,
|
|
158
|
-
message: "Direct channel access requires lead privileges.",
|
|
159
|
-
messages: [],
|
|
160
|
-
},
|
|
161
|
-
};
|
|
122
|
+
return toolErr("Direct channel access requires lead privileges.", {
|
|
123
|
+
data: { messages: [] },
|
|
124
|
+
});
|
|
162
125
|
}
|
|
163
126
|
slackChannelId = channelId;
|
|
164
127
|
slackThreadTs = threadTs;
|
|
165
128
|
} else {
|
|
166
|
-
return {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
success: false,
|
|
170
|
-
message: "Must provide inboxMessageId, taskId, or channelId.",
|
|
171
|
-
messages: [],
|
|
172
|
-
},
|
|
173
|
-
};
|
|
129
|
+
return toolErr("Must provide inboxMessageId, taskId, or channelId.", {
|
|
130
|
+
data: { messages: [] },
|
|
131
|
+
});
|
|
174
132
|
}
|
|
175
133
|
|
|
176
134
|
if (!slackChannelId) {
|
|
177
|
-
return {
|
|
178
|
-
content: [{ type: "text", text: "No Slack channel context available." }],
|
|
179
|
-
structuredContent: {
|
|
180
|
-
success: false,
|
|
181
|
-
message: "No Slack channel context available.",
|
|
182
|
-
messages: [],
|
|
183
|
-
},
|
|
184
|
-
};
|
|
135
|
+
return toolErr("No Slack channel context available.", { data: { messages: [] } });
|
|
185
136
|
}
|
|
186
137
|
|
|
187
138
|
const app = getSlackApp();
|
|
188
139
|
if (!app) {
|
|
189
|
-
return {
|
|
190
|
-
content: [{ type: "text", text: "Slack not configured." }],
|
|
191
|
-
structuredContent: { success: false, message: "Slack not configured.", messages: [] },
|
|
192
|
-
};
|
|
140
|
+
return toolErr("Slack not configured.", { data: { messages: [] } });
|
|
193
141
|
}
|
|
194
142
|
|
|
195
143
|
try {
|
|
@@ -370,31 +318,13 @@ export const registerSlackReadTool = (server: McpServer) => {
|
|
|
370
318
|
})
|
|
371
319
|
.join("\n\n");
|
|
372
320
|
|
|
373
|
-
return {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
text: `Retrieved ${messages.length} message(s) from Slack.\n\n${textOutput}`,
|
|
378
|
-
},
|
|
379
|
-
],
|
|
380
|
-
structuredContent: {
|
|
381
|
-
success: true,
|
|
382
|
-
message: `Retrieved ${messages.length} message(s).`,
|
|
383
|
-
channelId: slackChannelId,
|
|
384
|
-
threadTs: slackThreadTs,
|
|
385
|
-
messages,
|
|
386
|
-
},
|
|
387
|
-
};
|
|
321
|
+
return toolOk(`Retrieved ${messages.length} message(s).`, {
|
|
322
|
+
details: textOutput || undefined,
|
|
323
|
+
data: { channelId: slackChannelId, threadTs: slackThreadTs, messages },
|
|
324
|
+
});
|
|
388
325
|
} catch (error) {
|
|
389
326
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
390
|
-
return {
|
|
391
|
-
content: [{ type: "text", text: `Failed to read Slack messages: ${errorMsg}` }],
|
|
392
|
-
structuredContent: {
|
|
393
|
-
success: false,
|
|
394
|
-
message: `Failed to read Slack messages: ${errorMsg}`,
|
|
395
|
-
messages: [],
|
|
396
|
-
},
|
|
397
|
-
};
|
|
327
|
+
return toolErr(`Failed to read Slack messages: ${errorMsg}`, { data: { messages: [] } });
|
|
398
328
|
}
|
|
399
329
|
},
|
|
400
330
|
);
|