erosolar-cli 1.4.7 → 1.5.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/dist/capabilities/emailCapability.d.ts +12 -0
- package/dist/capabilities/emailCapability.d.ts.map +1 -0
- package/dist/capabilities/emailCapability.js +22 -0
- package/dist/capabilities/emailCapability.js.map +1 -0
- package/dist/capabilities/index.d.ts +2 -0
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +2 -0
- package/dist/capabilities/index.js.map +1 -1
- package/dist/plugins/tools/email/emailPlugin.d.ts +3 -0
- package/dist/plugins/tools/email/emailPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/email/emailPlugin.js +12 -0
- package/dist/plugins/tools/email/emailPlugin.js.map +1 -0
- package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
- package/dist/plugins/tools/nodeDefaults.js +2 -0
- package/dist/plugins/tools/nodeDefaults.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +6 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +44 -0
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/tools/emailTools.d.ts +21 -0
- package/dist/tools/emailTools.d.ts.map +1 -0
- package/dist/tools/emailTools.js +445 -0
- package/dist/tools/emailTools.js.map +1 -0
- package/dist/tools/webTools.d.ts.map +1 -1
- package/dist/tools/webTools.js +140 -2
- package/dist/tools/webTools.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email Tools - SMTP email sending capabilities
|
|
3
|
+
*
|
|
4
|
+
* Supports Gmail, Outlook, and custom SMTP servers with app password authentication.
|
|
5
|
+
* Users configure their email credentials via /secrets or environment variables.
|
|
6
|
+
*/
|
|
7
|
+
import * as nodemailer from 'nodemailer';
|
|
8
|
+
// SMTP provider presets
|
|
9
|
+
const SMTP_PRESETS = {
|
|
10
|
+
gmail: {
|
|
11
|
+
host: 'smtp.gmail.com',
|
|
12
|
+
port: 587,
|
|
13
|
+
secure: false, // Uses STARTTLS
|
|
14
|
+
},
|
|
15
|
+
outlook: {
|
|
16
|
+
host: 'smtp.office365.com',
|
|
17
|
+
port: 587,
|
|
18
|
+
secure: false,
|
|
19
|
+
},
|
|
20
|
+
hotmail: {
|
|
21
|
+
host: 'smtp.office365.com',
|
|
22
|
+
port: 587,
|
|
23
|
+
secure: false,
|
|
24
|
+
},
|
|
25
|
+
yahoo: {
|
|
26
|
+
host: 'smtp.mail.yahoo.com',
|
|
27
|
+
port: 587,
|
|
28
|
+
secure: false,
|
|
29
|
+
},
|
|
30
|
+
icloud: {
|
|
31
|
+
host: 'smtp.mail.me.com',
|
|
32
|
+
port: 587,
|
|
33
|
+
secure: false,
|
|
34
|
+
},
|
|
35
|
+
zoho: {
|
|
36
|
+
host: 'smtp.zoho.com',
|
|
37
|
+
port: 587,
|
|
38
|
+
secure: false,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
function getEmailConfig() {
|
|
42
|
+
// Check for provider-specific config first
|
|
43
|
+
const provider = (process.env['SMTP_PROVIDER'] || 'gmail').toLowerCase();
|
|
44
|
+
const user = process.env['SMTP_USER'] || process.env['EMAIL_USER'];
|
|
45
|
+
const password = process.env['SMTP_PASSWORD'] || process.env['EMAIL_APP_PASSWORD'] || process.env['SMTP_APP_PASSWORD'];
|
|
46
|
+
if (!user || !password) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
// Get preset or custom config
|
|
50
|
+
const preset = SMTP_PRESETS[provider];
|
|
51
|
+
return {
|
|
52
|
+
provider,
|
|
53
|
+
host: process.env['SMTP_HOST'] || preset?.host || 'smtp.gmail.com',
|
|
54
|
+
port: parseInt(process.env['SMTP_PORT'] || String(preset?.port || 587), 10),
|
|
55
|
+
secure: process.env['SMTP_SECURE'] === 'true' || preset?.secure || false,
|
|
56
|
+
user,
|
|
57
|
+
password,
|
|
58
|
+
fromName: process.env['SMTP_FROM_NAME'] || process.env['EMAIL_FROM_NAME'],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function createTransporter(config) {
|
|
62
|
+
const transporter = nodemailer.createTransport({
|
|
63
|
+
host: config.host,
|
|
64
|
+
port: config.port,
|
|
65
|
+
secure: config.secure,
|
|
66
|
+
auth: {
|
|
67
|
+
user: config.user,
|
|
68
|
+
pass: config.password,
|
|
69
|
+
},
|
|
70
|
+
tls: {
|
|
71
|
+
// Allow self-signed certificates for custom SMTP servers
|
|
72
|
+
rejectUnauthorized: process.env['SMTP_REJECT_UNAUTHORIZED'] !== 'false',
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
// Verify connection
|
|
76
|
+
await transporter.verify();
|
|
77
|
+
return transporter;
|
|
78
|
+
}
|
|
79
|
+
export function createEmailTools() {
|
|
80
|
+
return [
|
|
81
|
+
{
|
|
82
|
+
name: 'send_email',
|
|
83
|
+
description: `Send an email via SMTP. Supports Gmail, Outlook, Yahoo, iCloud, Zoho, and custom SMTP servers.
|
|
84
|
+
|
|
85
|
+
Configuration (set via /secrets or environment variables):
|
|
86
|
+
- SMTP_USER or EMAIL_USER: Your email address
|
|
87
|
+
- SMTP_PASSWORD or EMAIL_APP_PASSWORD: Your app password (NOT your regular password)
|
|
88
|
+
- SMTP_PROVIDER: gmail, outlook, yahoo, icloud, zoho (default: gmail)
|
|
89
|
+
- SMTP_FROM_NAME: Display name for sent emails (optional)
|
|
90
|
+
|
|
91
|
+
For Gmail:
|
|
92
|
+
1. Enable 2-Factor Authentication
|
|
93
|
+
2. Go to https://myaccount.google.com/apppasswords
|
|
94
|
+
3. Generate an app password for "Mail"
|
|
95
|
+
4. Use that app password as SMTP_PASSWORD
|
|
96
|
+
|
|
97
|
+
For Outlook/Hotmail:
|
|
98
|
+
1. Go to https://account.live.com/proofs/AppPassword
|
|
99
|
+
2. Generate an app password
|
|
100
|
+
3. Use that as SMTP_PASSWORD
|
|
101
|
+
|
|
102
|
+
Use cases:
|
|
103
|
+
- Send notifications, reports, or alerts
|
|
104
|
+
- Automated outreach (investors, leads, contacts)
|
|
105
|
+
- Send formatted HTML emails with attachments
|
|
106
|
+
- Batch email campaigns with personalization`,
|
|
107
|
+
parameters: {
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: {
|
|
110
|
+
to: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
description: 'Recipient email address(es). For multiple recipients, use comma-separated values.',
|
|
113
|
+
},
|
|
114
|
+
subject: {
|
|
115
|
+
type: 'string',
|
|
116
|
+
description: 'Email subject line',
|
|
117
|
+
},
|
|
118
|
+
body: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
description: 'Email body content. Can be plain text or HTML.',
|
|
121
|
+
},
|
|
122
|
+
html: {
|
|
123
|
+
type: 'boolean',
|
|
124
|
+
description: 'Set to true if body contains HTML content (default: false)',
|
|
125
|
+
},
|
|
126
|
+
cc: {
|
|
127
|
+
type: 'string',
|
|
128
|
+
description: 'CC recipient(s), comma-separated (optional)',
|
|
129
|
+
},
|
|
130
|
+
bcc: {
|
|
131
|
+
type: 'string',
|
|
132
|
+
description: 'BCC recipient(s), comma-separated (optional)',
|
|
133
|
+
},
|
|
134
|
+
reply_to: {
|
|
135
|
+
type: 'string',
|
|
136
|
+
description: 'Reply-To address (optional)',
|
|
137
|
+
},
|
|
138
|
+
attachments: {
|
|
139
|
+
type: 'array',
|
|
140
|
+
items: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
properties: {
|
|
143
|
+
filename: { type: 'string' },
|
|
144
|
+
path: { type: 'string', description: 'File path to attach' },
|
|
145
|
+
content: { type: 'string', description: 'Base64 encoded content (alternative to path)' },
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
description: 'Array of attachments (optional)',
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
required: ['to', 'subject', 'body'],
|
|
152
|
+
},
|
|
153
|
+
handler: async (args) => {
|
|
154
|
+
const config = getEmailConfig();
|
|
155
|
+
if (!config) {
|
|
156
|
+
return `Email not configured. Please set up SMTP credentials:
|
|
157
|
+
|
|
158
|
+
Required environment variables:
|
|
159
|
+
- SMTP_USER or EMAIL_USER: Your email address
|
|
160
|
+
- SMTP_PASSWORD or EMAIL_APP_PASSWORD: Your app password
|
|
161
|
+
|
|
162
|
+
Optional:
|
|
163
|
+
- SMTP_PROVIDER: gmail, outlook, yahoo, icloud, zoho (default: gmail)
|
|
164
|
+
- SMTP_FROM_NAME: Display name for sent emails
|
|
165
|
+
|
|
166
|
+
For Gmail, create an app password at: https://myaccount.google.com/apppasswords
|
|
167
|
+
For Outlook, create an app password at: https://account.live.com/proofs/AppPassword
|
|
168
|
+
|
|
169
|
+
Use /secrets to configure these values.`;
|
|
170
|
+
}
|
|
171
|
+
const to = args['to'];
|
|
172
|
+
const subject = args['subject'];
|
|
173
|
+
const body = args['body'];
|
|
174
|
+
const isHtml = args['html'] === true;
|
|
175
|
+
const cc = args['cc'];
|
|
176
|
+
const bcc = args['bcc'];
|
|
177
|
+
const replyTo = args['reply_to'];
|
|
178
|
+
const attachments = args['attachments'];
|
|
179
|
+
if (!to || !subject || !body) {
|
|
180
|
+
return 'Error: to, subject, and body are required parameters.';
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const transporter = await createTransporter(config);
|
|
184
|
+
const fromAddress = config.fromName
|
|
185
|
+
? `"${config.fromName}" <${config.user}>`
|
|
186
|
+
: config.user;
|
|
187
|
+
const mailOptions = {
|
|
188
|
+
from: fromAddress,
|
|
189
|
+
to,
|
|
190
|
+
subject,
|
|
191
|
+
...(isHtml ? { html: body } : { text: body }),
|
|
192
|
+
...(cc && { cc }),
|
|
193
|
+
...(bcc && { bcc }),
|
|
194
|
+
...(replyTo && { replyTo }),
|
|
195
|
+
...(attachments && {
|
|
196
|
+
attachments: attachments.map(att => ({
|
|
197
|
+
filename: att.filename,
|
|
198
|
+
...(att.path ? { path: att.path } : {}),
|
|
199
|
+
...(att.content ? { content: att.content, encoding: 'base64' } : {}),
|
|
200
|
+
})),
|
|
201
|
+
}),
|
|
202
|
+
};
|
|
203
|
+
const info = await transporter.sendMail(mailOptions);
|
|
204
|
+
return `✅ Email sent successfully!
|
|
205
|
+
|
|
206
|
+
To: ${to}
|
|
207
|
+
Subject: ${subject}
|
|
208
|
+
Message ID: ${info.messageId}
|
|
209
|
+
Provider: ${config.provider}
|
|
210
|
+
${cc ? `CC: ${cc}` : ''}
|
|
211
|
+
${bcc ? `BCC: ${bcc}` : ''}
|
|
212
|
+
${attachments?.length ? `Attachments: ${attachments.length} file(s)` : ''}
|
|
213
|
+
|
|
214
|
+
Response: ${info.response || 'Accepted'}`;
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
218
|
+
// Provide helpful error messages
|
|
219
|
+
if (errorMessage.includes('Invalid login') || errorMessage.includes('authentication')) {
|
|
220
|
+
return `❌ Authentication failed.
|
|
221
|
+
|
|
222
|
+
Error: ${errorMessage}
|
|
223
|
+
|
|
224
|
+
Common fixes:
|
|
225
|
+
1. Make sure you're using an APP PASSWORD, not your regular password
|
|
226
|
+
2. For Gmail: https://myaccount.google.com/apppasswords
|
|
227
|
+
3. For Outlook: https://account.live.com/proofs/AppPassword
|
|
228
|
+
4. Ensure 2-Factor Authentication is enabled on your account
|
|
229
|
+
5. Check that SMTP_USER matches the email account`;
|
|
230
|
+
}
|
|
231
|
+
if (errorMessage.includes('ENOTFOUND') || errorMessage.includes('ECONNREFUSED')) {
|
|
232
|
+
return `❌ Could not connect to SMTP server.
|
|
233
|
+
|
|
234
|
+
Error: ${errorMessage}
|
|
235
|
+
|
|
236
|
+
Current config:
|
|
237
|
+
- Host: ${config.host}
|
|
238
|
+
- Port: ${config.port}
|
|
239
|
+
- Provider: ${config.provider}
|
|
240
|
+
|
|
241
|
+
Try setting SMTP_HOST and SMTP_PORT manually if using a custom server.`;
|
|
242
|
+
}
|
|
243
|
+
return `❌ Failed to send email: ${errorMessage}`;
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: 'verify_email_config',
|
|
249
|
+
description: 'Verify that email/SMTP configuration is correct and can connect to the mail server.',
|
|
250
|
+
parameters: {
|
|
251
|
+
type: 'object',
|
|
252
|
+
properties: {},
|
|
253
|
+
},
|
|
254
|
+
handler: async () => {
|
|
255
|
+
const config = getEmailConfig();
|
|
256
|
+
if (!config) {
|
|
257
|
+
return `❌ Email not configured.
|
|
258
|
+
|
|
259
|
+
Required environment variables:
|
|
260
|
+
- SMTP_USER or EMAIL_USER
|
|
261
|
+
- SMTP_PASSWORD or EMAIL_APP_PASSWORD
|
|
262
|
+
|
|
263
|
+
Optional:
|
|
264
|
+
- SMTP_PROVIDER: gmail, outlook, yahoo, icloud, zoho
|
|
265
|
+
- SMTP_HOST, SMTP_PORT: For custom SMTP servers
|
|
266
|
+
- SMTP_FROM_NAME: Display name
|
|
267
|
+
|
|
268
|
+
Use /secrets to configure these values.`;
|
|
269
|
+
}
|
|
270
|
+
try {
|
|
271
|
+
await createTransporter(config);
|
|
272
|
+
return `✅ Email configuration verified!
|
|
273
|
+
|
|
274
|
+
Provider: ${config.provider}
|
|
275
|
+
Host: ${config.host}
|
|
276
|
+
Port: ${config.port}
|
|
277
|
+
User: ${config.user}
|
|
278
|
+
Secure: ${config.secure ? 'Yes (SSL/TLS)' : 'No (STARTTLS)'}
|
|
279
|
+
From Name: ${config.fromName || '(not set)'}
|
|
280
|
+
|
|
281
|
+
SMTP connection successful. You can now use send_email to send emails.`;
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
285
|
+
return `❌ Email configuration verification failed.
|
|
286
|
+
|
|
287
|
+
Provider: ${config.provider}
|
|
288
|
+
Host: ${config.host}
|
|
289
|
+
Port: ${config.port}
|
|
290
|
+
User: ${config.user}
|
|
291
|
+
|
|
292
|
+
Error: ${errorMessage}
|
|
293
|
+
|
|
294
|
+
Common issues:
|
|
295
|
+
1. Wrong app password (must use app password, not regular password)
|
|
296
|
+
2. 2FA not enabled on email account
|
|
297
|
+
3. Wrong SMTP provider selected
|
|
298
|
+
4. Network/firewall blocking SMTP ports`;
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: 'send_batch_emails',
|
|
304
|
+
description: `Send personalized emails to multiple recipients in batch.
|
|
305
|
+
|
|
306
|
+
Useful for:
|
|
307
|
+
- Investor outreach campaigns
|
|
308
|
+
- Lead nurturing sequences
|
|
309
|
+
- Newsletter distribution
|
|
310
|
+
- Bulk notifications with personalization
|
|
311
|
+
|
|
312
|
+
Supports template variables: {{name}}, {{company}}, {{custom_field}}`,
|
|
313
|
+
parameters: {
|
|
314
|
+
type: 'object',
|
|
315
|
+
properties: {
|
|
316
|
+
recipients: {
|
|
317
|
+
type: 'array',
|
|
318
|
+
items: {
|
|
319
|
+
type: 'object',
|
|
320
|
+
properties: {
|
|
321
|
+
email: { type: 'string', description: 'Recipient email' },
|
|
322
|
+
name: { type: 'string', description: 'Recipient name for personalization' },
|
|
323
|
+
company: { type: 'string', description: 'Company name (optional)' },
|
|
324
|
+
custom: {
|
|
325
|
+
type: 'object',
|
|
326
|
+
description: 'Custom fields for template substitution',
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
required: ['email'],
|
|
330
|
+
},
|
|
331
|
+
description: 'Array of recipients with personalization data',
|
|
332
|
+
},
|
|
333
|
+
subject_template: {
|
|
334
|
+
type: 'string',
|
|
335
|
+
description: 'Subject line template with {{variables}}',
|
|
336
|
+
},
|
|
337
|
+
body_template: {
|
|
338
|
+
type: 'string',
|
|
339
|
+
description: 'Email body template with {{variables}}',
|
|
340
|
+
},
|
|
341
|
+
html: {
|
|
342
|
+
type: 'boolean',
|
|
343
|
+
description: 'Set to true if body contains HTML (default: false)',
|
|
344
|
+
},
|
|
345
|
+
delay_ms: {
|
|
346
|
+
type: 'number',
|
|
347
|
+
description: 'Delay between emails in milliseconds (default: 1000). Helps avoid rate limits.',
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
required: ['recipients', 'subject_template', 'body_template'],
|
|
351
|
+
},
|
|
352
|
+
handler: async (args) => {
|
|
353
|
+
const config = getEmailConfig();
|
|
354
|
+
if (!config) {
|
|
355
|
+
return 'Email not configured. Use /secrets to set SMTP_USER and SMTP_PASSWORD.';
|
|
356
|
+
}
|
|
357
|
+
const recipients = args['recipients'];
|
|
358
|
+
const subjectTemplate = args['subject_template'];
|
|
359
|
+
const bodyTemplate = args['body_template'];
|
|
360
|
+
const isHtml = args['html'] === true;
|
|
361
|
+
const delayMs = args['delay_ms'] || 1000;
|
|
362
|
+
if (!recipients?.length || !subjectTemplate || !bodyTemplate) {
|
|
363
|
+
return 'Error: recipients, subject_template, and body_template are required.';
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
const transporter = await createTransporter(config);
|
|
367
|
+
const fromAddress = config.fromName
|
|
368
|
+
? `"${config.fromName}" <${config.user}>`
|
|
369
|
+
: config.user;
|
|
370
|
+
const results = [];
|
|
371
|
+
for (let i = 0; i < recipients.length; i++) {
|
|
372
|
+
const recipient = recipients[i];
|
|
373
|
+
if (!recipient)
|
|
374
|
+
continue;
|
|
375
|
+
// Apply template substitution
|
|
376
|
+
const personalizedSubject = applyTemplate(subjectTemplate, recipient);
|
|
377
|
+
const personalizedBody = applyTemplate(bodyTemplate, recipient);
|
|
378
|
+
try {
|
|
379
|
+
await transporter.sendMail({
|
|
380
|
+
from: fromAddress,
|
|
381
|
+
to: recipient.email,
|
|
382
|
+
subject: personalizedSubject,
|
|
383
|
+
...(isHtml ? { html: personalizedBody } : { text: personalizedBody }),
|
|
384
|
+
});
|
|
385
|
+
results.push({ email: recipient.email, success: true });
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
results.push({
|
|
389
|
+
email: recipient.email,
|
|
390
|
+
success: false,
|
|
391
|
+
error: error instanceof Error ? error.message : String(error),
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
// Delay between emails (except for last one)
|
|
395
|
+
if (i < recipients.length - 1 && delayMs > 0) {
|
|
396
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const successful = results.filter(r => r.success).length;
|
|
400
|
+
const failed = results.filter(r => !r.success);
|
|
401
|
+
let summary = `📧 Batch Email Results
|
|
402
|
+
|
|
403
|
+
Total: ${recipients.length}
|
|
404
|
+
Sent: ${successful}
|
|
405
|
+
Failed: ${failed.length}
|
|
406
|
+
Provider: ${config.provider}
|
|
407
|
+
`;
|
|
408
|
+
if (failed.length > 0) {
|
|
409
|
+
summary += '\n❌ Failed emails:\n';
|
|
410
|
+
for (const f of failed) {
|
|
411
|
+
summary += `- ${f.email}: ${f.error}\n`;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return summary;
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
return `❌ Batch email failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
];
|
|
422
|
+
}
|
|
423
|
+
function applyTemplate(template, data) {
|
|
424
|
+
let result = template;
|
|
425
|
+
// Standard fields
|
|
426
|
+
result = result.replace(/\{\{email\}\}/gi, data.email);
|
|
427
|
+
result = result.replace(/\{\{name\}\}/gi, data.name || '');
|
|
428
|
+
result = result.replace(/\{\{company\}\}/gi, data.company || '');
|
|
429
|
+
// First name extraction
|
|
430
|
+
const firstName = data.name?.split(' ')[0] || '';
|
|
431
|
+
result = result.replace(/\{\{first_name\}\}/gi, firstName);
|
|
432
|
+
result = result.replace(/\{\{firstName\}\}/gi, firstName);
|
|
433
|
+
// Custom fields
|
|
434
|
+
if (data.custom) {
|
|
435
|
+
for (const [key, value] of Object.entries(data.custom)) {
|
|
436
|
+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'gi');
|
|
437
|
+
result = result.replace(regex, value);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
// Clean up any remaining unmatched placeholders
|
|
441
|
+
result = result.replace(/\{\{[^}]+\}\}/g, '');
|
|
442
|
+
return result;
|
|
443
|
+
}
|
|
444
|
+
export { getEmailConfig };
|
|
445
|
+
//# sourceMappingURL=emailTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailTools.js","sourceRoot":"","sources":["../../src/tools/emailTools.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webTools.d.ts","sourceRoot":"","sources":["../../src/tools/webTools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI7D,wBAAgB,cAAc,IAAI,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"webTools.d.ts","sourceRoot":"","sources":["../../src/tools/webTools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI7D,wBAAgB,cAAc,IAAI,cAAc,EAAE,CAgPjD"}
|
package/dist/tools/webTools.js
CHANGED
|
@@ -12,7 +12,7 @@ export function createWebTools() {
|
|
|
12
12
|
- Use this tool when you need to retrieve and analyze web content
|
|
13
13
|
|
|
14
14
|
Usage notes:
|
|
15
|
-
- IMPORTANT: If
|
|
15
|
+
- IMPORTANT: If TAVILY_API_KEY is set, use WebExtract instead for better content extraction
|
|
16
16
|
- The URL must be a fully-formed valid URL
|
|
17
17
|
- HTTP URLs will be automatically upgraded to HTTPS
|
|
18
18
|
- The prompt should describe what information you want to extract from the page
|
|
@@ -62,6 +62,95 @@ Summary: This is the content fetched from the URL. In a full implementation, thi
|
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
},
|
|
65
|
+
{
|
|
66
|
+
name: 'WebExtract',
|
|
67
|
+
description: `- Extracts clean, structured content from one or more URLs using Tavily Extract API
|
|
68
|
+
- Superior to WebFetch for content extraction when TAVILY_API_KEY is available
|
|
69
|
+
- Returns raw text content optimized for LLM consumption
|
|
70
|
+
- Supports batch extraction of up to 20 URLs in a single call
|
|
71
|
+
|
|
72
|
+
Usage notes:
|
|
73
|
+
- Requires TAVILY_API_KEY environment variable
|
|
74
|
+
- Best for extracting article content, documentation, blog posts
|
|
75
|
+
- Returns clean text without HTML artifacts
|
|
76
|
+
- More reliable than basic HTML parsing for complex pages
|
|
77
|
+
- Use for deep content extraction when you need full page text`,
|
|
78
|
+
parameters: {
|
|
79
|
+
type: 'object',
|
|
80
|
+
properties: {
|
|
81
|
+
urls: {
|
|
82
|
+
type: 'array',
|
|
83
|
+
items: { type: 'string' },
|
|
84
|
+
description: 'Array of URLs to extract content from (max 20)',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
required: ['urls'],
|
|
88
|
+
},
|
|
89
|
+
handler: async (args) => {
|
|
90
|
+
const urls = args['urls'];
|
|
91
|
+
if (!urls || !Array.isArray(urls) || urls.length === 0) {
|
|
92
|
+
return 'Error: urls parameter is required and must be a non-empty array.';
|
|
93
|
+
}
|
|
94
|
+
if (urls.length > 20) {
|
|
95
|
+
return 'Error: Maximum 20 URLs allowed per request.';
|
|
96
|
+
}
|
|
97
|
+
const tavilyKey = process.env['TAVILY_API_KEY']?.trim();
|
|
98
|
+
if (!tavilyKey) {
|
|
99
|
+
return [
|
|
100
|
+
'WebExtract requires TAVILY_API_KEY to be set.',
|
|
101
|
+
'Get your API key at: https://tavily.com',
|
|
102
|
+
'',
|
|
103
|
+
'Falling back to WebFetch for basic extraction is available as an alternative.',
|
|
104
|
+
].join('\n');
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const response = await fetch('https://api.tavily.com/extract', {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: {
|
|
110
|
+
'Content-Type': 'application/json',
|
|
111
|
+
},
|
|
112
|
+
body: JSON.stringify({
|
|
113
|
+
api_key: tavilyKey,
|
|
114
|
+
urls: urls,
|
|
115
|
+
}),
|
|
116
|
+
});
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
const errorText = await response.text().catch(() => '');
|
|
119
|
+
throw new Error(`Tavily Extract returned HTTP ${response.status}: ${errorText}`);
|
|
120
|
+
}
|
|
121
|
+
const payload = (await response.json());
|
|
122
|
+
const results = payload.results || [];
|
|
123
|
+
const failedUrls = payload.failed_results || [];
|
|
124
|
+
if (results.length === 0 && failedUrls.length === urls.length) {
|
|
125
|
+
return `Failed to extract content from all ${urls.length} URLs. This may be due to access restrictions or invalid URLs.`;
|
|
126
|
+
}
|
|
127
|
+
let output = `Extracted content from ${results.length}/${urls.length} URLs:\n\n`;
|
|
128
|
+
for (const result of results) {
|
|
129
|
+
output += `--- ${result.url} ---\n`;
|
|
130
|
+
if (result.raw_content) {
|
|
131
|
+
// Truncate very long content
|
|
132
|
+
const content = result.raw_content.length > 10000
|
|
133
|
+
? result.raw_content.slice(0, 10000) + '\n\n... (content truncated)'
|
|
134
|
+
: result.raw_content;
|
|
135
|
+
output += `${content}\n\n`;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
output += '(No content extracted)\n\n';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (failedUrls.length > 0) {
|
|
142
|
+
output += `\nFailed URLs (${failedUrls.length}):\n`;
|
|
143
|
+
for (const failed of failedUrls) {
|
|
144
|
+
output += `- ${failed.url}: ${failed.error || 'Unknown error'}\n`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return output.trim();
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
return `Error extracting content: ${error instanceof Error ? error.message : String(error)}`;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
},
|
|
65
154
|
{
|
|
66
155
|
name: 'WebSearch',
|
|
67
156
|
description: `- Allows Claude to search the web and use the results to inform responses
|
|
@@ -109,8 +198,12 @@ Usage notes:
|
|
|
109
198
|
const provider = resolveSearchProvider();
|
|
110
199
|
if (!provider) {
|
|
111
200
|
return [
|
|
112
|
-
'WebSearch requires
|
|
201
|
+
'WebSearch requires TAVILY_API_KEY (recommended), BRAVE_SEARCH_API_KEY, or SERPAPI_API_KEY.',
|
|
113
202
|
'Run /secrets (or set the environment variables directly) to configure an API key.',
|
|
203
|
+
'',
|
|
204
|
+
'Get your Tavily API key at: https://tavily.com (recommended)',
|
|
205
|
+
'Get your Brave Search API key at: https://brave.com/search/api/',
|
|
206
|
+
'Get your SerpAPI key at: https://serpapi.com/',
|
|
114
207
|
].join('\n');
|
|
115
208
|
}
|
|
116
209
|
const results = await provider.search({
|
|
@@ -132,6 +225,15 @@ Usage notes:
|
|
|
132
225
|
];
|
|
133
226
|
}
|
|
134
227
|
function resolveSearchProvider() {
|
|
228
|
+
// Tavily is the preferred search provider
|
|
229
|
+
const tavilyKey = process.env['TAVILY_API_KEY']?.trim();
|
|
230
|
+
if (tavilyKey) {
|
|
231
|
+
return {
|
|
232
|
+
id: 'tavily',
|
|
233
|
+
label: 'Tavily Search',
|
|
234
|
+
search: (params) => performTavilySearch(params, tavilyKey),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
135
237
|
const braveKey = process.env['BRAVE_SEARCH_API_KEY']?.trim();
|
|
136
238
|
if (braveKey) {
|
|
137
239
|
return {
|
|
@@ -199,6 +301,42 @@ async function performSerpApiSearch(params, apiKey) {
|
|
|
199
301
|
.filter((result) => Boolean(result.url));
|
|
200
302
|
return applyDomainFilters(mapped, params.allowedDomains, params.blockedDomains).slice(0, params.maxResults);
|
|
201
303
|
}
|
|
304
|
+
async function performTavilySearch(params, apiKey) {
|
|
305
|
+
const response = await fetch('https://api.tavily.com/search', {
|
|
306
|
+
method: 'POST',
|
|
307
|
+
headers: {
|
|
308
|
+
'Content-Type': 'application/json',
|
|
309
|
+
},
|
|
310
|
+
body: JSON.stringify({
|
|
311
|
+
api_key: apiKey,
|
|
312
|
+
query: params.query,
|
|
313
|
+
search_depth: 'advanced',
|
|
314
|
+
include_answer: true,
|
|
315
|
+
include_raw_content: false,
|
|
316
|
+
max_results: Math.min(params.maxResults * 2, 10),
|
|
317
|
+
include_domains: params.allowedDomains.length ? params.allowedDomains : undefined,
|
|
318
|
+
exclude_domains: params.blockedDomains.length ? params.blockedDomains : undefined,
|
|
319
|
+
}),
|
|
320
|
+
});
|
|
321
|
+
if (!response.ok) {
|
|
322
|
+
const errorText = await response.text().catch(() => '');
|
|
323
|
+
throw new Error(`Tavily Search returned HTTP ${response.status}: ${errorText}`);
|
|
324
|
+
}
|
|
325
|
+
const payload = (await response.json());
|
|
326
|
+
const entries = Array.isArray(payload?.results) ? payload.results : [];
|
|
327
|
+
const mapped = entries
|
|
328
|
+
.map((entry) => ({
|
|
329
|
+
title: entry.title || entry.url,
|
|
330
|
+
url: entry.url,
|
|
331
|
+
snippet: entry.content || '',
|
|
332
|
+
source: safeHostname(entry.url) || undefined,
|
|
333
|
+
published: entry.published_date,
|
|
334
|
+
score: entry.score,
|
|
335
|
+
}))
|
|
336
|
+
.filter((result) => Boolean(result.url));
|
|
337
|
+
// Tavily already handles domain filtering via include_domains/exclude_domains
|
|
338
|
+
return mapped.slice(0, params.maxResults);
|
|
339
|
+
}
|
|
202
340
|
function parseDomainList(value) {
|
|
203
341
|
if (!Array.isArray(value)) {
|
|
204
342
|
return [];
|