digital-tools 2.0.2 → 2.1.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/CHANGELOG.md +17 -0
- package/package.json +3 -4
- package/src/define.js +267 -0
- package/src/entities/advertising.js +999 -0
- package/src/entities/ai.js +756 -0
- package/src/entities/analytics.js +1588 -0
- package/src/entities/automation.js +601 -0
- package/src/entities/communication.js +1150 -0
- package/src/entities/crm.js +1386 -0
- package/src/entities/design.js +546 -0
- package/src/entities/development.js +2212 -0
- package/src/entities/document.js +874 -0
- package/src/entities/ecommerce.js +1429 -0
- package/src/entities/experiment.js +1039 -0
- package/src/entities/finance.js +3478 -0
- package/src/entities/forms.js +1892 -0
- package/src/entities/hr.js +661 -0
- package/src/entities/identity.js +997 -0
- package/src/entities/index.js +282 -0
- package/src/entities/infrastructure.js +1153 -0
- package/src/entities/knowledge.js +1438 -0
- package/src/entities/marketing.js +1610 -0
- package/src/entities/media.js +1634 -0
- package/src/entities/notification.js +1199 -0
- package/src/entities/presentation.js +1274 -0
- package/src/entities/productivity.js +1317 -0
- package/src/entities/project-management.js +1136 -0
- package/src/entities/recruiting.js +736 -0
- package/src/entities/shipping.js +509 -0
- package/src/entities/signature.js +1102 -0
- package/src/entities/site.js +222 -0
- package/src/entities/spreadsheet.js +1341 -0
- package/src/entities/storage.js +1198 -0
- package/src/entities/support.js +1166 -0
- package/src/entities/video-conferencing.js +1750 -0
- package/src/entities/video.js +950 -0
- package/src/entities.js +1663 -0
- package/src/index.js +74 -0
- package/src/providers/analytics/index.js +17 -0
- package/src/providers/analytics/mixpanel.js +255 -0
- package/src/providers/calendar/cal-com.js +303 -0
- package/src/providers/calendar/google-calendar.js +335 -0
- package/src/providers/calendar/index.js +20 -0
- package/src/providers/crm/hubspot.js +566 -0
- package/src/providers/crm/index.js +17 -0
- package/src/providers/development/github.js +472 -0
- package/src/providers/development/index.js +17 -0
- package/src/providers/ecommerce/index.js +17 -0
- package/src/providers/ecommerce/shopify.js +378 -0
- package/src/providers/email/index.js +20 -0
- package/src/providers/email/resend.js +258 -0
- package/src/providers/email/sendgrid.js +161 -0
- package/src/providers/finance/index.js +17 -0
- package/src/providers/finance/stripe.js +549 -0
- package/src/providers/forms/index.js +17 -0
- package/src/providers/forms/typeform.js +500 -0
- package/src/providers/index.js +123 -0
- package/src/providers/knowledge/index.js +17 -0
- package/src/providers/knowledge/notion.js +389 -0
- package/src/providers/marketing/index.js +17 -0
- package/src/providers/marketing/mailchimp.js +443 -0
- package/src/providers/media/cloudinary.js +318 -0
- package/src/providers/media/index.js +17 -0
- package/src/providers/messaging/index.js +20 -0
- package/src/providers/messaging/slack.js +393 -0
- package/src/providers/messaging/twilio-sms.js +249 -0
- package/src/providers/project-management/index.js +17 -0
- package/src/providers/project-management/linear.js +575 -0
- package/src/providers/registry.js +86 -0
- package/src/providers/spreadsheet/google-sheets.js +375 -0
- package/src/providers/spreadsheet/index.js +20 -0
- package/src/providers/spreadsheet/xlsx.js +423 -0
- package/src/providers/storage/index.js +24 -0
- package/src/providers/storage/s3.js +419 -0
- package/src/providers/support/index.js +17 -0
- package/src/providers/support/zendesk.js +373 -0
- package/src/providers/tasks/index.js +17 -0
- package/src/providers/tasks/todoist.js +286 -0
- package/src/providers/types.js +9 -0
- package/src/providers/video-conferencing/google-meet.js +286 -0
- package/src/providers/video-conferencing/index.js +31 -0
- package/src/providers/video-conferencing/jitsi.js +254 -0
- package/src/providers/video-conferencing/teams.js +270 -0
- package/src/providers/video-conferencing/zoom.js +332 -0
- package/src/registry.js +128 -0
- package/src/tools/communication.js +184 -0
- package/src/tools/data.js +205 -0
- package/src/tools/index.js +11 -0
- package/src/tools/web.js +137 -0
- package/src/types.js +10 -0
- package/test/define.test.js +306 -0
- package/test/registry.test.js +357 -0
- package/test/tools.test.js +363 -0
package/src/registry.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry - Registration and discovery for tools
|
|
3
|
+
*
|
|
4
|
+
* Provides a central registry for tools that can be used by
|
|
5
|
+
* both humans and AI agents.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* In-memory tool registry implementation
|
|
11
|
+
*/
|
|
12
|
+
class InMemoryToolRegistry {
|
|
13
|
+
tools = new Map();
|
|
14
|
+
register(tool) {
|
|
15
|
+
if (this.tools.has(tool.id)) {
|
|
16
|
+
console.warn(`Tool "${tool.id}" already registered, overwriting`);
|
|
17
|
+
}
|
|
18
|
+
this.tools.set(tool.id, tool);
|
|
19
|
+
}
|
|
20
|
+
unregister(id) {
|
|
21
|
+
return this.tools.delete(id);
|
|
22
|
+
}
|
|
23
|
+
get(id) {
|
|
24
|
+
return this.tools.get(id);
|
|
25
|
+
}
|
|
26
|
+
has(id) {
|
|
27
|
+
return this.tools.has(id);
|
|
28
|
+
}
|
|
29
|
+
list() {
|
|
30
|
+
return Array.from(this.tools.keys());
|
|
31
|
+
}
|
|
32
|
+
query(options) {
|
|
33
|
+
let results = Array.from(this.tools.values());
|
|
34
|
+
// Filter by category
|
|
35
|
+
if (options.category) {
|
|
36
|
+
results = results.filter((t) => t.category === options.category);
|
|
37
|
+
}
|
|
38
|
+
// Filter by subcategory
|
|
39
|
+
if (options.subcategory) {
|
|
40
|
+
results = results.filter((t) => t.subcategory === options.subcategory);
|
|
41
|
+
}
|
|
42
|
+
// Filter by tags
|
|
43
|
+
if (options.tags && options.tags.length > 0) {
|
|
44
|
+
results = results.filter((t) => t.tags && options.tags.some((tag) => t.tags.includes(tag)));
|
|
45
|
+
}
|
|
46
|
+
// Filter by audience
|
|
47
|
+
if (options.audience) {
|
|
48
|
+
results = results.filter((t) => t.audience === options.audience ||
|
|
49
|
+
t.audience === 'both' ||
|
|
50
|
+
!t.audience);
|
|
51
|
+
}
|
|
52
|
+
// Text search
|
|
53
|
+
if (options.search) {
|
|
54
|
+
const search = options.search.toLowerCase();
|
|
55
|
+
results = results.filter((t) => t.name.toLowerCase().includes(search) ||
|
|
56
|
+
t.description.toLowerCase().includes(search) ||
|
|
57
|
+
t.id.toLowerCase().includes(search));
|
|
58
|
+
}
|
|
59
|
+
// Pagination
|
|
60
|
+
const offset = options.offset ?? 0;
|
|
61
|
+
const limit = options.limit ?? results.length;
|
|
62
|
+
results = results.slice(offset, offset + limit);
|
|
63
|
+
return results;
|
|
64
|
+
}
|
|
65
|
+
byCategory(category) {
|
|
66
|
+
return this.query({ category });
|
|
67
|
+
}
|
|
68
|
+
clear() {
|
|
69
|
+
this.tools.clear();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Global tool registry instance
|
|
74
|
+
*/
|
|
75
|
+
export const registry = new InMemoryToolRegistry();
|
|
76
|
+
/**
|
|
77
|
+
* Create a new registry instance (for isolated testing or namespacing)
|
|
78
|
+
*/
|
|
79
|
+
export function createRegistry() {
|
|
80
|
+
return new InMemoryToolRegistry();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Convert a Tool to MCP format
|
|
84
|
+
*/
|
|
85
|
+
export function toMCP(tool) {
|
|
86
|
+
return {
|
|
87
|
+
name: tool.id,
|
|
88
|
+
description: tool.description,
|
|
89
|
+
inputSchema: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: Object.fromEntries(tool.parameters.map((p) => [
|
|
92
|
+
p.name,
|
|
93
|
+
typeof p.schema === 'object' && 'type' in p.schema
|
|
94
|
+
? { ...p.schema, description: p.description }
|
|
95
|
+
: { description: p.description },
|
|
96
|
+
])),
|
|
97
|
+
required: tool.parameters.filter((p) => p.required).map((p) => p.name),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Convert all registered tools to MCP format
|
|
103
|
+
*/
|
|
104
|
+
export function listMCPTools(reg = registry) {
|
|
105
|
+
return reg.list().map((id) => toMCP(reg.get(id)));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Register a tool in the global registry
|
|
109
|
+
*/
|
|
110
|
+
export function registerTool(tool) {
|
|
111
|
+
registry.register(tool);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get a tool from the global registry
|
|
115
|
+
*/
|
|
116
|
+
export function getTool(id) {
|
|
117
|
+
return registry.get(id);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Execute a tool by ID
|
|
121
|
+
*/
|
|
122
|
+
export async function executeTool(id, input) {
|
|
123
|
+
const tool = registry.get(id);
|
|
124
|
+
if (!tool) {
|
|
125
|
+
throw new Error(`Tool "${id}" not found`);
|
|
126
|
+
}
|
|
127
|
+
return tool.handler(input);
|
|
128
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Communication Tools - Email, messaging, notifications
|
|
3
|
+
*
|
|
4
|
+
* These tools define the interface for communication.
|
|
5
|
+
* Actual implementations would integrate with email services,
|
|
6
|
+
* Slack, etc. in production.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { defineTool } from '../define.js';
|
|
11
|
+
/**
|
|
12
|
+
* Send an email
|
|
13
|
+
*/
|
|
14
|
+
export const sendEmail = defineTool({
|
|
15
|
+
id: 'communication.email.send',
|
|
16
|
+
name: 'Send Email',
|
|
17
|
+
description: 'Send an email to one or more recipients',
|
|
18
|
+
category: 'communication',
|
|
19
|
+
subcategory: 'email',
|
|
20
|
+
input: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
to: { type: 'array', items: { type: 'string' }, description: 'Recipient email addresses' },
|
|
24
|
+
cc: { type: 'array', items: { type: 'string' }, description: 'CC recipients' },
|
|
25
|
+
bcc: { type: 'array', items: { type: 'string' }, description: 'BCC recipients' },
|
|
26
|
+
subject: { type: 'string', description: 'Email subject' },
|
|
27
|
+
body: { type: 'string', description: 'Plain text body' },
|
|
28
|
+
html: { type: 'string', description: 'HTML body (optional)' },
|
|
29
|
+
attachments: {
|
|
30
|
+
type: 'array',
|
|
31
|
+
items: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
filename: { type: 'string' },
|
|
35
|
+
content: { type: 'string' },
|
|
36
|
+
contentType: { type: 'string' },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
description: 'File attachments',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
required: ['to', 'subject', 'body'],
|
|
43
|
+
},
|
|
44
|
+
handler: async (input) => {
|
|
45
|
+
// In production, this would integrate with an email service
|
|
46
|
+
// (SendGrid, SES, Postmark, etc.)
|
|
47
|
+
console.log('[Email] Sending to:', input.to.join(', '));
|
|
48
|
+
console.log('[Email] Subject:', input.subject);
|
|
49
|
+
// Simulate sending
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
messageId: `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
options: {
|
|
56
|
+
audience: 'both',
|
|
57
|
+
tags: ['email', 'send', 'notify'],
|
|
58
|
+
requiresConfirmation: true,
|
|
59
|
+
permissions: [{ type: 'execute', resource: 'email' }],
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Send a Slack message
|
|
64
|
+
*/
|
|
65
|
+
export const sendSlackMessage = defineTool({
|
|
66
|
+
id: 'communication.slack.send',
|
|
67
|
+
name: 'Send Slack Message',
|
|
68
|
+
description: 'Send a message to a Slack channel or thread',
|
|
69
|
+
category: 'communication',
|
|
70
|
+
subcategory: 'slack',
|
|
71
|
+
input: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
channel: { type: 'string', description: 'Channel ID or name (e.g., #general)' },
|
|
75
|
+
text: { type: 'string', description: 'Message text' },
|
|
76
|
+
blocks: { type: 'array', description: 'Slack Block Kit blocks' },
|
|
77
|
+
threadTs: { type: 'string', description: 'Thread timestamp for replies' },
|
|
78
|
+
unfurlLinks: { type: 'boolean', description: 'Unfurl URLs in the message' },
|
|
79
|
+
},
|
|
80
|
+
required: ['channel', 'text'],
|
|
81
|
+
},
|
|
82
|
+
handler: async (input) => {
|
|
83
|
+
// In production, this would integrate with Slack API
|
|
84
|
+
console.log('[Slack] Sending to:', input.channel);
|
|
85
|
+
console.log('[Slack] Message:', input.text);
|
|
86
|
+
return {
|
|
87
|
+
success: true,
|
|
88
|
+
ts: `${Date.now()}.000001`,
|
|
89
|
+
channel: input.channel,
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
options: {
|
|
93
|
+
audience: 'both',
|
|
94
|
+
tags: ['slack', 'message', 'chat'],
|
|
95
|
+
permissions: [{ type: 'execute', resource: 'slack' }],
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* Send a notification
|
|
100
|
+
*/
|
|
101
|
+
export const sendNotification = defineTool({
|
|
102
|
+
id: 'communication.notify',
|
|
103
|
+
name: 'Send Notification',
|
|
104
|
+
description: 'Send a notification through various channels',
|
|
105
|
+
category: 'communication',
|
|
106
|
+
subcategory: 'notification',
|
|
107
|
+
input: {
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: {
|
|
110
|
+
channel: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
enum: ['email', 'slack', 'sms', 'push', 'webhook'],
|
|
113
|
+
description: 'Notification channel',
|
|
114
|
+
},
|
|
115
|
+
recipients: { type: 'array', items: { type: 'string' }, description: 'Recipients' },
|
|
116
|
+
title: { type: 'string', description: 'Notification title' },
|
|
117
|
+
message: { type: 'string', description: 'Notification message' },
|
|
118
|
+
priority: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
enum: ['low', 'normal', 'high', 'urgent'],
|
|
121
|
+
description: 'Priority level',
|
|
122
|
+
},
|
|
123
|
+
data: { type: 'object', description: 'Additional data' },
|
|
124
|
+
},
|
|
125
|
+
required: ['channel', 'recipients', 'title', 'message'],
|
|
126
|
+
},
|
|
127
|
+
handler: async (input) => {
|
|
128
|
+
console.log(`[Notification] [${input.channel}] ${input.title}`);
|
|
129
|
+
console.log(`[Notification] Recipients:`, input.recipients);
|
|
130
|
+
console.log(`[Notification] Priority:`, input.priority || 'normal');
|
|
131
|
+
return {
|
|
132
|
+
success: true,
|
|
133
|
+
notificationId: `notif_${Date.now()}`,
|
|
134
|
+
delivered: input.recipients,
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
options: {
|
|
138
|
+
audience: 'both',
|
|
139
|
+
tags: ['notify', 'alert', 'message'],
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
/**
|
|
143
|
+
* Send an SMS
|
|
144
|
+
*/
|
|
145
|
+
export const sendSms = defineTool({
|
|
146
|
+
id: 'communication.sms.send',
|
|
147
|
+
name: 'Send SMS',
|
|
148
|
+
description: 'Send an SMS text message',
|
|
149
|
+
category: 'communication',
|
|
150
|
+
subcategory: 'sms',
|
|
151
|
+
input: {
|
|
152
|
+
type: 'object',
|
|
153
|
+
properties: {
|
|
154
|
+
to: { type: 'string', description: 'Phone number (E.164 format)' },
|
|
155
|
+
message: { type: 'string', description: 'SMS message (max 160 chars recommended)' },
|
|
156
|
+
from: { type: 'string', description: 'Sender phone number or ID' },
|
|
157
|
+
},
|
|
158
|
+
required: ['to', 'message'],
|
|
159
|
+
},
|
|
160
|
+
handler: async (input) => {
|
|
161
|
+
// In production, this would integrate with Twilio, etc.
|
|
162
|
+
console.log('[SMS] Sending to:', input.to);
|
|
163
|
+
console.log('[SMS] Message:', input.message.slice(0, 160));
|
|
164
|
+
return {
|
|
165
|
+
success: true,
|
|
166
|
+
messageId: `sms_${Date.now()}`,
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
options: {
|
|
170
|
+
audience: 'both',
|
|
171
|
+
tags: ['sms', 'text', 'mobile'],
|
|
172
|
+
requiresConfirmation: true,
|
|
173
|
+
permissions: [{ type: 'execute', resource: 'sms' }],
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
/**
|
|
177
|
+
* All communication tools
|
|
178
|
+
*/
|
|
179
|
+
export const communicationTools = [
|
|
180
|
+
sendEmail,
|
|
181
|
+
sendSlackMessage,
|
|
182
|
+
sendNotification,
|
|
183
|
+
sendSms,
|
|
184
|
+
];
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data Tools - Data manipulation, transformation, validation
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import { defineTool } from '../define.js';
|
|
7
|
+
/**
|
|
8
|
+
* Parse JSON string
|
|
9
|
+
*/
|
|
10
|
+
export const parseJson = defineTool({
|
|
11
|
+
id: 'data.json.parse',
|
|
12
|
+
name: 'Parse JSON',
|
|
13
|
+
description: 'Parse a JSON string into an object',
|
|
14
|
+
category: 'data',
|
|
15
|
+
subcategory: 'transform',
|
|
16
|
+
input: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
text: { type: 'string', description: 'JSON string to parse' },
|
|
20
|
+
},
|
|
21
|
+
required: ['text'],
|
|
22
|
+
},
|
|
23
|
+
handler: async (input) => {
|
|
24
|
+
try {
|
|
25
|
+
const data = JSON.parse(input.text);
|
|
26
|
+
return { data, valid: true };
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
return {
|
|
30
|
+
data: null,
|
|
31
|
+
valid: false,
|
|
32
|
+
error: e instanceof Error ? e.message : 'Invalid JSON',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
options: {
|
|
37
|
+
audience: 'both',
|
|
38
|
+
tags: ['json', 'parse', 'transform'],
|
|
39
|
+
idempotent: true,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Stringify object to JSON
|
|
44
|
+
*/
|
|
45
|
+
export const stringifyJson = defineTool({
|
|
46
|
+
id: 'data.json.stringify',
|
|
47
|
+
name: 'Stringify JSON',
|
|
48
|
+
description: 'Convert an object to a JSON string',
|
|
49
|
+
category: 'data',
|
|
50
|
+
subcategory: 'transform',
|
|
51
|
+
input: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
data: { description: 'Data to stringify' },
|
|
55
|
+
pretty: { type: 'boolean', description: 'Pretty print with indentation' },
|
|
56
|
+
},
|
|
57
|
+
required: ['data'],
|
|
58
|
+
},
|
|
59
|
+
handler: async (input) => {
|
|
60
|
+
const text = input.pretty
|
|
61
|
+
? JSON.stringify(input.data, null, 2)
|
|
62
|
+
: JSON.stringify(input.data);
|
|
63
|
+
return { text };
|
|
64
|
+
},
|
|
65
|
+
options: {
|
|
66
|
+
audience: 'both',
|
|
67
|
+
tags: ['json', 'stringify', 'transform'],
|
|
68
|
+
idempotent: true,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* Parse CSV to array of objects
|
|
73
|
+
*/
|
|
74
|
+
export const parseCsv = defineTool({
|
|
75
|
+
id: 'data.csv.parse',
|
|
76
|
+
name: 'Parse CSV',
|
|
77
|
+
description: 'Parse CSV text into an array of objects',
|
|
78
|
+
category: 'data',
|
|
79
|
+
subcategory: 'transform',
|
|
80
|
+
input: {
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {
|
|
83
|
+
text: { type: 'string', description: 'CSV text to parse' },
|
|
84
|
+
delimiter: { type: 'string', description: 'Column delimiter (default: comma)' },
|
|
85
|
+
hasHeaders: { type: 'boolean', description: 'First row is headers (default: true)' },
|
|
86
|
+
},
|
|
87
|
+
required: ['text'],
|
|
88
|
+
},
|
|
89
|
+
handler: async (input) => {
|
|
90
|
+
const delimiter = input.delimiter || ',';
|
|
91
|
+
const hasHeaders = input.hasHeaders !== false;
|
|
92
|
+
const lines = input.text.split('\n').filter((line) => line.trim());
|
|
93
|
+
if (lines.length === 0) {
|
|
94
|
+
return { rows: [], headers: [], rowCount: 0 };
|
|
95
|
+
}
|
|
96
|
+
const headers = hasHeaders
|
|
97
|
+
? lines[0].split(delimiter).map((h) => h.trim())
|
|
98
|
+
: lines[0].split(delimiter).map((_, i) => `column${i + 1}`);
|
|
99
|
+
const dataLines = hasHeaders ? lines.slice(1) : lines;
|
|
100
|
+
const rows = dataLines.map((line) => {
|
|
101
|
+
const values = line.split(delimiter).map((v) => v.trim());
|
|
102
|
+
const row = {};
|
|
103
|
+
headers.forEach((header, i) => {
|
|
104
|
+
row[header] = values[i] || '';
|
|
105
|
+
});
|
|
106
|
+
return row;
|
|
107
|
+
});
|
|
108
|
+
return { rows, headers, rowCount: rows.length };
|
|
109
|
+
},
|
|
110
|
+
options: {
|
|
111
|
+
audience: 'both',
|
|
112
|
+
tags: ['csv', 'parse', 'transform'],
|
|
113
|
+
idempotent: true,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
/**
|
|
117
|
+
* Transform data using JSONPath-like expressions
|
|
118
|
+
*/
|
|
119
|
+
export const transformData = defineTool({
|
|
120
|
+
id: 'data.transform',
|
|
121
|
+
name: 'Transform Data',
|
|
122
|
+
description: 'Transform data by mapping fields to new structure',
|
|
123
|
+
category: 'data',
|
|
124
|
+
subcategory: 'transform',
|
|
125
|
+
input: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: {
|
|
128
|
+
data: { description: 'Source data to transform' },
|
|
129
|
+
transform: {
|
|
130
|
+
type: 'object',
|
|
131
|
+
description: 'Mapping of output fields to input paths (e.g., { "name": "user.firstName" })',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
required: ['data', 'transform'],
|
|
135
|
+
},
|
|
136
|
+
handler: async (input) => {
|
|
137
|
+
const result = {};
|
|
138
|
+
for (const [outputKey, inputPath] of Object.entries(input.transform)) {
|
|
139
|
+
const pathParts = inputPath.split('.');
|
|
140
|
+
let value = input.data;
|
|
141
|
+
for (const part of pathParts) {
|
|
142
|
+
if (value && typeof value === 'object' && part in value) {
|
|
143
|
+
value = value[part];
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
value = undefined;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
result[outputKey] = value;
|
|
151
|
+
}
|
|
152
|
+
return { result };
|
|
153
|
+
},
|
|
154
|
+
options: {
|
|
155
|
+
audience: 'both',
|
|
156
|
+
tags: ['transform', 'map', 'extract'],
|
|
157
|
+
idempotent: true,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
/**
|
|
161
|
+
* Filter array of objects
|
|
162
|
+
*/
|
|
163
|
+
export const filterData = defineTool({
|
|
164
|
+
id: 'data.filter',
|
|
165
|
+
name: 'Filter Data',
|
|
166
|
+
description: 'Filter an array of objects by field values',
|
|
167
|
+
category: 'data',
|
|
168
|
+
subcategory: 'transform',
|
|
169
|
+
input: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
data: { type: 'array', description: 'Array of objects to filter' },
|
|
173
|
+
filter: { type: 'object', description: 'Filter criteria (e.g., { "status": "active" })' },
|
|
174
|
+
},
|
|
175
|
+
required: ['data', 'filter'],
|
|
176
|
+
},
|
|
177
|
+
handler: async (input) => {
|
|
178
|
+
const results = input.data.filter((item) => {
|
|
179
|
+
if (typeof item !== 'object' || item === null)
|
|
180
|
+
return false;
|
|
181
|
+
for (const [key, value] of Object.entries(input.filter)) {
|
|
182
|
+
if (item[key] !== value) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
});
|
|
188
|
+
return { results, count: results.length };
|
|
189
|
+
},
|
|
190
|
+
options: {
|
|
191
|
+
audience: 'both',
|
|
192
|
+
tags: ['filter', 'query', 'search'],
|
|
193
|
+
idempotent: true,
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
/**
|
|
197
|
+
* All data tools
|
|
198
|
+
*/
|
|
199
|
+
export const dataTools = [
|
|
200
|
+
parseJson,
|
|
201
|
+
stringifyJson,
|
|
202
|
+
parseCsv,
|
|
203
|
+
transformData,
|
|
204
|
+
filterData,
|
|
205
|
+
];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common tool implementations
|
|
3
|
+
*
|
|
4
|
+
* Pre-built tools for common operations that can be used
|
|
5
|
+
* out of the box by both humans and AI agents.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export * from './web.js';
|
|
10
|
+
export * from './data.js';
|
|
11
|
+
export * from './communication.js';
|
package/src/tools/web.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Tools - HTTP, scraping, browser automation
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import { defineTool } from '../define.js';
|
|
7
|
+
/**
|
|
8
|
+
* Fetch content from a URL
|
|
9
|
+
*/
|
|
10
|
+
export const fetchUrl = defineTool({
|
|
11
|
+
id: 'web.fetch',
|
|
12
|
+
name: 'Fetch URL',
|
|
13
|
+
description: 'Fetch content from a URL using HTTP',
|
|
14
|
+
category: 'web',
|
|
15
|
+
subcategory: 'fetch',
|
|
16
|
+
input: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
url: { type: 'string', description: 'URL to fetch' },
|
|
20
|
+
method: { type: 'string', description: 'HTTP method (default: GET)', enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] },
|
|
21
|
+
headers: { type: 'object', description: 'Request headers' },
|
|
22
|
+
body: { type: 'string', description: 'Request body (for POST/PUT/PATCH)' },
|
|
23
|
+
},
|
|
24
|
+
required: ['url'],
|
|
25
|
+
},
|
|
26
|
+
handler: async (input) => {
|
|
27
|
+
const response = await fetch(input.url, {
|
|
28
|
+
method: input.method || 'GET',
|
|
29
|
+
headers: input.headers,
|
|
30
|
+
body: input.body,
|
|
31
|
+
});
|
|
32
|
+
const headers = {};
|
|
33
|
+
response.headers.forEach((value, key) => {
|
|
34
|
+
headers[key] = value;
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
status: response.status,
|
|
38
|
+
headers,
|
|
39
|
+
body: await response.text(),
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
options: {
|
|
43
|
+
audience: 'both',
|
|
44
|
+
tags: ['http', 'network', 'api'],
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Parse HTML and extract content
|
|
49
|
+
*/
|
|
50
|
+
export const parseHtml = defineTool({
|
|
51
|
+
id: 'web.parse-html',
|
|
52
|
+
name: 'Parse HTML',
|
|
53
|
+
description: 'Parse HTML content and extract text, links, and images',
|
|
54
|
+
category: 'web',
|
|
55
|
+
subcategory: 'scrape',
|
|
56
|
+
input: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
html: { type: 'string', description: 'HTML content to parse' },
|
|
60
|
+
selector: { type: 'string', description: 'CSS selector to filter content (optional)' },
|
|
61
|
+
},
|
|
62
|
+
required: ['html'],
|
|
63
|
+
},
|
|
64
|
+
handler: async (input) => {
|
|
65
|
+
// Basic HTML parsing without DOM (would use cheerio or jsdom in production)
|
|
66
|
+
const text = input.html.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
67
|
+
// Extract links
|
|
68
|
+
const linkRegex = /href="([^"]+)"/g;
|
|
69
|
+
const links = [];
|
|
70
|
+
let match;
|
|
71
|
+
while ((match = linkRegex.exec(input.html)) !== null) {
|
|
72
|
+
links.push(match[1]);
|
|
73
|
+
}
|
|
74
|
+
// Extract images
|
|
75
|
+
const imgRegex = /src="([^"]+)"/g;
|
|
76
|
+
const images = [];
|
|
77
|
+
while ((match = imgRegex.exec(input.html)) !== null) {
|
|
78
|
+
if (match[1].match(/\.(jpg|jpeg|png|gif|webp|svg)/i)) {
|
|
79
|
+
images.push(match[1]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { text, links, images };
|
|
83
|
+
},
|
|
84
|
+
options: {
|
|
85
|
+
audience: 'both',
|
|
86
|
+
tags: ['html', 'parse', 'extract'],
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
/**
|
|
90
|
+
* Read content from a URL (combines fetch + parse)
|
|
91
|
+
*/
|
|
92
|
+
export const readUrl = defineTool({
|
|
93
|
+
id: 'web.read',
|
|
94
|
+
name: 'Read URL',
|
|
95
|
+
description: 'Read and extract content from a webpage',
|
|
96
|
+
category: 'web',
|
|
97
|
+
subcategory: 'scrape',
|
|
98
|
+
input: {
|
|
99
|
+
type: 'object',
|
|
100
|
+
properties: {
|
|
101
|
+
url: { type: 'string', description: 'URL to read' },
|
|
102
|
+
},
|
|
103
|
+
required: ['url'],
|
|
104
|
+
},
|
|
105
|
+
handler: async (input) => {
|
|
106
|
+
const response = await fetch(input.url);
|
|
107
|
+
const html = await response.text();
|
|
108
|
+
// Extract title
|
|
109
|
+
const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/i);
|
|
110
|
+
const title = titleMatch ? titleMatch[1].trim() : '';
|
|
111
|
+
// Extract body text
|
|
112
|
+
const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
|
|
113
|
+
const body = bodyMatch ? bodyMatch[1] : html;
|
|
114
|
+
const text = body.replace(/<script[\s\S]*?<\/script>/gi, '')
|
|
115
|
+
.replace(/<style[\s\S]*?<\/style>/gi, '')
|
|
116
|
+
.replace(/<[^>]*>/g, ' ')
|
|
117
|
+
.replace(/\s+/g, ' ')
|
|
118
|
+
.trim();
|
|
119
|
+
// Extract links
|
|
120
|
+
const linkRegex = /href="(https?:\/\/[^"]+)"/g;
|
|
121
|
+
const links = [];
|
|
122
|
+
let match;
|
|
123
|
+
while ((match = linkRegex.exec(html)) !== null) {
|
|
124
|
+
links.push(match[1]);
|
|
125
|
+
}
|
|
126
|
+
return { title, text: text.slice(0, 10000), links: [...new Set(links)] };
|
|
127
|
+
},
|
|
128
|
+
options: {
|
|
129
|
+
audience: 'both',
|
|
130
|
+
tags: ['read', 'scrape', 'extract'],
|
|
131
|
+
idempotent: true,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* All web tools
|
|
136
|
+
*/
|
|
137
|
+
export const webTools = [fetchUrl, parseHtml, readUrl];
|
package/src/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for digital-tools
|
|
3
|
+
*
|
|
4
|
+
* Core types for tools that can be used by both humans and AI agents.
|
|
5
|
+
* This package provides the foundational tool primitives used across
|
|
6
|
+
* autonomous-agents, human-in-the-loop, and services-as-software.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
export {};
|