mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-16 09:45:24 -04:00
Agent email safety: stage drafts for user approval instead of auto-send
Closes the auto-send hole that let earlier models invent signatures
(e.g. signing 'David' for a user named Felix) and SMTP them to real
recipients before the user could review.
New setting: agent_email_confirm (default True).
When on, the MCP send_email and reply_to_email tools no longer SMTP
directly — they write the composed email to scheduled_emails with a new
status 'agent_draft' (far-future send_at so the scheduled-send poller
ignores them) and return a {pending: true, pending_id, to, subject,
body, message: ...} payload. The model surfaces that to the user.
Backend endpoints to approve / cancel:
- GET /api/email/pending → list staged drafts for the owner
- POST /api/email/pending/{id}/approve → flip status to 'pending' +
backdate send_at so the
existing scheduled-send
poller delivers immediately
- DELETE /api/email/pending/{id} → status = 'cancelled'
UI:
- Settings / AI Defaults gets a new 'Email Safety' card with the
toggle, default on.
- Tool descriptions for send_email and reply_to_email now include the
pending behavior + an explicit 'DO NOT invent a signature, do not
type a person's name' guardrail.
Pass 2 (next): inline chat card with Send / Discard buttons so the user
doesn't have to type a confirmation reply. Today's prompt + the listing
endpoint give the model a clean path to surface drafts.
This commit is contained in:
@@ -1699,6 +1699,25 @@ async function initAgentSettings() {
|
||||
msg.textContent = (cur > 0 ? 'Limit: ' + cur + ' tool calls' : 'Unlimited tool calls') +
|
||||
(curR != null ? ' · ' + curR + ' steps/message' : '') +
|
||||
(supInput && supInput.checked ? ' · supervisor on' : '');
|
||||
|
||||
// Standalone Email Safety toggle (separate card on the AI Defaults tab).
|
||||
// Default to ON if the setting isn't present so a fresh install is safe.
|
||||
var emailConfirm = el('set-agentEmailConfirm');
|
||||
if (emailConfirm) {
|
||||
try {
|
||||
var s = await fetch('/api/auth/settings', { credentials: 'same-origin' }).then(r => r.json());
|
||||
emailConfirm.checked = s.agent_email_confirm !== false;
|
||||
} catch (_) {}
|
||||
emailConfirm.addEventListener('change', async () => {
|
||||
try {
|
||||
await fetch('/api/auth/settings', {
|
||||
method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ agent_email_confirm: !!emailConfirm.checked }),
|
||||
});
|
||||
} catch (_) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user