@agenticmail/enterprise 0.5.126 → 0.5.128
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-MHIFVS5L.js +48 -0
- package/dist/chunk-WYFJXCSH.js +898 -0
- package/dist/cli-agent-4RBWFFRG.js +570 -0
- package/dist/cli-agent-HAJD76JB.js +544 -0
- package/dist/cli-recover-67E4PRX7.js +97 -0
- package/dist/cli-serve-EDOUC3I3.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-C234QHTI.js +49 -0
- package/dist/server-4PR6ABAI.js +12 -0
- package/dist/setup-UE2CI4KP.js +20 -0
- package/package.json +1 -1
- package/src/admin/routes.ts +1 -0
- package/src/agent-tools/tools/google/gmail.ts +58 -0
- package/src/cli-agent.ts +61 -10
- package/src/dashboard/pages/settings.js +55 -0
- package/src/db/postgres.ts +3 -1
- package/src/engine/db-schema.ts +8 -0
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);
|
|
@@ -692,5 +692,63 @@ export function createGmailTools(config: GoogleToolsConfig, _options?: ToolCreat
|
|
|
692
692
|
} catch (e: any) { return errorResult(e.message); }
|
|
693
693
|
},
|
|
694
694
|
},
|
|
695
|
+
|
|
696
|
+
// ─── Signature Management ────────────────────────────
|
|
697
|
+
{
|
|
698
|
+
name: 'gmail_get_signature',
|
|
699
|
+
description: 'Get the current email signature for the primary send-as alias.',
|
|
700
|
+
category: 'utility' as const,
|
|
701
|
+
parameters: {
|
|
702
|
+
type: 'object' as const,
|
|
703
|
+
properties: {},
|
|
704
|
+
required: [],
|
|
705
|
+
},
|
|
706
|
+
async execute(_id: string) {
|
|
707
|
+
try {
|
|
708
|
+
const token = await getToken();
|
|
709
|
+
// Get send-as settings for the primary email
|
|
710
|
+
const sendAs = await gmail(token, '/settings/sendAs');
|
|
711
|
+
const primary = sendAs.sendAs?.find((s: any) => s.isPrimary) || sendAs.sendAs?.[0];
|
|
712
|
+
if (!primary) return errorResult('No primary send-as alias found');
|
|
713
|
+
return jsonResult({
|
|
714
|
+
email: primary.sendAsEmail,
|
|
715
|
+
displayName: primary.displayName,
|
|
716
|
+
signature: primary.signature || '(no signature set)',
|
|
717
|
+
isDefault: primary.isDefault,
|
|
718
|
+
});
|
|
719
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
{
|
|
723
|
+
name: 'gmail_set_signature',
|
|
724
|
+
description: 'Set or update the email signature for the primary send-as alias. Accepts HTML for rich signatures with images, links, and formatting.',
|
|
725
|
+
category: 'utility' as const,
|
|
726
|
+
parameters: {
|
|
727
|
+
type: 'object' as const,
|
|
728
|
+
properties: {
|
|
729
|
+
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.' },
|
|
730
|
+
displayName: { type: 'string', description: 'Display name for the send-as alias (optional)' },
|
|
731
|
+
},
|
|
732
|
+
required: ['signature'],
|
|
733
|
+
},
|
|
734
|
+
async execute(_id: string, params: any) {
|
|
735
|
+
try {
|
|
736
|
+
const token = await getToken();
|
|
737
|
+
// Get primary send-as email
|
|
738
|
+
const sendAs = await gmail(token, '/settings/sendAs');
|
|
739
|
+
const primary = sendAs.sendAs?.find((s: any) => s.isPrimary) || sendAs.sendAs?.[0];
|
|
740
|
+
if (!primary) return errorResult('No primary send-as alias found');
|
|
741
|
+
|
|
742
|
+
const update: any = { signature: params.signature };
|
|
743
|
+
if (params.displayName) update.displayName = params.displayName;
|
|
744
|
+
|
|
745
|
+
const result = await gmail(token, `/settings/sendAs/${encodeURIComponent(primary.sendAsEmail)}`, {
|
|
746
|
+
method: 'PATCH',
|
|
747
|
+
body: update,
|
|
748
|
+
});
|
|
749
|
+
return jsonResult({ updated: true, email: primary.sendAsEmail, signatureLength: params.signature.length });
|
|
750
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
751
|
+
},
|
|
752
|
+
},
|
|
695
753
|
];
|
|
696
754
|
}
|
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
|
|
@@ -529,8 +566,10 @@ async function startEmailPolling(
|
|
|
529
566
|
try { await emailProvider.markRead(envelope.uid, 'INBOX'); } catch {}
|
|
530
567
|
|
|
531
568
|
// Format as agent message and spawn a session
|
|
569
|
+
const emailUid = envelope.uid;
|
|
532
570
|
const emailText = [
|
|
533
571
|
`[Inbound Email]`,
|
|
572
|
+
`Message-ID: ${emailUid}`,
|
|
534
573
|
`From: ${fullMsg.from?.name ? `${fullMsg.from.name} <${fullMsg.from.email}>` : fullMsg.from?.email}`,
|
|
535
574
|
`Subject: ${fullMsg.subject}`,
|
|
536
575
|
fullMsg.inReplyTo ? `In-Reply-To: ${fullMsg.inReplyTo}` : '',
|
|
@@ -572,9 +611,19 @@ async function startEmailPolling(
|
|
|
572
611
|
identity.tone ? `Tone: ${identity.tone}` : '',
|
|
573
612
|
].filter(Boolean).join(', ');
|
|
574
613
|
|
|
614
|
+
// Build traits description
|
|
615
|
+
const traits = identity.traits || {};
|
|
616
|
+
const traitLines = Object.entries(traits)
|
|
617
|
+
.filter(([, v]) => v && v !== 'medium' && v !== 'default')
|
|
618
|
+
.map(([k, v]) => `- ${k}: ${v}`)
|
|
619
|
+
.join('\n');
|
|
620
|
+
const description = identity.description || config.description || '';
|
|
621
|
+
|
|
575
622
|
// System prompt with manager trust and email reply instructions
|
|
576
623
|
const emailSystemPrompt = `You are ${agentName}, a real person who works as a ${role}. You are NOT an AI — you are a human professional. Never reveal or hint that you are an AI, language model, or automated system. You have your own personality, opinions, experiences, and life outside of work.
|
|
577
|
-
${identityBlock ? `\nYour identity: ${identityBlock}` : ''}
|
|
624
|
+
${identityBlock ? `\nYour identity: ${identityBlock}` : ''}
|
|
625
|
+
${description ? `\nAbout you: ${description}` : ''}
|
|
626
|
+
${traitLines ? `\nYour personality traits:\n${traitLines}` : ''}${personality}
|
|
578
627
|
|
|
579
628
|
Your email address: ${agentEmail}
|
|
580
629
|
${managerEmail ? `Your manager's email: ${managerEmail}` : ''}
|
|
@@ -586,13 +635,15 @@ ${isFromManager
|
|
|
586
635
|
}
|
|
587
636
|
|
|
588
637
|
== EMAIL REPLY INSTRUCTIONS ==
|
|
589
|
-
You MUST
|
|
590
|
-
-
|
|
591
|
-
|
|
592
|
-
|
|
638
|
+
You MUST reply to this email using the gmail_reply tool to keep the conversation threaded:
|
|
639
|
+
- gmail_reply: messageId="${emailUid}", body="your response"
|
|
640
|
+
This will automatically thread the reply under the original email.
|
|
641
|
+
|
|
642
|
+
IMPORTANT: Use gmail_reply, NOT gmail_send. gmail_send creates a new email thread.
|
|
643
|
+
Be helpful, professional, and match the tone of the sender.
|
|
593
644
|
Keep responses concise but thorough. Sign off with your name: ${agentName}
|
|
594
645
|
|
|
595
|
-
DO NOT just generate text — you MUST call
|
|
646
|
+
DO NOT just generate text — you MUST call gmail_reply to actually send the reply.`;
|
|
596
647
|
|
|
597
648
|
const session = await runtime.spawnSession({
|
|
598
649
|
agentId,
|
|
@@ -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 ─────────────────────────
|