@agentforge/tools 0.8.2 → 0.9.1
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 +80 -7
- package/dist/index.cjs +387 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +296 -2
- package/dist/index.d.ts +296 -2
- package/dist/index.js +382 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @agentforge/tools
|
|
2
2
|
|
|
3
|
-
> Production-ready tools collection for AgentForge -
|
|
3
|
+
> Production-ready tools collection for AgentForge - 74 tools for web, data, file, utility, and agent operations
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@agentforge/tools)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## 🎉 Status: Production Ready & Published
|
|
10
10
|
|
|
11
|
-
**
|
|
11
|
+
**74 production-ready tools** | **Full TypeScript support** | **Comprehensive documentation** | **LangChain compatible**
|
|
12
12
|
|
|
13
13
|
## 📦 Installation
|
|
14
14
|
|
|
@@ -22,9 +22,9 @@ yarn add @agentforge/tools
|
|
|
22
22
|
|
|
23
23
|
## 🎯 Overview
|
|
24
24
|
|
|
25
|
-
This package provides **
|
|
25
|
+
This package provides **74 ready-to-use tools** organized into 5 categories:
|
|
26
26
|
|
|
27
|
-
- **🌐 Web Tools** (
|
|
27
|
+
- **🌐 Web Tools** (15 tools) - HTTP requests, web search, web scraping, HTML parsing, URL manipulation, Slack integration
|
|
28
28
|
- **📊 Data Tools** (18 tools) - JSON, CSV, XML processing and data transformation
|
|
29
29
|
- **📁 File Tools** (18 tools) - File operations, directory management, path utilities
|
|
30
30
|
- **🔧 Utility Tools** (22 tools) - Date/time, strings, math, validation
|
|
@@ -96,6 +96,13 @@ Tools for web interactions and HTTP operations.
|
|
|
96
96
|
- **`urlBuilder`** - Build URLs from components
|
|
97
97
|
- **`urlQueryParser`** - Parse query parameters
|
|
98
98
|
|
|
99
|
+
#### Slack Tools
|
|
100
|
+
- **`sendSlackMessage`** - Send messages to Slack channels
|
|
101
|
+
- **`notifySlack`** - Send notifications with @mentions
|
|
102
|
+
- **`getSlackChannels`** - List available Slack channels
|
|
103
|
+
- **`getSlackMessages`** - Read message history from channels
|
|
104
|
+
- **`createSlackTools()`** - Factory function for custom Slack configuration
|
|
105
|
+
|
|
99
106
|
### 📊 Data Tools (18 tools)
|
|
100
107
|
|
|
101
108
|
Tools for data processing and transformation.
|
|
@@ -287,6 +294,71 @@ console.log(result.links);
|
|
|
287
294
|
console.log(result.metadata);
|
|
288
295
|
```
|
|
289
296
|
|
|
297
|
+
### Slack Integration Example
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import {
|
|
301
|
+
sendSlackMessage,
|
|
302
|
+
notifySlack,
|
|
303
|
+
getSlackChannels,
|
|
304
|
+
getSlackMessages,
|
|
305
|
+
createSlackTools
|
|
306
|
+
} from '@agentforge/tools';
|
|
307
|
+
|
|
308
|
+
// Send a simple message
|
|
309
|
+
const message = await sendSlackMessage.execute({
|
|
310
|
+
channel: 'general',
|
|
311
|
+
message: 'Hello from AgentForge!'
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Send a notification with mentions
|
|
315
|
+
const notification = await notifySlack.execute({
|
|
316
|
+
channel: 'alerts',
|
|
317
|
+
message: 'System alert: High CPU usage detected',
|
|
318
|
+
mentions: ['john', 'jane'] // Will send as: @john @jane System alert...
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// List available channels
|
|
322
|
+
const channels = await getSlackChannels.execute({
|
|
323
|
+
include_private: false // Only public channels
|
|
324
|
+
});
|
|
325
|
+
console.log(channels.data?.channels);
|
|
326
|
+
|
|
327
|
+
// Read message history
|
|
328
|
+
const history = await getSlackMessages.execute({
|
|
329
|
+
channel: 'general',
|
|
330
|
+
limit: 50
|
|
331
|
+
});
|
|
332
|
+
console.log(`Found ${history.data?.count} messages`);
|
|
333
|
+
|
|
334
|
+
// Custom configuration (for multiple workspaces or custom bot settings)
|
|
335
|
+
const customTools = createSlackTools({
|
|
336
|
+
token: 'xoxb-your-custom-token',
|
|
337
|
+
botName: 'My Custom Bot',
|
|
338
|
+
botIcon: ':rocket:'
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
await customTools.sendMessage.execute({
|
|
342
|
+
channel: 'general',
|
|
343
|
+
message: 'Message from custom bot!'
|
|
344
|
+
});
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Environment Setup:**
|
|
348
|
+
```bash
|
|
349
|
+
# Add to your .env file
|
|
350
|
+
SLACK_USER_TOKEN=xoxp-your-user-token
|
|
351
|
+
# OR
|
|
352
|
+
SLACK_BOT_TOKEN=xoxb-your-bot-token
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Getting a Slack Token:**
|
|
356
|
+
1. Go to [Slack API](https://api.slack.com/apps)
|
|
357
|
+
2. Create a new app or select existing
|
|
358
|
+
3. Add OAuth scopes: `chat:write`, `channels:read`, `channels:history`
|
|
359
|
+
4. Install app to workspace
|
|
360
|
+
5. Copy the token (starts with `xoxb-` for bot or `xoxp-` for user)
|
|
361
|
+
|
|
290
362
|
### Data Processing Example
|
|
291
363
|
|
|
292
364
|
```typescript
|
|
@@ -522,12 +594,13 @@ pnpm lint
|
|
|
522
594
|
|
|
523
595
|
## 📊 Tool Statistics
|
|
524
596
|
|
|
525
|
-
- **Total Tools**:
|
|
526
|
-
- **Web Tools**:
|
|
597
|
+
- **Total Tools**: 74
|
|
598
|
+
- **Web Tools**: 15 (includes 4 Slack tools)
|
|
527
599
|
- **Data Tools**: 18
|
|
528
600
|
- **File Tools**: 18
|
|
529
601
|
- **Utility Tools**: 22
|
|
530
|
-
- **
|
|
602
|
+
- **Agent Tools**: 1
|
|
603
|
+
- **Lines of Code**: ~3,200
|
|
531
604
|
- **Full TypeScript Support**: ✅
|
|
532
605
|
- **Zod Validation**: ✅
|
|
533
606
|
- **LangChain Compatible**: ✅
|
package/dist/index.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var core = require('@agentforge/core');
|
|
|
4
4
|
var zod = require('zod');
|
|
5
5
|
var axios = require('axios');
|
|
6
6
|
var cheerio2 = require('cheerio');
|
|
7
|
+
var webApi = require('@slack/web-api');
|
|
7
8
|
var sync = require('csv-parse/sync');
|
|
8
9
|
var sync$1 = require('csv-stringify/sync');
|
|
9
10
|
var fastXmlParser = require('fast-xml-parser');
|
|
@@ -682,6 +683,381 @@ var webSearch = core.toolBuilder().name("web-search").description(
|
|
|
682
683
|
};
|
|
683
684
|
}
|
|
684
685
|
}).build();
|
|
686
|
+
var logLevel = process.env.LOG_LEVEL?.toLowerCase() || core.LogLevel.INFO;
|
|
687
|
+
var logger = core.createLogger("tools:slack", { level: logLevel });
|
|
688
|
+
var defaultSlackClient = null;
|
|
689
|
+
function getDefaultSlackClient() {
|
|
690
|
+
if (!defaultSlackClient) {
|
|
691
|
+
const token = process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN;
|
|
692
|
+
if (!token) {
|
|
693
|
+
throw new Error(
|
|
694
|
+
"Slack token not configured. Please set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
defaultSlackClient = new webApi.WebClient(token);
|
|
698
|
+
}
|
|
699
|
+
return defaultSlackClient;
|
|
700
|
+
}
|
|
701
|
+
var sendSlackMessage = core.toolBuilder().name("send-slack-message").description("Send a message to a Slack channel for team communication and notifications").category(core.ToolCategory.WEB).tags(["slack", "messaging", "communication"]).usageNotes(
|
|
702
|
+
"Use this for general team communication. For notifications with @mentions, consider using notify-slack instead. Use get-slack-channels first if you need to find the right channel."
|
|
703
|
+
).suggests(["get-slack-channels"]).schema(
|
|
704
|
+
zod.z.object({
|
|
705
|
+
channel: zod.z.string().describe("Channel name (e.g., 'general') or ID (e.g., 'C123456')"),
|
|
706
|
+
message: zod.z.string().describe("Message content to send")
|
|
707
|
+
})
|
|
708
|
+
).implementSafe(async ({ channel, message }) => {
|
|
709
|
+
logger.info("send-slack-message called", { channel, messageLength: message.length });
|
|
710
|
+
try {
|
|
711
|
+
const slack = getDefaultSlackClient();
|
|
712
|
+
const result = await slack.chat.postMessage({
|
|
713
|
+
channel,
|
|
714
|
+
text: message,
|
|
715
|
+
username: "AgentForge Bot",
|
|
716
|
+
icon_emoji: ":robot_face:"
|
|
717
|
+
});
|
|
718
|
+
logger.info("send-slack-message result", {
|
|
719
|
+
channel: result.channel,
|
|
720
|
+
timestamp: result.ts,
|
|
721
|
+
messageLength: message.length,
|
|
722
|
+
success: true
|
|
723
|
+
});
|
|
724
|
+
return {
|
|
725
|
+
channel: result.channel,
|
|
726
|
+
message,
|
|
727
|
+
timestamp: result.ts,
|
|
728
|
+
message_id: result.ts
|
|
729
|
+
};
|
|
730
|
+
} catch (error) {
|
|
731
|
+
logger.error("send-slack-message failed", {
|
|
732
|
+
channel,
|
|
733
|
+
error: error.message,
|
|
734
|
+
data: error.data
|
|
735
|
+
});
|
|
736
|
+
throw error;
|
|
737
|
+
}
|
|
738
|
+
}).build();
|
|
739
|
+
var notifySlack = core.toolBuilder().name("notify-slack").description("Send a notification to a Slack channel with optional @mentions for urgent alerts").category(core.ToolCategory.WEB).tags(["slack", "notification", "alert"]).usageNotes(
|
|
740
|
+
"Use this for urgent notifications that require @mentions. For general messages without mentions, use send-slack-message instead."
|
|
741
|
+
).suggests(["get-slack-channels"]).schema(
|
|
742
|
+
zod.z.object({
|
|
743
|
+
channel: zod.z.string().describe("Channel name or ID"),
|
|
744
|
+
message: zod.z.string().describe("Notification message"),
|
|
745
|
+
mentions: zod.z.array(zod.z.string()).optional().describe("List of usernames to mention (without @)")
|
|
746
|
+
})
|
|
747
|
+
).implementSafe(async ({ channel, message, mentions = [] }) => {
|
|
748
|
+
logger.info("notify-slack called", {
|
|
749
|
+
channel,
|
|
750
|
+
messageLength: message.length,
|
|
751
|
+
mentionCount: mentions.length
|
|
752
|
+
});
|
|
753
|
+
const slack = getDefaultSlackClient();
|
|
754
|
+
const mentionText = mentions.length > 0 ? mentions.map((m) => `<@${m}>`).join(" ") + " " : "";
|
|
755
|
+
const fullMessage = `${mentionText}${message}`;
|
|
756
|
+
const result = await slack.chat.postMessage({
|
|
757
|
+
channel,
|
|
758
|
+
text: fullMessage,
|
|
759
|
+
username: "AgentForge Bot",
|
|
760
|
+
icon_emoji: ":robot_face:"
|
|
761
|
+
});
|
|
762
|
+
logger.info("notify-slack result", {
|
|
763
|
+
channel: result.channel,
|
|
764
|
+
timestamp: result.ts,
|
|
765
|
+
mentions: mentions.length
|
|
766
|
+
});
|
|
767
|
+
return {
|
|
768
|
+
channel: result.channel,
|
|
769
|
+
message: fullMessage,
|
|
770
|
+
mentions,
|
|
771
|
+
timestamp: result.ts,
|
|
772
|
+
notification_id: result.ts
|
|
773
|
+
};
|
|
774
|
+
}).build();
|
|
775
|
+
var getSlackChannels = core.toolBuilder().name("get-slack-channels").description("Get a list of available Slack channels to find the right channel for messaging").category(core.ToolCategory.WEB).tags(["slack", "channels", "list"]).usageNotes(
|
|
776
|
+
"Use this first to discover available channels before sending messages. Helps ensure you are sending to the correct channel."
|
|
777
|
+
).follows(["send-slack-message", "notify-slack"]).schema(
|
|
778
|
+
zod.z.object({
|
|
779
|
+
include_private: zod.z.boolean().optional().describe("Include private channels (default: false)")
|
|
780
|
+
})
|
|
781
|
+
).implementSafe(async ({ include_private = false }) => {
|
|
782
|
+
logger.info("get-slack-channels called", { include_private });
|
|
783
|
+
const slack = getDefaultSlackClient();
|
|
784
|
+
const publicChannels = await slack.conversations.list({
|
|
785
|
+
types: "public_channel",
|
|
786
|
+
exclude_archived: true
|
|
787
|
+
});
|
|
788
|
+
let allChannels = publicChannels.channels || [];
|
|
789
|
+
if (include_private) {
|
|
790
|
+
const privateChannels = await slack.conversations.list({
|
|
791
|
+
types: "private_channel",
|
|
792
|
+
exclude_archived: true
|
|
793
|
+
});
|
|
794
|
+
allChannels = [...allChannels, ...privateChannels.channels || []];
|
|
795
|
+
}
|
|
796
|
+
logger.info("get-slack-channels result", {
|
|
797
|
+
channelCount: allChannels.length,
|
|
798
|
+
includePrivate: include_private
|
|
799
|
+
});
|
|
800
|
+
return {
|
|
801
|
+
count: allChannels.length,
|
|
802
|
+
channels: allChannels.map((c) => ({
|
|
803
|
+
id: c.id,
|
|
804
|
+
name: c.name,
|
|
805
|
+
is_private: c.is_private || false,
|
|
806
|
+
num_members: c.num_members || 0
|
|
807
|
+
}))
|
|
808
|
+
};
|
|
809
|
+
}).build();
|
|
810
|
+
var getSlackMessages = core.toolBuilder().name("get-slack-messages").description("Retrieve message history from a Slack channel to read recent conversations").category(core.ToolCategory.WEB).tags(["slack", "messages", "history", "read"]).usageNotes(
|
|
811
|
+
"Use this to read recent messages from a channel. Use get-slack-channels first if you need to find the channel ID. Returns messages in reverse chronological order (newest first)."
|
|
812
|
+
).suggests(["get-slack-channels"]).schema(
|
|
813
|
+
zod.z.object({
|
|
814
|
+
channel: zod.z.string().describe("Channel name (e.g., 'general') or ID (e.g., 'C123456')"),
|
|
815
|
+
limit: zod.z.number().int().min(1).max(100).optional().describe("Number of messages to retrieve (default: 20, max: 100)")
|
|
816
|
+
})
|
|
817
|
+
).implementSafe(async ({ channel, limit = 20 }) => {
|
|
818
|
+
logger.info("get-slack-messages called", { channel, limit });
|
|
819
|
+
try {
|
|
820
|
+
const slack = getDefaultSlackClient();
|
|
821
|
+
let channelId = channel;
|
|
822
|
+
if (!channel.startsWith("C") && !channel.startsWith("D")) {
|
|
823
|
+
const channels = await slack.conversations.list({
|
|
824
|
+
types: "public_channel,private_channel",
|
|
825
|
+
exclude_archived: true
|
|
826
|
+
});
|
|
827
|
+
const found = channels.channels?.find((c) => c.name === channel);
|
|
828
|
+
if (!found) {
|
|
829
|
+
logger.error("get-slack-messages: channel not found", { channel });
|
|
830
|
+
throw new Error(
|
|
831
|
+
`Channel '${channel}' not found. Use get-slack-channels to see available channels.`
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
channelId = found.id;
|
|
835
|
+
}
|
|
836
|
+
const result = await slack.conversations.history({
|
|
837
|
+
channel: channelId,
|
|
838
|
+
limit: Math.min(limit, 100)
|
|
839
|
+
// Cap at 100 for performance
|
|
840
|
+
});
|
|
841
|
+
logger.info("get-slack-messages result", {
|
|
842
|
+
channel: channelId,
|
|
843
|
+
messageCount: result.messages?.length || 0,
|
|
844
|
+
limit
|
|
845
|
+
});
|
|
846
|
+
return {
|
|
847
|
+
channel: channelId,
|
|
848
|
+
count: result.messages?.length || 0,
|
|
849
|
+
messages: result.messages?.map((m) => ({
|
|
850
|
+
user: m.user || "unknown",
|
|
851
|
+
text: m.text || "",
|
|
852
|
+
timestamp: m.ts,
|
|
853
|
+
thread_ts: m.thread_ts,
|
|
854
|
+
type: m.type,
|
|
855
|
+
subtype: m.subtype
|
|
856
|
+
})) || []
|
|
857
|
+
};
|
|
858
|
+
} catch (error) {
|
|
859
|
+
logger.error("get-slack-messages failed", {
|
|
860
|
+
channel,
|
|
861
|
+
error: error.message,
|
|
862
|
+
data: error.data
|
|
863
|
+
});
|
|
864
|
+
throw error;
|
|
865
|
+
}
|
|
866
|
+
}).build();
|
|
867
|
+
function createSlackTools(config = {}) {
|
|
868
|
+
const {
|
|
869
|
+
token,
|
|
870
|
+
botName = "AgentForge Bot",
|
|
871
|
+
botIcon = ":robot_face:",
|
|
872
|
+
logLevel: customLogLevel
|
|
873
|
+
} = config;
|
|
874
|
+
let configuredClient = null;
|
|
875
|
+
function getConfiguredSlackClient() {
|
|
876
|
+
if (!configuredClient) {
|
|
877
|
+
const slackToken = token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN;
|
|
878
|
+
if (!slackToken) {
|
|
879
|
+
throw new Error(
|
|
880
|
+
"Slack token not configured. Please provide a token in config or set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
configuredClient = new webApi.WebClient(slackToken);
|
|
884
|
+
}
|
|
885
|
+
return configuredClient;
|
|
886
|
+
}
|
|
887
|
+
const toolLogger = customLogLevel ? core.createLogger("tools:slack", { level: customLogLevel }) : logger;
|
|
888
|
+
const sendMessage = core.toolBuilder().name("send-slack-message").description("Send a message to a Slack channel for team communication and notifications").category(core.ToolCategory.WEB).tags(["slack", "messaging", "communication"]).usageNotes(
|
|
889
|
+
"Use this for general team communication. For notifications with @mentions, consider using notify-slack instead. Use get-slack-channels first if you need to find the right channel."
|
|
890
|
+
).suggests(["get-slack-channels"]).schema(
|
|
891
|
+
zod.z.object({
|
|
892
|
+
channel: zod.z.string().describe("Channel name (e.g., 'general') or ID (e.g., 'C123456')"),
|
|
893
|
+
message: zod.z.string().describe("Message content to send")
|
|
894
|
+
})
|
|
895
|
+
).implementSafe(async ({ channel, message }) => {
|
|
896
|
+
toolLogger.info("send-slack-message called", { channel, messageLength: message.length });
|
|
897
|
+
try {
|
|
898
|
+
const slack = getConfiguredSlackClient();
|
|
899
|
+
const result = await slack.chat.postMessage({
|
|
900
|
+
channel,
|
|
901
|
+
text: message,
|
|
902
|
+
username: botName,
|
|
903
|
+
icon_emoji: botIcon
|
|
904
|
+
});
|
|
905
|
+
toolLogger.info("send-slack-message result", {
|
|
906
|
+
channel: result.channel,
|
|
907
|
+
timestamp: result.ts,
|
|
908
|
+
messageLength: message.length,
|
|
909
|
+
success: true
|
|
910
|
+
});
|
|
911
|
+
return {
|
|
912
|
+
channel: result.channel,
|
|
913
|
+
message,
|
|
914
|
+
timestamp: result.ts,
|
|
915
|
+
message_id: result.ts
|
|
916
|
+
};
|
|
917
|
+
} catch (error) {
|
|
918
|
+
toolLogger.error("send-slack-message failed", {
|
|
919
|
+
channel,
|
|
920
|
+
error: error.message,
|
|
921
|
+
data: error.data
|
|
922
|
+
});
|
|
923
|
+
throw error;
|
|
924
|
+
}
|
|
925
|
+
}).build();
|
|
926
|
+
const notify = core.toolBuilder().name("notify-slack").description("Send a notification to a Slack channel with optional @mentions for urgent alerts").category(core.ToolCategory.WEB).tags(["slack", "notification", "alert"]).usageNotes(
|
|
927
|
+
"Use this for urgent notifications that require @mentions. For general messages without mentions, use send-slack-message instead."
|
|
928
|
+
).suggests(["get-slack-channels"]).schema(
|
|
929
|
+
zod.z.object({
|
|
930
|
+
channel: zod.z.string().describe("Channel name or ID"),
|
|
931
|
+
message: zod.z.string().describe("Notification message"),
|
|
932
|
+
mentions: zod.z.array(zod.z.string()).optional().describe("List of usernames to mention (without @)")
|
|
933
|
+
})
|
|
934
|
+
).implementSafe(async ({ channel, message, mentions = [] }) => {
|
|
935
|
+
toolLogger.info("notify-slack called", {
|
|
936
|
+
channel,
|
|
937
|
+
messageLength: message.length,
|
|
938
|
+
mentionCount: mentions.length
|
|
939
|
+
});
|
|
940
|
+
const slack = getConfiguredSlackClient();
|
|
941
|
+
const mentionText = mentions.length > 0 ? mentions.map((m) => `<@${m}>`).join(" ") + " " : "";
|
|
942
|
+
const fullMessage = `${mentionText}${message}`;
|
|
943
|
+
const result = await slack.chat.postMessage({
|
|
944
|
+
channel,
|
|
945
|
+
text: fullMessage,
|
|
946
|
+
username: botName,
|
|
947
|
+
icon_emoji: botIcon
|
|
948
|
+
});
|
|
949
|
+
toolLogger.info("notify-slack result", {
|
|
950
|
+
channel: result.channel,
|
|
951
|
+
timestamp: result.ts,
|
|
952
|
+
mentions: mentions.length
|
|
953
|
+
});
|
|
954
|
+
return {
|
|
955
|
+
channel: result.channel,
|
|
956
|
+
message: fullMessage,
|
|
957
|
+
mentions,
|
|
958
|
+
timestamp: result.ts,
|
|
959
|
+
notification_id: result.ts
|
|
960
|
+
};
|
|
961
|
+
}).build();
|
|
962
|
+
const getChannels = core.toolBuilder().name("get-slack-channels").description("Get a list of available Slack channels to find the right channel for messaging").category(core.ToolCategory.WEB).tags(["slack", "channels", "list"]).usageNotes(
|
|
963
|
+
"Use this first to discover available channels before sending messages. Helps ensure you are sending to the correct channel."
|
|
964
|
+
).follows(["send-slack-message", "notify-slack"]).schema(
|
|
965
|
+
zod.z.object({
|
|
966
|
+
include_private: zod.z.boolean().optional().describe("Include private channels (default: false)")
|
|
967
|
+
})
|
|
968
|
+
).implementSafe(async ({ include_private = false }) => {
|
|
969
|
+
toolLogger.info("get-slack-channels called", { include_private });
|
|
970
|
+
const slack = getConfiguredSlackClient();
|
|
971
|
+
const publicChannels = await slack.conversations.list({
|
|
972
|
+
types: "public_channel",
|
|
973
|
+
exclude_archived: true
|
|
974
|
+
});
|
|
975
|
+
let allChannels = publicChannels.channels || [];
|
|
976
|
+
if (include_private) {
|
|
977
|
+
const privateChannels = await slack.conversations.list({
|
|
978
|
+
types: "private_channel",
|
|
979
|
+
exclude_archived: true
|
|
980
|
+
});
|
|
981
|
+
allChannels = [...allChannels, ...privateChannels.channels || []];
|
|
982
|
+
}
|
|
983
|
+
toolLogger.info("get-slack-channels result", {
|
|
984
|
+
channelCount: allChannels.length,
|
|
985
|
+
includePrivate: include_private
|
|
986
|
+
});
|
|
987
|
+
return {
|
|
988
|
+
count: allChannels.length,
|
|
989
|
+
channels: allChannels.map((c) => ({
|
|
990
|
+
id: c.id,
|
|
991
|
+
name: c.name,
|
|
992
|
+
is_private: c.is_private || false,
|
|
993
|
+
num_members: c.num_members || 0
|
|
994
|
+
}))
|
|
995
|
+
};
|
|
996
|
+
}).build();
|
|
997
|
+
const getMessages = core.toolBuilder().name("get-slack-messages").description("Retrieve message history from a Slack channel to read recent conversations").category(core.ToolCategory.WEB).tags(["slack", "messages", "history", "read"]).usageNotes(
|
|
998
|
+
"Use this to read recent messages from a channel. Use get-slack-channels first if you need to find the channel ID. Returns messages in reverse chronological order (newest first)."
|
|
999
|
+
).suggests(["get-slack-channels"]).schema(
|
|
1000
|
+
zod.z.object({
|
|
1001
|
+
channel: zod.z.string().describe("Channel name (e.g., 'general') or ID (e.g., 'C123456')"),
|
|
1002
|
+
limit: zod.z.number().int().min(1).max(100).optional().describe("Number of messages to retrieve (default: 20, max: 100)")
|
|
1003
|
+
})
|
|
1004
|
+
).implementSafe(async ({ channel, limit = 20 }) => {
|
|
1005
|
+
toolLogger.info("get-slack-messages called", { channel, limit });
|
|
1006
|
+
try {
|
|
1007
|
+
const slack = getConfiguredSlackClient();
|
|
1008
|
+
let channelId = channel;
|
|
1009
|
+
if (!channel.startsWith("C") && !channel.startsWith("D")) {
|
|
1010
|
+
const channels = await slack.conversations.list({
|
|
1011
|
+
types: "public_channel,private_channel",
|
|
1012
|
+
exclude_archived: true
|
|
1013
|
+
});
|
|
1014
|
+
const found = channels.channels?.find((c) => c.name === channel);
|
|
1015
|
+
if (!found) {
|
|
1016
|
+
toolLogger.error("get-slack-messages: channel not found", { channel });
|
|
1017
|
+
throw new Error(
|
|
1018
|
+
`Channel '${channel}' not found. Use get-slack-channels to see available channels.`
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
channelId = found.id;
|
|
1022
|
+
}
|
|
1023
|
+
const result = await slack.conversations.history({
|
|
1024
|
+
channel: channelId,
|
|
1025
|
+
limit: Math.min(limit, 100)
|
|
1026
|
+
});
|
|
1027
|
+
toolLogger.info("get-slack-messages result", {
|
|
1028
|
+
channel: channelId,
|
|
1029
|
+
messageCount: result.messages?.length || 0,
|
|
1030
|
+
limit
|
|
1031
|
+
});
|
|
1032
|
+
return {
|
|
1033
|
+
channel: channelId,
|
|
1034
|
+
count: result.messages?.length || 0,
|
|
1035
|
+
messages: result.messages?.map((m) => ({
|
|
1036
|
+
user: m.user || "unknown",
|
|
1037
|
+
text: m.text || "",
|
|
1038
|
+
timestamp: m.ts,
|
|
1039
|
+
thread_ts: m.thread_ts,
|
|
1040
|
+
type: m.type,
|
|
1041
|
+
subtype: m.subtype
|
|
1042
|
+
})) || []
|
|
1043
|
+
};
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
toolLogger.error("get-slack-messages failed", {
|
|
1046
|
+
channel,
|
|
1047
|
+
error: error.message,
|
|
1048
|
+
data: error.data
|
|
1049
|
+
});
|
|
1050
|
+
throw error;
|
|
1051
|
+
}
|
|
1052
|
+
}).build();
|
|
1053
|
+
return {
|
|
1054
|
+
sendMessage,
|
|
1055
|
+
notify,
|
|
1056
|
+
getChannels,
|
|
1057
|
+
getMessages
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
var slackTools = [sendSlackMessage, notifySlack, getSlackChannels, getSlackMessages];
|
|
685
1061
|
var jsonParser = core.toolBuilder().name("json-parser").description("Parse JSON string into an object. Validates JSON syntax and returns parsed data or error details.").category(core.ToolCategory.UTILITY).tags(["json", "parse", "data"]).schema(zod.z.object({
|
|
686
1062
|
json: zod.z.string().describe("JSON string to parse"),
|
|
687
1063
|
strict: zod.z.boolean().default(true).describe("Use strict JSON parsing (no trailing commas, etc.)")
|
|
@@ -1906,8 +2282,8 @@ var AskHumanInputSchema = zod.z.object({
|
|
|
1906
2282
|
*/
|
|
1907
2283
|
suggestions: zod.z.array(zod.z.string()).optional().describe("Suggested responses for the human")
|
|
1908
2284
|
});
|
|
1909
|
-
var
|
|
1910
|
-
var
|
|
2285
|
+
var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || core.LogLevel.INFO;
|
|
2286
|
+
var logger2 = core.createLogger("askHuman", { level: logLevel2 });
|
|
1911
2287
|
function createAskHumanTool() {
|
|
1912
2288
|
return core.toolBuilder().name("ask-human").description(
|
|
1913
2289
|
"Ask a human for input or approval. Use this when you need human guidance, approval for a critical action, or clarification on ambiguous requirements. The agent execution will pause until the human responds."
|
|
@@ -1940,13 +2316,13 @@ function createAskHumanTool() {
|
|
|
1940
2316
|
suggestions: validatedInput.suggestions,
|
|
1941
2317
|
status: "pending"
|
|
1942
2318
|
};
|
|
1943
|
-
|
|
2319
|
+
logger2.debug("About to call interrupt()", { humanRequest });
|
|
1944
2320
|
let response;
|
|
1945
2321
|
try {
|
|
1946
2322
|
response = interrupt(humanRequest);
|
|
1947
|
-
|
|
2323
|
+
logger2.debug("interrupt() returned successfully", { response, responseType: typeof response });
|
|
1948
2324
|
} catch (error) {
|
|
1949
|
-
|
|
2325
|
+
logger2.debug("interrupt() threw error (expected for GraphInterrupt)", {
|
|
1950
2326
|
errorType: error?.constructor?.name,
|
|
1951
2327
|
error: error instanceof Error ? error.message : String(error)
|
|
1952
2328
|
});
|
|
@@ -1983,6 +2359,7 @@ exports.calculator = calculator;
|
|
|
1983
2359
|
exports.createAskHumanTool = createAskHumanTool;
|
|
1984
2360
|
exports.createDuckDuckGoProvider = createDuckDuckGoProvider;
|
|
1985
2361
|
exports.createSerperProvider = createSerperProvider;
|
|
2362
|
+
exports.createSlackTools = createSlackTools;
|
|
1986
2363
|
exports.creditCardValidator = creditCardValidator;
|
|
1987
2364
|
exports.csvGenerator = csvGenerator;
|
|
1988
2365
|
exports.csvParser = csvParser;
|
|
@@ -2004,6 +2381,8 @@ exports.fileExists = fileExists;
|
|
|
2004
2381
|
exports.fileReader = fileReader;
|
|
2005
2382
|
exports.fileSearch = fileSearch;
|
|
2006
2383
|
exports.fileWriter = fileWriter;
|
|
2384
|
+
exports.getSlackChannels = getSlackChannels;
|
|
2385
|
+
exports.getSlackMessages = getSlackMessages;
|
|
2007
2386
|
exports.htmlParser = htmlParser;
|
|
2008
2387
|
exports.httpClient = httpClient;
|
|
2009
2388
|
exports.httpGet = httpGet;
|
|
@@ -2017,6 +2396,7 @@ exports.jsonToCsv = jsonToCsv;
|
|
|
2017
2396
|
exports.jsonToXml = jsonToXml;
|
|
2018
2397
|
exports.jsonValidator = jsonValidator;
|
|
2019
2398
|
exports.mathFunctions = mathFunctions;
|
|
2399
|
+
exports.notifySlack = notifySlack;
|
|
2020
2400
|
exports.objectOmit = objectOmit;
|
|
2021
2401
|
exports.objectPick = objectPick;
|
|
2022
2402
|
exports.pathBasename = pathBasename;
|
|
@@ -2030,6 +2410,8 @@ exports.pathResolve = pathResolve;
|
|
|
2030
2410
|
exports.phoneValidator = phoneValidator;
|
|
2031
2411
|
exports.randomNumber = randomNumber;
|
|
2032
2412
|
exports.searchResultSchema = searchResultSchema;
|
|
2413
|
+
exports.sendSlackMessage = sendSlackMessage;
|
|
2414
|
+
exports.slackTools = slackTools;
|
|
2033
2415
|
exports.statistics = statistics;
|
|
2034
2416
|
exports.stringCaseConverter = stringCaseConverter;
|
|
2035
2417
|
exports.stringJoin = stringJoin;
|