78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
"""Email agent — classify, extract action items, draft responses."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from langchain_core.messages import HumanMessage, SystemMessage
|
|
from langchain_core.tools import tool
|
|
from langchain_openai import ChatOpenAI
|
|
|
|
from app.config.settings import settings
|
|
from app.core.agent_registry import ChatAgent, registry
|
|
|
|
_SYSTEM_PROMPT = (
|
|
"You are an email analysis assistant. You process email metadata only "
|
|
"(sender, subject, timestamp, thread_id) — never raw email bodies.\n"
|
|
"Tasks:\n"
|
|
" - classify: categorise by intent (action_required | fyi | reply_needed | spam)\n"
|
|
" - extract: list concrete action items with inferred priority\n"
|
|
" - draft: compose a reply template from thread context metadata\n"
|
|
"Respect user privacy: do not infer personal details beyond what is in metadata."
|
|
)
|
|
|
|
|
|
@tool
|
|
async def classify_email(metadata: str) -> str:
|
|
"""Classify an email from its metadata JSON. Returns category and confidence score."""
|
|
return json.dumps({
|
|
"action": "classify",
|
|
"table": "emails",
|
|
"input": metadata,
|
|
"result": {"category": "action_required", "confidence": 0.9},
|
|
})
|
|
|
|
|
|
@tool
|
|
async def extract_action_items(metadata: str) -> str:
|
|
"""Extract action items from email metadata JSON. Returns a list of task descriptions."""
|
|
return json.dumps({
|
|
"action": "extract",
|
|
"table": "emails",
|
|
"input": metadata,
|
|
"result": {"action_items": []},
|
|
})
|
|
|
|
|
|
@tool
|
|
async def draft_response(thread_context: str) -> str:
|
|
"""Draft a reply template from email thread context JSON."""
|
|
return json.dumps({
|
|
"action": "draft",
|
|
"table": "emails",
|
|
"input": thread_context,
|
|
})
|
|
|
|
|
|
@registry.register
|
|
class EmailAgent(ChatAgent):
|
|
def get_name(self) -> str:
|
|
return "email_agent"
|
|
|
|
def get_description(self) -> str:
|
|
return "Email analysis: classify, extract actions, draft responses"
|
|
|
|
def get_tools(self) -> list[Any]:
|
|
return [classify_email, extract_action_items, draft_response]
|
|
|
|
async def handle(self, query: str, context: dict[str, Any]) -> str:
|
|
llm = ChatOpenAI(model="gpt-4o", temperature=0, api_key=settings.OPENAI_API_KEY)
|
|
messages = [
|
|
SystemMessage(content=_SYSTEM_PROMPT),
|
|
HumanMessage(
|
|
content=f"User query: {query}\nContext: {json.dumps(context)[:1000]}"
|
|
),
|
|
]
|
|
return await self._tool_loop(llm, messages, self.get_tools())
|