The agent engine is the core AI workflow built on LangGraph. It processes emails through a deterministic pipeline of nodes, each powered by Google Gemini via LangChain.
- Calls
GeminiClient.classify_intent()via LangChain - Returns: intent category + confidence score
- Short-circuits spam emails with high confidence
- Embeds email text using Gemini embeddings (via LangChain)
- Searches pgvector for similar past emails
- Fetches CRM contact data and calendar events
- Returns: ranked list of context strings
- Analyzes classification + context
- Selects tools to invoke from available registry
- Returns: list of tools with parameters
- Iterates selected tools via ToolManager
- Each call logged to
tool_executionstable - Failures isolated — one tool failing doesn't block others
- Returns: dict of tool results
- Generates email response using Gemini via LangChain
- Incorporates context + tool results
- Returns: draft response text + confidence
- Decides: auto-approve vs human review
- Threshold: confidence ≥ 0.8 → auto-approve
- Complaints always require human review
- Returns:
requires_approvalflag
- Sends approved response via Gmail API
- Updates email status to "sent"
All LLM calls use langchain-google-genai:
from langchain_google_genai import ChatGoogleGenerativeAI
llm = ChatGoogleGenerativeAI(
model="gemini-2.0-flash",
google_api_key=settings.GEMINI_API_KEY,
)Embeddings use:
from langchain_google_genai import GoogleGenerativeAIEmbeddings
embeddings = GoogleGenerativeAIEmbeddings(
model="models/embedding-001",
google_api_key=settings.GEMINI_API_KEY,
)| Tool | Integration | Description |
|---|---|---|
| send_email | Gmail | Send an email response |
| create_draft | Gmail | Create a draft for review |
| check_calendar | Calendar | Check availability |
| create_event | Calendar | Schedule a meeting |
| get_contact | CRM | Fetch contact info |
| update_contact | CRM | Update contact data |
Every execution generates:
AgentLogentries for each node (with full state I/O)ToolExecutionentries for each tool call- A
trace_idto group all entries for one run