mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-07-14 12:48:03 +00:00
fix(email): close remaining email-tool registry drift; classify every email tool for plan mode
Deep self-review follow-up on #3681. Three review rounds each found another hand-maintained copy of the email tool list that had drifted; this commit hunts down ALL remaining copies and pins them to BUILTIN_EMAIL_TOOLS. The same 5 tools (search_emails, draft_email, draft_email_reply, ai_draft_email_reply, download_attachment) were missing from every advertising surface, so they were dispatchable but never offered: - FUNCTION_TOOL_SCHEMAS: native function-calling models never saw them (the round-1 fix covered dispatch only); schemas added, mirroring the email server's inputSchema definitions. - TOOL_SECTIONS: fenced-block models were never told about them; prompt sections added. - tool_index: absent from the RAG embedding registry (never retrievable), the email keyword hints, and the scheduled assistant's always-available set — the latter two now derive from BUILTIN_EMAIL_TOOLS. - agent_loop._DOMAIN_TOOL_MAP["email"], tool_policy._COMMON_TOOL_NAMES, the assistant tool-selector UI groups (assistant.js), and the default Assistant crew seed (task_scheduler) now derive from / cover the set. Plan mode now classifies every email tool explicitly: - list_email_accounts and search_emails join PLAN_MODE_READONLY_TOOLS. Without this, list_email_accounts sat in the plan-mode bare denylist (schema-derived) while its qualified form passed the MCP read-only filter — and the round-2 bare/qualified alias gate would have blocked the qualified call too, regressing read-only email discovery in plan mode. - draft_email, draft_email_reply, ai_draft_email_reply, and download_attachment join the fail-closed mutator backstop (drafts create documents; download_attachment writes to disk). Tests: tests/test_email_registry_sync.py pins every registry (including the email server source and assistant.js) to BUILTIN_EMAIL_TOOLS and asserts the plan-mode partition, so the next email tool can't drift; a parse/strip mirror grid covers 192 fence shapes (tag x header x body) asserting executed <=> stripped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1187,6 +1187,97 @@ FUNCTION_TOOL_SCHEMAS = [
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "search_emails",
|
||||
"description": "Search emails by free-text query (sender, subject, or body) across INBOX + Sent + Archive by default. Use whenever the user names a person or topic that isn't in the most recent inbox slice. Returns matching emails with UIDs for read_email/reply_to_email.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {"type": "string", "description": "Free-text query. Matches FROM, SUBJECT, and body TEXT."},
|
||||
"folders": {"type": "array", "items": {"type": "string"}, "description": "Folders to search (default: INBOX, Sent, Archive)"},
|
||||
"max_results": {"type": "integer", "description": "Max results per folder (default: 20)"},
|
||||
"account": {"type": "string", "description": "Account name/email/id from list_email_accounts"},
|
||||
},
|
||||
"required": ["query"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "draft_email",
|
||||
"description": "Create a new email compose DRAFT document for user review — this does NOT send. Prefer this over send_email when the user asks you to write/compose an email without explicitly saying send.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"to": {"type": "string", "description": "Recipient email address(es), comma-separated"},
|
||||
"subject": {"type": "string", "description": "Email subject line"},
|
||||
"body": {"type": "string", "description": "Draft body"},
|
||||
"cc": {"type": "string", "description": "CC address(es), comma-separated (optional)"},
|
||||
"bcc": {"type": "string", "description": "BCC address(es), comma-separated (optional)"},
|
||||
"title": {"type": "string", "description": "Optional document title"},
|
||||
"account": {"type": "string", "description": "Account name/email/id from list_email_accounts"},
|
||||
},
|
||||
"required": ["to", "subject", "body"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "draft_email_reply",
|
||||
"description": "Create a threaded reply DRAFT document for an existing email UID — this does NOT send. Prefer this over reply_to_email when the user wants a reply written, not sent. Threads with In-Reply-To/References and prefills recipient/subject.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uid": {"type": "string", "description": "Exact Email UID from list_emails/read_email; never invent UID 1"},
|
||||
"body": {"type": "string", "description": "Draft reply body text"},
|
||||
"folder": {"type": "string", "description": "IMAP folder (default: INBOX)"},
|
||||
"reply_all": {"type": "boolean", "description": "Reply to all recipients (default: false)"},
|
||||
"title": {"type": "string", "description": "Optional document title"},
|
||||
"account": {"type": "string", "description": "Account name/email/id from list_email_accounts"},
|
||||
},
|
||||
"required": ["uid", "body"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "ai_draft_email_reply",
|
||||
"description": "Generate an AI-written reply draft for an email UID using the user's configured writing style, then open it as a compose document for review — this does NOT send. Use when asked to write/draft a reply without dictating the exact body.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uid": {"type": "string", "description": "Exact Email UID from list_emails/read_email; never invent UID 1"},
|
||||
"folder": {"type": "string", "description": "IMAP folder (default: INBOX)"},
|
||||
"reply_all": {"type": "boolean", "description": "Reply to all recipients (default: false)"},
|
||||
"title": {"type": "string", "description": "Optional document title"},
|
||||
"account": {"type": "string", "description": "Account name/email/id from list_email_accounts"},
|
||||
},
|
||||
"required": ["uid"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "download_attachment",
|
||||
"description": "Download an email attachment to local disk and return the file path (read it with read_file afterwards). Use to review a document/spreadsheet/file attached to an email.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uid": {"type": "string", "description": "Email UID from list_emails"},
|
||||
"index": {"type": "integer", "description": "Attachment index from read_email's attachments list"},
|
||||
"folder": {"type": "string", "description": "IMAP folder (default: INBOX)"},
|
||||
"account": {"type": "string", "description": "Account name/email/id from list_email_accounts"},
|
||||
},
|
||||
"required": ["uid", "index"]
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user