@agenticmail/enterprise 0.5.127 → 0.5.129
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/chunk-3UJJAD4H.js +2195 -0
- package/dist/chunk-7RU5FIWV.js +2404 -0
- package/dist/chunk-D2MMF22A.js +16163 -0
- package/dist/chunk-EUMQIDYD.js +2195 -0
- package/dist/chunk-I6X4KSPW.js +16167 -0
- package/dist/chunk-M6GX25GK.js +898 -0
- package/dist/chunk-MHIFVS5L.js +48 -0
- package/dist/chunk-WYFJXCSH.js +898 -0
- package/dist/cli-agent-4RBWFFRG.js +570 -0
- package/dist/cli-agent-EE2HIA5Y.js +576 -0
- package/dist/cli-recover-67E4PRX7.js +97 -0
- package/dist/cli-serve-EDOUC3I3.js +34 -0
- package/dist/cli-serve-JWB66CU3.js +34 -0
- package/dist/cli-verify-6WVZMPH3.js +98 -0
- package/dist/cli.js +5 -5
- package/dist/dashboard/pages/settings.js +55 -0
- package/dist/db-adapter-MB5ONQGD.js +7 -0
- package/dist/factory-MBP7N2OQ.js +9 -0
- package/dist/index.js +5 -5
- package/dist/postgres-DJYELYKL.js +609 -0
- package/dist/runtime-A66NGCLG.js +49 -0
- package/dist/runtime-C234QHTI.js +49 -0
- package/dist/server-4PR6ABAI.js +12 -0
- package/dist/server-ZOAAIRVP.js +12 -0
- package/dist/setup-UE2CI4KP.js +20 -0
- package/dist/setup-WCW5BH3U.js +20 -0
- package/package.json +1 -1
- package/src/admin/routes.ts +1 -0
- package/src/agent-tools/tools/google/gmail.ts +68 -2
- package/src/cli-agent.ts +47 -4
- package/src/dashboard/pages/settings.js +55 -0
- package/src/db/postgres.ts +3 -1
- package/src/engine/db-schema.ts +8 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer
|
|
3
|
+
} from "./chunk-3UJJAD4H.js";
|
|
4
|
+
import "./chunk-3SMTCIR4.js";
|
|
5
|
+
import "./chunk-RO537U6H.js";
|
|
6
|
+
import "./chunk-DRXMYYKN.js";
|
|
7
|
+
import "./chunk-67KZYSLU.js";
|
|
8
|
+
import "./chunk-JLSQOQ5L.js";
|
|
9
|
+
import "./chunk-KFQGP6VL.js";
|
|
10
|
+
export {
|
|
11
|
+
createServer
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer
|
|
3
|
+
} from "./chunk-EUMQIDYD.js";
|
|
4
|
+
import "./chunk-3SMTCIR4.js";
|
|
5
|
+
import "./chunk-RO537U6H.js";
|
|
6
|
+
import "./chunk-DRXMYYKN.js";
|
|
7
|
+
import "./chunk-67KZYSLU.js";
|
|
8
|
+
import "./chunk-JLSQOQ5L.js";
|
|
9
|
+
import "./chunk-KFQGP6VL.js";
|
|
10
|
+
export {
|
|
11
|
+
createServer
|
|
12
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
promptCompanyInfo,
|
|
3
|
+
promptDatabase,
|
|
4
|
+
promptDeployment,
|
|
5
|
+
promptDomain,
|
|
6
|
+
promptRegistration,
|
|
7
|
+
provision,
|
|
8
|
+
runSetupWizard
|
|
9
|
+
} from "./chunk-WYFJXCSH.js";
|
|
10
|
+
import "./chunk-MHIFVS5L.js";
|
|
11
|
+
import "./chunk-KFQGP6VL.js";
|
|
12
|
+
export {
|
|
13
|
+
promptCompanyInfo,
|
|
14
|
+
promptDatabase,
|
|
15
|
+
promptDeployment,
|
|
16
|
+
promptDomain,
|
|
17
|
+
promptRegistration,
|
|
18
|
+
provision,
|
|
19
|
+
runSetupWizard
|
|
20
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
promptCompanyInfo,
|
|
3
|
+
promptDatabase,
|
|
4
|
+
promptDeployment,
|
|
5
|
+
promptDomain,
|
|
6
|
+
promptRegistration,
|
|
7
|
+
provision,
|
|
8
|
+
runSetupWizard
|
|
9
|
+
} from "./chunk-M6GX25GK.js";
|
|
10
|
+
import "./chunk-MHIFVS5L.js";
|
|
11
|
+
import "./chunk-KFQGP6VL.js";
|
|
12
|
+
export {
|
|
13
|
+
promptCompanyInfo,
|
|
14
|
+
promptDatabase,
|
|
15
|
+
promptDeployment,
|
|
16
|
+
promptDomain,
|
|
17
|
+
promptRegistration,
|
|
18
|
+
provision,
|
|
19
|
+
runSetupWizard
|
|
20
|
+
};
|
package/package.json
CHANGED
package/src/admin/routes.ts
CHANGED
|
@@ -470,6 +470,7 @@ export function createAdminRoutes(db: DatabaseAdapter) {
|
|
|
470
470
|
{ field: 'cfApiToken', type: 'string', maxLength: 500 },
|
|
471
471
|
{ field: 'cfAccountId', type: 'string', maxLength: 100 },
|
|
472
472
|
{ field: 'plan', type: 'string', maxLength: 32 },
|
|
473
|
+
{ field: 'signatureTemplate', type: 'string', maxLength: 10000 },
|
|
473
474
|
]);
|
|
474
475
|
|
|
475
476
|
const settings = await db.updateSettings(body);
|
|
@@ -355,9 +355,17 @@ export function createGmailTools(config: GoogleToolsConfig, _options?: ToolCreat
|
|
|
355
355
|
const original = await gmail(token, `/messages/${params.messageId}`, { query: { format: 'metadata', metadataHeaders: 'From,To,Cc,Subject,Message-ID,References' } });
|
|
356
356
|
const oh = extractHeaders(original.payload?.headers || [], ['From', 'To', 'Cc', 'Subject', 'Message-ID', 'References']);
|
|
357
357
|
|
|
358
|
+
// Extract clean email from From header (handles "Name <email>" format)
|
|
359
|
+
const extractEmail = (h: string) => {
|
|
360
|
+
const m = h.match(/<([^>]+)>/);
|
|
361
|
+
return m ? m[1] : h.trim();
|
|
362
|
+
};
|
|
358
363
|
const to = params.replyAll === 'true'
|
|
359
|
-
? [oh.From, ...(oh.To || '').split(','), ...(oh.Cc || '').split(',')]
|
|
360
|
-
|
|
364
|
+
? [oh.From, ...(oh.To || '').split(','), ...(oh.Cc || '').split(',')]
|
|
365
|
+
.map(e => extractEmail(e))
|
|
366
|
+
.filter(e => e && !e.includes(email || '___'))
|
|
367
|
+
.join(',')
|
|
368
|
+
: extractEmail(oh.From);
|
|
361
369
|
|
|
362
370
|
const subject = oh.Subject?.startsWith('Re:') ? oh.Subject : `Re: ${oh.Subject || ''}`;
|
|
363
371
|
const references = [oh.References, oh['Message-ID']].filter(Boolean).join(' ');
|
|
@@ -692,5 +700,63 @@ export function createGmailTools(config: GoogleToolsConfig, _options?: ToolCreat
|
|
|
692
700
|
} catch (e: any) { return errorResult(e.message); }
|
|
693
701
|
},
|
|
694
702
|
},
|
|
703
|
+
|
|
704
|
+
// ─── Signature Management ────────────────────────────
|
|
705
|
+
{
|
|
706
|
+
name: 'gmail_get_signature',
|
|
707
|
+
description: 'Get the current email signature for the primary send-as alias.',
|
|
708
|
+
category: 'utility' as const,
|
|
709
|
+
parameters: {
|
|
710
|
+
type: 'object' as const,
|
|
711
|
+
properties: {},
|
|
712
|
+
required: [],
|
|
713
|
+
},
|
|
714
|
+
async execute(_id: string) {
|
|
715
|
+
try {
|
|
716
|
+
const token = await getToken();
|
|
717
|
+
// Get send-as settings for the primary email
|
|
718
|
+
const sendAs = await gmail(token, '/settings/sendAs');
|
|
719
|
+
const primary = sendAs.sendAs?.find((s: any) => s.isPrimary) || sendAs.sendAs?.[0];
|
|
720
|
+
if (!primary) return errorResult('No primary send-as alias found');
|
|
721
|
+
return jsonResult({
|
|
722
|
+
email: primary.sendAsEmail,
|
|
723
|
+
displayName: primary.displayName,
|
|
724
|
+
signature: primary.signature || '(no signature set)',
|
|
725
|
+
isDefault: primary.isDefault,
|
|
726
|
+
});
|
|
727
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
name: 'gmail_set_signature',
|
|
732
|
+
description: 'Set or update the email signature for the primary send-as alias. Accepts HTML for rich signatures with images, links, and formatting.',
|
|
733
|
+
category: 'utility' as const,
|
|
734
|
+
parameters: {
|
|
735
|
+
type: 'object' as const,
|
|
736
|
+
properties: {
|
|
737
|
+
signature: { type: 'string', description: 'HTML signature content. Use HTML tags for formatting: <b>bold</b>, <a href="...">links</a>, <img src="..."> for logos, <br> for line breaks, <table> for layout.' },
|
|
738
|
+
displayName: { type: 'string', description: 'Display name for the send-as alias (optional)' },
|
|
739
|
+
},
|
|
740
|
+
required: ['signature'],
|
|
741
|
+
},
|
|
742
|
+
async execute(_id: string, params: any) {
|
|
743
|
+
try {
|
|
744
|
+
const token = await getToken();
|
|
745
|
+
// Get primary send-as email
|
|
746
|
+
const sendAs = await gmail(token, '/settings/sendAs');
|
|
747
|
+
const primary = sendAs.sendAs?.find((s: any) => s.isPrimary) || sendAs.sendAs?.[0];
|
|
748
|
+
if (!primary) return errorResult('No primary send-as alias found');
|
|
749
|
+
|
|
750
|
+
const update: any = { signature: params.signature };
|
|
751
|
+
if (params.displayName) update.displayName = params.displayName;
|
|
752
|
+
|
|
753
|
+
const result = await gmail(token, `/settings/sendAs/${encodeURIComponent(primary.sendAsEmail)}`, {
|
|
754
|
+
method: 'PATCH',
|
|
755
|
+
body: update,
|
|
756
|
+
});
|
|
757
|
+
return jsonResult({ updated: true, email: primary.sendAsEmail, signatureLength: params.signature.length });
|
|
758
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
759
|
+
},
|
|
760
|
+
},
|
|
695
761
|
];
|
|
696
762
|
}
|
package/src/cli-agent.ts
CHANGED
|
@@ -418,7 +418,45 @@ Available tools: gmail_send (to, subject, body) or agenticmail_send (to, subject
|
|
|
418
418
|
console.error(`[onboarding] Error: ${err.message}`);
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
-
// 12.
|
|
421
|
+
// 12. Auto-setup Gmail signature from org template
|
|
422
|
+
try {
|
|
423
|
+
const orgSettings = await db.getSettings();
|
|
424
|
+
const sigTemplate = (orgSettings as any)?.signatureTemplate;
|
|
425
|
+
if (sigTemplate && currentAccessToken) {
|
|
426
|
+
const agentName = config.displayName || config.name;
|
|
427
|
+
const role = config.identity?.role || 'AI Agent';
|
|
428
|
+
const agentEmailAddr = config.email?.address || emailConfig?.email || '';
|
|
429
|
+
const companyName = orgSettings?.name || '';
|
|
430
|
+
const logoUrl = orgSettings?.logoUrl || '';
|
|
431
|
+
|
|
432
|
+
const signature = sigTemplate
|
|
433
|
+
.replace(/\{\{name\}\}/g, agentName)
|
|
434
|
+
.replace(/\{\{role\}\}/g, role)
|
|
435
|
+
.replace(/\{\{email\}\}/g, agentEmailAddr)
|
|
436
|
+
.replace(/\{\{company\}\}/g, companyName)
|
|
437
|
+
.replace(/\{\{logo\}\}/g, logoUrl)
|
|
438
|
+
.replace(/\{\{phone\}\}/g, '');
|
|
439
|
+
|
|
440
|
+
// Set Gmail signature via API
|
|
441
|
+
const sendAsRes = await fetch('https://gmail.googleapis.com/gmail/v1/users/me/settings/sendAs', {
|
|
442
|
+
headers: { Authorization: `Bearer ${currentAccessToken}` },
|
|
443
|
+
});
|
|
444
|
+
const sendAs = await sendAsRes.json() as any;
|
|
445
|
+
const primary = sendAs.sendAs?.find((s: any) => s.isPrimary) || sendAs.sendAs?.[0];
|
|
446
|
+
if (primary) {
|
|
447
|
+
await fetch(`https://gmail.googleapis.com/gmail/v1/users/me/settings/sendAs/${encodeURIComponent(primary.sendAsEmail)}`, {
|
|
448
|
+
method: 'PATCH',
|
|
449
|
+
headers: { Authorization: `Bearer ${currentAccessToken}`, 'Content-Type': 'application/json' },
|
|
450
|
+
body: JSON.stringify({ signature }),
|
|
451
|
+
});
|
|
452
|
+
console.log(`[signature] ✅ Gmail signature set for ${primary.sendAsEmail}`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
} catch (sigErr: any) {
|
|
456
|
+
console.log(`[signature] Skipped: ${sigErr.message}`);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// 13. Start email inbox polling loop
|
|
422
460
|
startEmailPolling(AGENT_ID, config, lifecycle, runtime, engineDb, memoryManager);
|
|
423
461
|
}, 3000);
|
|
424
462
|
}
|
|
@@ -509,12 +547,11 @@ async function startEmailPolling(
|
|
|
509
547
|
try {
|
|
510
548
|
const messages = await emailProvider.listMessages('INBOX', { limit: 20 });
|
|
511
549
|
const newMessages = messages.filter(m => !processedIds.has(m.uid));
|
|
512
|
-
const unread = newMessages.filter(m => !m.read);
|
|
513
550
|
if (newMessages.length > 0) {
|
|
514
|
-
console.log(`[email-poll] Found ${newMessages.length} new messages
|
|
551
|
+
console.log(`[email-poll] Found ${newMessages.length} new messages`);
|
|
515
552
|
}
|
|
516
553
|
|
|
517
|
-
for (const envelope of
|
|
554
|
+
for (const envelope of newMessages) {
|
|
518
555
|
processedIds.add(envelope.uid);
|
|
519
556
|
|
|
520
557
|
// Skip emails from ourselves
|
|
@@ -606,6 +643,12 @@ IMPORTANT: Use gmail_reply, NOT gmail_send. gmail_send creates a new email threa
|
|
|
606
643
|
Be helpful, professional, and match the tone of the sender.
|
|
607
644
|
Keep responses concise but thorough. Sign off with your name: ${agentName}
|
|
608
645
|
|
|
646
|
+
FORMATTING RULES:
|
|
647
|
+
- NEVER use "--" or "---" or em dashes (—) in your emails
|
|
648
|
+
- NEVER use markdown formatting (no **, no ##, no bullet points with -)
|
|
649
|
+
- Write natural, flowing prose like a real human email
|
|
650
|
+
- Keep it warm and conversational, not robotic or formatted
|
|
651
|
+
|
|
609
652
|
DO NOT just generate text — you MUST call gmail_reply to actually send the reply.`;
|
|
610
653
|
|
|
611
654
|
const session = await runtime.spawnSession({
|
|
@@ -256,6 +256,61 @@ export function SettingsPage() {
|
|
|
256
256
|
h('button', { className: 'btn btn-primary', onClick: () => apiCall('/settings', { method: 'PATCH', body: JSON.stringify({ name: settings.name, domain: settings.domain, subdomain: settings.subdomain, logoUrl: settings.logoUrl, primaryColor: settings.primaryColor, plan: settings.plan }) }).then(d => { setSettings(d); toast('Settings saved', 'success'); }).catch(e => toast(e.message, 'error')) }, 'Save Changes')
|
|
257
257
|
)
|
|
258
258
|
),
|
|
259
|
+
|
|
260
|
+
// ─── Email Signature Template ─────────────────────
|
|
261
|
+
h('div', { className: 'card' },
|
|
262
|
+
h('div', { className: 'card-header' },
|
|
263
|
+
h('h3', null, 'Email Signature Template'),
|
|
264
|
+
h('span', { style: { fontSize: 12, color: 'var(--text-muted)', marginLeft: 8 } }, 'Applied to all agents')
|
|
265
|
+
),
|
|
266
|
+
h('div', { className: 'card-body' },
|
|
267
|
+
h('p', { style: { fontSize: 13, color: 'var(--text-muted)', marginBottom: 16 } }, 'Define an HTML signature template that agents will use in their Gmail accounts. Use {{name}}, {{role}}, {{email}}, {{phone}}, {{company}} as placeholders.'),
|
|
268
|
+
h('div', { className: 'form-group' },
|
|
269
|
+
h('label', { className: 'form-label' }, 'Signature HTML Template'),
|
|
270
|
+
h('textarea', {
|
|
271
|
+
className: 'input',
|
|
272
|
+
value: settings.signatureTemplate || '',
|
|
273
|
+
onChange: function(e) { setSettings(function(s) { return Object.assign({}, s, { signatureTemplate: e.target.value }); }); },
|
|
274
|
+
placeholder: '<table cellpadding="0" cellspacing="0" style="font-family: Arial, sans-serif; font-size: 13px; color: #333;">\n <tr>\n <td style="padding-right: 15px; border-right: 2px solid #6366f1;">\n <img src="{{logo}}" width="60" alt="{{company}}">\n </td>\n <td style="padding-left: 15px;">\n <b style="font-size: 14px;">{{name}}</b><br>\n <span style="color: #6366f1;">{{role}}</span><br>\n <span style="color: #888;">{{email}}</span><br>\n <span style="color: #888;">{{company}}</span>\n </td>\n </tr>\n</table>',
|
|
275
|
+
rows: 12,
|
|
276
|
+
style: { fontFamily: 'var(--font-mono)', fontSize: 12, resize: 'vertical' }
|
|
277
|
+
})
|
|
278
|
+
),
|
|
279
|
+
h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12 } },
|
|
280
|
+
h('span', { className: 'badge', style: { fontSize: 11 } }, '{{name}}'),
|
|
281
|
+
h('span', { className: 'badge', style: { fontSize: 11 } }, '{{role}}'),
|
|
282
|
+
h('span', { className: 'badge', style: { fontSize: 11 } }, '{{email}}'),
|
|
283
|
+
h('span', { className: 'badge', style: { fontSize: 11 } }, '{{phone}}'),
|
|
284
|
+
h('span', { className: 'badge', style: { fontSize: 11 } }, '{{company}}'),
|
|
285
|
+
h('span', { className: 'badge', style: { fontSize: 11 } }, '{{logo}}')
|
|
286
|
+
),
|
|
287
|
+
settings.signatureTemplate && h('div', { style: { marginBottom: 16 } },
|
|
288
|
+
h('label', { className: 'form-label' }, 'Preview'),
|
|
289
|
+
h('div', {
|
|
290
|
+
style: { background: 'white', padding: 16, borderRadius: 'var(--radius)', border: '1px solid var(--border)', color: '#333' },
|
|
291
|
+
dangerouslySetInnerHTML: {
|
|
292
|
+
__html: (settings.signatureTemplate || '')
|
|
293
|
+
.replace(/\{\{name\}\}/g, 'Jane Smith')
|
|
294
|
+
.replace(/\{\{role\}\}/g, 'Customer Support Lead')
|
|
295
|
+
.replace(/\{\{email\}\}/g, 'jane@company.com')
|
|
296
|
+
.replace(/\{\{phone\}\}/g, '+1 (555) 123-4567')
|
|
297
|
+
.replace(/\{\{company\}\}/g, settings.name || 'Your Company')
|
|
298
|
+
.replace(/\{\{logo\}\}/g, settings.logoUrl || 'https://placehold.co/60x60?text=Logo')
|
|
299
|
+
}
|
|
300
|
+
})
|
|
301
|
+
),
|
|
302
|
+
h('button', {
|
|
303
|
+
className: 'btn btn-primary',
|
|
304
|
+
onClick: function() {
|
|
305
|
+
apiCall('/settings', {
|
|
306
|
+
method: 'PATCH',
|
|
307
|
+
body: JSON.stringify({ signatureTemplate: settings.signatureTemplate })
|
|
308
|
+
}).then(function() { toast('Signature template saved', 'success'); }).catch(function(e) { toast(e.message, 'error'); });
|
|
309
|
+
}
|
|
310
|
+
}, 'Save Signature Template')
|
|
311
|
+
)
|
|
312
|
+
),
|
|
313
|
+
|
|
259
314
|
h('div', { className: 'card' },
|
|
260
315
|
h('div', { className: 'card-header' },
|
|
261
316
|
h('h3', null, 'Organization Email'),
|
package/src/db/postgres.ts
CHANGED
|
@@ -150,6 +150,7 @@ export class PostgresAdapter extends DatabaseAdapter {
|
|
|
150
150
|
domainStatus: 'domain_status',
|
|
151
151
|
cfApiToken: 'cf_api_token',
|
|
152
152
|
cfAccountId: 'cf_account_id',
|
|
153
|
+
signatureTemplate: 'signature_template',
|
|
153
154
|
};
|
|
154
155
|
for (const [key, col] of Object.entries(map)) {
|
|
155
156
|
if ((updates as any)[key] !== undefined) {
|
|
@@ -562,6 +563,7 @@ export class PostgresAdapter extends DatabaseAdapter {
|
|
|
562
563
|
cfApiToken: r.cf_api_token || undefined,
|
|
563
564
|
cfAccountId: r.cf_account_id || undefined,
|
|
564
565
|
orgEmailConfig: r.org_email_config ? (typeof r.org_email_config === 'string' ? JSON.parse(r.org_email_config) : r.org_email_config) : undefined,
|
|
565
|
-
|
|
566
|
+
signatureTemplate: r.signature_template || undefined,
|
|
567
|
+
} as any;
|
|
566
568
|
}
|
|
567
569
|
}
|
package/src/engine/db-schema.ts
CHANGED
|
@@ -1297,6 +1297,14 @@ CREATE INDEX IF NOT EXISTS idx_kc_entries_base ON knowledge_contribution_entries
|
|
|
1297
1297
|
mysql: `SELECT 1;`,
|
|
1298
1298
|
nosql: async () => {},
|
|
1299
1299
|
},
|
|
1300
|
+
{
|
|
1301
|
+
version: 19,
|
|
1302
|
+
name: 'signature_template',
|
|
1303
|
+
sql: `ALTER TABLE company_settings ADD COLUMN signature_template TEXT;`,
|
|
1304
|
+
postgres: `ALTER TABLE company_settings ADD COLUMN IF NOT EXISTS signature_template TEXT;`,
|
|
1305
|
+
mysql: `ALTER TABLE company_settings ADD COLUMN signature_template TEXT;`,
|
|
1306
|
+
nosql: async () => {},
|
|
1307
|
+
},
|
|
1300
1308
|
];
|
|
1301
1309
|
|
|
1302
1310
|
// ─── Dynamic Table Definitions ─────────────────────────
|