mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-15 17:25:26 -04:00
AI Reply menu: '...' kebab opens a note input to steer the draft
The Fast/Full popover now has a kebab (three-dot) button alongside the
two preset choices. Clicking it expands a textarea below with a
'Draft with note' send button. The textarea is for the user to tell
the AI how to reply ('confirm Tuesday at 2', 'decline politely', 'say
we'll need an extra week') instead of accepting a generic draft.
Plumbing:
- emailLibrary.js: kebab button + note panel inside .email-ai-reply-choice
menu. Submitting calls _runAiReplyFromButton with mode='ai-reply-full'
and a noteHint string.
- _runAiReplyFromButton signature gains noteHint; passes it through
state._onEmailClick as opts.noteHint.
- emailInbox.js consumer: forwards opts.noteHint into _openEmail's new
5th arg, which puts it in the /api/email/ai-reply POST body as
user_hint.
- routes/email_routes.py /ai-reply: reads user_hint, appends a
'User's instructions for THIS reply' section to the user message
(priority over default tone/length). Also skips the per-message
AI-reply cache when a hint is set — the cached generic draft would
silently override the instructions otherwise.
This commit is contained in:
+11
-2
@@ -2657,11 +2657,15 @@ def setup_email_routes():
|
||||
source_uid = (data.get("uid") or "").strip()
|
||||
source_folder = (data.get("folder") or "INBOX").strip()
|
||||
fast_reply = bool(data.get("fast", False))
|
||||
user_hint = (data.get("user_hint") or "").strip()
|
||||
|
||||
if not original_body:
|
||||
return {"success": False, "error": "No email body provided"}
|
||||
|
||||
if message_id:
|
||||
# Skip cache lookup when the caller supplied a user_hint — the
|
||||
# cached generic reply doesn't reflect the instructions and
|
||||
# would silently override them.
|
||||
if message_id and not user_hint:
|
||||
try:
|
||||
_c = _sql3.connect(SCHEDULED_DB)
|
||||
owner_clause, owner_params = _email_cache_owner_clause(owner)
|
||||
@@ -2801,8 +2805,13 @@ def setup_email_routes():
|
||||
user_msg = (
|
||||
f"Recipient: {to}\nSubject: {subject}\n\n"
|
||||
f"Original email and any current draft:\n{original_body[:6000]}\n\n"
|
||||
f"Draft a reply. Return only the reply body text."
|
||||
)
|
||||
if user_hint:
|
||||
user_msg += (
|
||||
f"User's instructions for THIS reply (follow these — they override "
|
||||
f"defaults like length/tone):\n{user_hint[:2000]}\n\n"
|
||||
)
|
||||
user_msg += "Draft a reply. Return only the reply body text."
|
||||
|
||||
# Build a candidate chain so a stale session-stored API key
|
||||
# (the most common cause of "authentication failed" here)
|
||||
|
||||
@@ -118,7 +118,7 @@ export function init(documentModule) {
|
||||
} catch (_) {}
|
||||
if (opts.compose) { _composeNew(); return; }
|
||||
if (opts.email) {
|
||||
await _openEmail(opts.email, null, opts.emailData, opts.mode || 'reply');
|
||||
await _openEmail(opts.email, null, opts.emailData, opts.mode || 'reply', opts.noteHint || '');
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -630,7 +630,7 @@ function _createEmailItem(em) {
|
||||
return item;
|
||||
}
|
||||
|
||||
async function _openEmail(em, itemEl, preloadedData = null, mode = 'reply') {
|
||||
async function _openEmail(em, itemEl, preloadedData = null, mode = 'reply', noteHint = '') {
|
||||
const aiReplyMode = mode === 'ai-reply-fast' ? 'fast' : (mode === 'ai-reply-full' ? 'full' : '');
|
||||
const wantsAiReply = mode === 'ai-reply' || !!aiReplyMode;
|
||||
let aiSuggestedBody = null;
|
||||
@@ -690,6 +690,7 @@ async function _openEmail(em, itemEl, preloadedData = null, mode = 'reply') {
|
||||
uid: String(em.uid || ''),
|
||||
folder: _currentFolder,
|
||||
fast: aiReplyMode ? aiReplyMode === 'fast' : _shouldUseFastAiReply(data),
|
||||
user_hint: (noteHint || '').trim() || undefined,
|
||||
}),
|
||||
});
|
||||
const result = await res.json();
|
||||
|
||||
Reference in New Issue
Block a user