Skip to content

About

An intelligent LangGraph-powered Gmail Assistant that helps users manage their Gmail accounts using natural language. Users securely connect their Google account via OAuth, allowing the agent to read, organize, search, summarize, draft, and send emails on their behalf while respecting Google permissions.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

158 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gmail Assistant Agent — Project Overview

Generated by reading the full backend (FastAPI) and frontend (Next.js) source trees. This document explains what the project actually does, how it is built, and how the pieces connect.


1. What this project is

Mailgent (frontend branding) is a full‑stack, AI‑powered Gmail client. A user signs in with their real Google account (OAuth), and the app then acts as a smarter layer on top of their actual Gmail mailbox:

  • Browse Inbox / Sent / Drafts like a normal webmail client (read, star, archive, trash, spam, delete, bulk actions).
  • Compose, reply, reply‑all, and forward emails — either manually or AI‑generated.
  • A conversational AI chat assistant ("AI Assistant" / chat page) that can read and act on the user's actual mailbox using tool-calling (search inbox, create/update/send drafts, reply, forward, trash/star/archive, etc.).
  • Automatic replies: a background scheduler periodically scans new mail and, using an LLM, decides whether a message deserves an auto‑reply, then sends one in the user's voice, respecting the user's stored preferences.
  • Document knowledge base (RAG): users upload PDFs; the app extracts text, chunks it, embeds it (HuggingFace embeddings), and stores vectors in Pinecone. The chat agent and the auto‑reply agent can retrieve from these documents to ground answers/replies.
  • User preferences: free-form name/value rules (e.g. "always sign emails with...", "keep tone formal") that are injected as hard constraints into every AI agent's system prompt.
  • Gmail search with local logging of search history.
  • Dashboard stats (counts of AI actions, auto-replies sent, etc.) pulled from an audit table that logs every AI-performed email action.
  • A /qalam/marks-change webhook endpoint used to email students automatically when an external system ("QALAM", a results portal) reports a grade change — a bespoke integration outside the normal user-driven flows, protected by a static API key header.

In short: it's a Gmail webmail clone + an agentic AI email assistant + a RAG knowledge base + an autonomous auto‑reply bot, all wired to a single Google account per user.


2. High-level architecture

┌─────────────────────────┐        HTTPS / JSON, Bearer JWT        ┌───────────────────────────┐
│  Next.js 16 frontend     │  ───────────────────────────────────▶ │  FastAPI backend           │
│  (React 19, Tailwind 4)  │  ◀─────────────────────────────────── │  (Python, Uvicorn)         │
│  Deployed: Vercel         │                                       │                             │
└─────────────────────────┘                                       └───────────┬────────────────┘
                                                                                │
                    ┌───────────────────────────────────────────────────────────────────────────┐
                    │                                                                              │
        ┌───────────▼───────────┐   ┌────────────▼─────────────┐   ┌─────────────▼─────────────┐
        │  MySQL (via SQLAlchemy)│   │  Google Gmail API (OAuth) │   │  Pinecone vector DB        │
        │  users, gmail_accounts,│   │  read/send/modify mail on │   │  per-user namespace        │
        │  preferences, docs,    │   │  behalf of the signed-in  │   │  "user_id_{id}_documents"  │
        │  ai_email_actions,     │   │  Google account            │   │                             │
        │  search_queries        │   └────────────────────────────┘   └─────────────────────────────┘
        └────────────────────────┘

        ┌────────────────────────────┐   ┌──────────────────────────────┐
        │  Azure-hosted OpenAI (LLM)  │   │  HuggingFace Inference API    │
        │  model: gpt-4.1-mini        │   │  sentence-transformers/       │
        │  used by LangChain agents   │   │  all-MiniLM-L6-v2 (embeddings)│
        └────────────────────────────┘   └──────────────────────────────┘

The backend is a modular FastAPI app; each domain (auth, gmail, chatbot, embeddings, preferences, search, stats, auto_reply) is its own package with a *_controller.py (routes), *_service.py (business logic), and sometimes a DTO.py (Pydantic request/response models).


3. Backend (/backend)

3.1 Stack

  • FastAPI (app/main.py) + Uvicorn, CORS enabled for the deployed frontend (https://gmail-assistant-eight.vercel.app) and localhost.
  • SQLAlchemy (raw text() SQL, not the ORM query layer) against MySQL (pymysql driver). Connection settings come from .env via pydantic_settings.
  • Auth: Google OAuth "authorization code" flow, exchanged server-side for Google access/refresh tokens; the backend then issues its own JWT (PyJWT) that the frontend stores in localStorage and sends as Authorization: Bearer <token> on every API call. All protected routes depend on get_current_user, which just decodes/verifies that JWT (no DB hit) and returns {user_id, name, email}.
  • Gmail integration: google-api-python-client + google-auth. A per-request GmailService wrapper is built from the user's stored refresh token (fetched from MySQL gmail_accounts.refresh_token), which is exchanged for a short-lived access token on every call (no caching).
  • AI orchestration: langchain, langchain_openai (ChatOpenAI against an Azure OpenAI-compatible endpoint, model gpt-4.1-mini), and LangGraph (langgraph) for a small state-graph based router that dispatches a chat message to one or more specialized "agents" and merges their results.
  • RAG / embeddings: pinecone (vector store), huggingface_hub (InferenceClient for embeddings via sentence-transformers/all-MiniLM-L6-v2), langchain-pinecone, langchain_text_splitters (RecursiveCharacterTextSplitter), pypdf/PyPDF2 for PDF text extraction.
  • Scheduling: apscheduler (BackgroundScheduler) — wired up but currently commented out in main.py's startup event, so auto‑reply currently only runs if triggered manually/externally rather than automatically every 10 minutes.

3.2 Directory map (backend/app/)

Folder Purpose
auth/ Google OAuth login/callback, JWT issuing & verification (jwt/service.py)
gmail/ All Gmail CRUD: inbox/sent/drafts, star/read/archive/trash/spam, send/reply/forward/draft, email parsing (Parser/)
chatbot/ Chat endpoint + the agent system: agent/gmail_agent.py, agent/knowledge_agent.py, agent/RAG_agent.py, LangGraph router in agent/langgraph/
auto_reply/ Background job that scans new mail per user and auto-replies via LLM, respecting user preferences
embeddings/ Upload PDFs, extract → chunk → embed → upsert to Pinecone; list/delete documents
preferences/ CRUD for user-defined AI behavior preferences (name/value/enabled)
search/ Server-side Gmail search (keyword scoring over live Gmail API results) + recent search history
stats/ Dashboard counts sourced from the ai_email_actions audit table
database/ SQLAlchemy engine/session setup, Pydantic settings, SQLAlchemy models (users, search_queries), the ai_action_service audit logger

3.3 Data model (database.sql)

MySQL database gmail_assistant:

  • users — id, google_id, name, email, profile_picture.
  • gmail_accounts — one row per connected Gmail account per user: refresh_token, status (ACTIVE/INACTIVE), auto_reply (bool toggle), last_history_id / last_auto_reply_check_at (Gmail History API cursor used to find "new since last check" messages for auto-reply).
  • gmail_syncs — placeholder table for initial-sync bookkeeping (not actively used in the code read).
  • search_queries — logs every Gmail search a user runs (query, is_ai_query, result_count) — powers "recent searches".
  • chat_threads / chat_messages — schema exists for persisted chat history, but the current chatbot implementation keeps conversation state in-memory via LangGraph's MemorySaver checkpointer keyed by f"{user_id}_{date.today()}", not in these tables.
  • user_preferences — preference_name + preference_value (free text) + enabled, unique per (user_id, preference_name). Injected into every AI agent's system prompt as hard constraints.
  • ai_email_actions — an audit/event log of every AI-driven mailbox action (draft created/updated, reply generated, email sent/trashed/deleted/starred/archived/ spam-marked/etc.), with status (pending/completed/failed), input/output text, and JSON metadata. This table is what powers the dashboard stats.
  • documents — one row per uploaded PDF: filename, purpose, chunk_count, status (processing/completed/failed). The actual vector embeddings live in Pinecone, not MySQL — this table is just the ledger.

3.4 Authentication flow

  1. Frontend uses @react-oauth/google's useGoogleLogin (auth-code flow, scope openid email profile https://mail.google.com/) to get a Google authorization code.
  2. Frontend POSTs the code to POST /api/auth/google/callback.
  3. Backend (auth_service.googleLogin) exchanges the code for Google access_token + refresh_token, fetches the Google profile, then:
    • If the email is new → creates a users row and a gmail_accounts row (storing the refresh token) — registerUser.
    • If the email exists → updates the stored refresh token — loginUser.
  4. Backend mints its own JWT (create_access_token) containing {user_id, name, email} with an expiry (ACCESS_TOKEN_EXPIRE_MINUTES env var) and returns it.
  5. Frontend stores the JWT in localStorage under access_token and attaches it as a Bearer token to every subsequent API call. GET /api/auth/user is used everywhere on the frontend as a lightweight "am I still logged in" probe.

Every Gmail operation on the backend re-derives a live Google access token from the stored refresh token via GmailService._get_access_token() — there is no access token caching layer, so each request does a token refresh call to Google.

3.5 Gmail domain (app/gmail/)

  • gmail_service.py — the core wrapper around the Gmail API (googleapiclient). Responsibilities:
    • List/get messages & threads, fetch attachments.
    • Build raw MIME messages (_build_message) supporting To/Cc/Bcc, attachments, and threading headers (In-Reply-To/References) so replies stay in the same Gmail conversation.
    • Draft lifecycle: create/get/update/send/delete drafts; resolve a Gmail message id to its draft id (get_draft_id) since the rest of the app standardizes on message ids.
    • Reply/forward as immediate sends (send_reply, send_forward) or as drafts in progress (create_reply_draft, update_reply_draft) — reply-all recipient logic excludes the sender and the signed-in user automatically.
    • Label/state mutations: read/unread toggle, star/unstar, archive/unarchive, trash/untrash, spam/not-spam, permanent delete — each with a bulk (batchModify) and single-message variant.
    • Gmail History API helpers (get_latest_history_id, get_messages_since_history_id) used by the auto-reply scheduler to find only genuinely new messages since the last check.
    • auto_reply_send — builds and sends a reply for the auto-reply pipeline.
  • Parser/ — three parsers producing different shapes of an email for different UI needs: cardEmailParser (dashboard preview cards), shortEmailParser (list views: inbox/sent/drafts), fullEmailParser (full email + thread detail view).
  • gmail.py — thin per-user helpers that look up the user's refresh token from MySQL, build a GmailService, and call it (get_5_emails, getEmail with thread assembly, get_account, toggle_auto_reply).
  • inbox_service.py, draft_service.py, sent_service.py, reply_service.py — the per-user, DB-token-lookup wrappers around specific GmailService operations, called both by REST controllers and by the AI agent's tool layer.
  • gmail_controller.py — the REST surface (/api/gmail/*): cards for the dashboard, inbox/sent/draft lists, single email + attachment download, draft CRUD + send, reply/forward/draft endpoints (multipart form-data with file attachments), star/read/ archive/trash/spam toggles (single + bulk), account info + auto-reply toggle, and the QALAM webhook.

3.6 AI Chat System (app/chatbot/)

Endpoint: POST /api/chatbot/ → chatbot_contoller.chat → run_chat_graph.

This is a small LangGraph state machine (agent_calling_graph.py):

  1. _detect_intents(prompt) — simple keyword-based classifier over the user's message:
    • Gmail-ish keywords (email, mail, reply, draft, inbox, trash, spam, archive, ...) → "gmail" intent.
    • Knowledge-ish keywords (document, pdf, embed, knowledge, rag, chunk, ...) → "knowledge" intent.
    • Neither → falls back to "retrieval" intent.
    • Both → "multi" (fan-out to multiple agents and combine results).
  2. Graph nodes route to one of three specialized LangChain agents (built with langchain.agents.create_agent, each its own ChatOpenAI(model="gpt-4.1-mini") instance bound to a curated tool list):
    • gmail_agent (gmail_tools) — everything mailbox-related: get/search inbox, drafts, sent; create/update/send/delete drafts; reply/forward/send; star/read/ archive/trash/spam/delete; also has access to preference tools. Includes a regex fast-path (_maybe_send_direct_email) that detects simple "send an email to x@y.com saying ..." requests and sends them directly without invoking the LLM agent loop, to save latency/cost for the common case.
    • knowledge_agent (knowledge_tools) — document retrieval (retrieval_from_docs tool over Pinecone), document management, and preferences.
    • RAG_agent.py — a generic retrieval agent (callagent) used for the "retrieval" fallback intent, and also exposes generate_auto_reply, the system prompt used specifically for the auto-reply pipeline (told to refuse/fallback rather than invent facts when it can't ground an answer in retrieved documents).
  3. Every agent call returns a normalized shape: content, token_usage, backend_details (agent name, tools used), tool_calls, and serialized messages. The LangGraph merges/accumulates these into a running Workflow state (conversation history, agents/tools called, token totals) and returns it to the controller, which returns it straight to the frontend as JSON.
  4. Conversation memory is per-(user_id, date) via LangGraph's in-memory MemorySaver checkpointer — so context resets daily and is not persisted across server restarts (despite the chat_threads/chat_messages tables existing in the schema).

Tool surface (agent/tools.py) is where LangChain @tool-decorated functions wrap the underlying services (gmail, draft, reply, inbox, preferences, embeddings, retrieval) — every mutating email tool call also writes an audit row via log_ai_email_action (the same audit table that powers /api/stats/dashboard/gmail).

Structured generation (agent/llm/):

  • prompts.py — three PromptTemplates: draft generation, "should this email get an auto-reply?" (boolean), and "write the reply body" — each paired with a Pydantic output parser (objects.py / structures.py: DraftEmail, ShouldReply, ReplyEmail).
  • llm_output_parsers.py — calls the LLM with those prompts and parses/repairs the JSON output (falls back gracefully if the model doesn't return perfectly valid JSON).
  • error_handling.py — turns Azure/OpenAI BadRequestErrors (e.g. content-filter trips) into a clean, user-facing fallback message instead of a 500.

3.7 Auto-reply pipeline (app/auto_reply/)

Designed to run on a schedule (schedular.py, APScheduler, every 10 minutes — currently disabled in main.py), or can be invoked directly:

  1. reply.py::autoReply() — finds every gmail_accounts row with auto_reply = TRUE and status = 'ACTIVE'.
  2. reply_service.py::reply_mails_by_user() — for each such user:
    • First run (or if >24h since last check) just baselines the Gmail History id and does nothing else (avoids replying to the user's entire mailbox history on first enable).
    • Otherwise, fetches messages since the last known history_id (get_messages_since_history_id) and hands them to the filter.
  3. filter.py::filter_and_send_messages() — for each new message not sent by the user themself:
    • Loads the user's preferences.
    • Asks the LLM shouldReply(email) — a strict "does this actually need a human-style reply?" classifier (deliberately says no to notifications, newsletters, receipts, OTPs, no-reply senders, spam, etc.).
    • If yes, generates a reply body with createReplyEmail (LLM, given the email, the user's identity, and their preferences as hard constraints) and sends it immediately via gmail.auto_reply_send (threaded into the original conversation).
    • Every attempt (success or failure) is logged to ai_email_actions.
  4. After processing, the account's last_history_id / last_auto_reply_check_at are updated so the next run only looks at genuinely new mail.

3.8 RAG / Document knowledge base (app/embeddings/, app/chatbot/agent/retrieval/)

  • Upload (POST /api/embed/, PDF only, frontend enforces ≤10MB): backend inserts a documents row (status='processing'), extracts text (pypdf, with a PyPDF2 fallback; .docx also supported at the extraction-function level), splits it with RecursiveCharacterTextSplitter (chunk size 500 / overlap 50), embeds each chunk via the HuggingFace Inference API (sentence-transformers/all-MiniLM-L6-v2, mean-pooled to a 384-dim vector), and upserts into Pinecone under a per-user namespace user_id_{user_id}_documents, with metadata including the source text (so retrieval doesn't need a second DB round-trip). Updates the documents row's chunk_count/ status afterward.
  • Delete — removes the Pinecone vectors for that doc's chunk-id range, then deletes the documents row.
  • List (GET /api/embed/) — simple listing of a user's uploaded documents and their processing status, shown in the frontend's "Add knowledge" page.
  • Retrieval tool (retrieval_from_docs) — a LangChain @tool used by both the knowledge_agent and the auto-reply's generate_auto_reply prompt: embeds the query with the same HF model, does a top-5 similarity search scoped to the user's Pinecone namespace, and returns concatenated chunk text (or "No relevant documents were found").

3.9 Preferences (app/preferences/)

Simple CRUD (GET/POST/PUT/PATCH/DELETE /api/preferences) over user_preferences. Each preference is a free-text name + value + enabled flag. These are surfaced to every AI agent (gmail, knowledge, retrieval, auto-reply) as tool-fetchable, hard-constraint context — every system prompt explicitly instructs the LLM to treat preferences as non-negotiable rather than optional style hints.

3.10 Search (app/search/)

GET /api/search/gmail?q=... performs a live Gmail API search (messages.list with the Gmail query string), fetches full message bodies for the results, and re-scores/filters them locally by simple term-matching against subject/ preview/body/participants (_score_email) before returning a sorted, capped list. Every search is logged to search_queries (log_search_query), and GET /api/search/recent returns the user's last few distinct queries for quick re-run suggestions.

3.11 Stats (app/stats/)

GET /api/stats/dashboard/gmail — three numbers computed from ai_email_actions: total AI actions, total auto-replies sent (reply_generated + completed), and "others" (the remainder) — rendered as colored stat pills on the frontend dashboard.

3.12 Notable backend quirks / current state

  • The APScheduler auto-reply job is commented out in main.py's startup/shutdown hooks — auto-reply as a continuously-running background feature is not currently wired to actually fire on its own; the code paths exist and work if invoked.
  • There are two duplicate/typo'd venv folders (venv/, vevn/) in backend/ — likely leftover from a rename; only one is presumably the active interpreter.
  • Two of the same email-list functions exist with slightly different call styles across files (a parse_recipients helper is defined identically in both app/gmail/DTO.py and inline inside gmail_controller.updateDraft).
  • Refresh tokens are stored as plain TEXT in MySQL (gmail_accounts.refresh_token) — no column-level encryption is applied in the code read.
  • chat_threads/chat_messages tables exist in the SQL schema but the live chat implementation does not currently write to them (conversation memory is process-local via LangGraph's MemorySaver).

4. Frontend (/frontend)

4.1 Stack

  • Next.js 16 (App Router, app/ directory), React 19.
  • Tailwind CSS 4 for styling (utility classes throughout, Gmail-like color palette: #1a73e8 blue, #ea4335 red, #34a853 green, #fbbc05 amber).
  • @react-oauth/google for the Google sign-in button/flow.
  • lucide-react for icons, recharts available (dashboard/stat visuals).
  • No global state library — each page/component manages its own useState/useEffect and talks directly to the backend via fetch.
  • Auth model: JWT stored in localStorage.access_token; every page/component that needs auth calls GET /api/auth/user on mount to verify the token and fetch the profile, redirecting to /login (or /) on failure. There is no shared auth context provider — this check is duplicated per page/component (Sidebar, page.js, inbox, chat, settings, etc.).
  • Backend base URL comes from NEXT_PUBLIC_API_BASE_URL (defaults to http://localhost:8000 if unset).

4.2 Routing map (app/)

Route File Purpose
/ page.js Root: checks auth, renders Home (dashboard) if logged in, else Nologin (redirects to /login)
/login login/page.js Google sign-in screen with marketing copy + OAuth button
/inbox inbox/page.js Gmail-like inbox list: filters (all/unread/starred/important/attachments/inbox/sent/draft), bulk select, bulk trash/delete, per-row nav to /email/{id}. Includes AgentAssistant floating chat widget
/sent sent/page.js Sent items list (same pattern)
/drafts drafts/page.js Draft list — likely supports editing/sending drafts in place (NewDraftPopup)
/email/[id] email/[id]/page.js Full email + thread detail view; reply/forward via ReplyBox
/chat chat/page.js Full-screen dedicated AI chat UI (dark theme) talking to POST /api/chatbot
/search search/page.js Gmail search UI backed by /api/search/gmail and /api/search/recent
/source source/page.js "Add knowledge" — PDF upload → embeddings management UI (list/upload/delete against /api/embed)
/settings settings/page.js Tabbed settings: Profile / Gmail Account / AI Preferences, plus logout (with a warning that logout disables auto-reply)
/profile profile/page.js User profile view/edit
/privacy, /terms static pages Legal copy linked from the login screen
layout.js — Root layout: wraps the app in GoogleOAuthProvider, renders the persistent Sidebar + main content area

4.3 Key components (app/components/)

  • Sidebar.jsx — persistent left nav (collapsible, mobile drawer variant). Performs its own /api/auth/user check and renders nothing if unauthenticated (so it disappears on the login page). Shows Dashboard / Add knowledge / Inbox / Sent / Draft / AI Assistant / Search / Settings, a Compose button, and the signed-in user's avatar initials + logout.
  • Home.jsx — the authenticated dashboard: welcome header, quick-nav cards (Inbox, Sent, Drafts, "Chat with AI"), live stat pills from /api/stats/dashboard/gmail, per-category preview cards from /api/gmail/card (last received/sent/drafts/ important), and embeds the full Preferences page inline at the bottom.
  • AgentAssistant.jsx — a reusable floating chat widget (bottom-right panel) embedded on content pages (inbox, etc.) that talks to POST /api/chatbot, shows suggested quick-action buttons, and surfaces "response diagnostics" (token usage, tools called, which agent handled the request) for transparency/debugging.
  • MessageCard.jsx — renders one of the dashboard's category preview cards (inbox/ sent/drafts/important) with its list of recent emails.
  • ReplyBox.jsx — the reply/forward composer used on the email detail page; talks to the reply/forward/draft multipart endpoints described in §3.5.
  • NewDraftPopup.jsx — compose-new / edit-draft modal, supports AI-assisted ("mode: ai") vs manual draft creation via POST /api/gmail/draft/create.
  • Preferences.jsx — full CRUD UI for user_preferences (search/filter by status, create/edit modal, enable/disable toggle switch, delete with confirmation) — used both standalone (Settings → AI Preferences) and embedded on the dashboard.
  • Gmail.jsx — "Gmail Account" settings panel (connection status, auto-reply toggle, presumably calls PATCH /api/gmail/account/auto-reply).
  • Profile.jsx — profile settings panel.
  • Nologin.jsx — redirect-only stub that sends unauthenticated visitors to /login.
  • ActionPill.jsx, Chip.jsx, DetailRow.jsx — small shared presentational primitives (badges/pills/detail rows) used across the email list/detail views.

4.4 Frontend/backend contract highlights

  • All list/detail Gmail data flows through the backend's parsers (Card_email_parser, Short_email_parser, parse_email_full) rather than raw Gmail API payloads, so the frontend gets consistent shapes (subject, from, to/cc, preview/body, labels, starred, unread, attachments, etc.).
  • Reply/forward/draft endpoints are intentionally all multipart/form-data (even with no attachments) for consistency, per explicit comments in gmail_controller.py.
  • The chat endpoints (/api/chatbot) return a rich payload (content, token_usage, tool_calls, backend_details, agents_called) that the frontend chat UIs use to show "diagnostics" (which agent/tools handled the request, token counts) alongside the plain-text reply.

5. Environment variables (as referenced in code)

Backend (backend/.env)

  • GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, REDIRECT_URI — Google OAuth app config.
  • SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES — JWT signing config.
  • DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME — MySQL connection.
  • HF_TOKEN, HF_MODEL (default sentence-transformers/all-MiniLM-L6-v2) — HuggingFace Inference API for embeddings.
  • PINECONE_API_KEY, PINECONE_INDEX_NAME — vector store.
  • EMAIL_VERIFICATION_API_KEY — static bearer-style key protecting the QALAM webhook.
  • LLM base URL is currently hard-coded in source (https://openai-rg-nadeem.openai.azure.com/openai/v1, model gpt-4.1-mini) rather than read from an env var — the API key for this presumably comes from a standard OPENAI_API_KEY picked up implicitly by langchain_openai.ChatOpenAI.

Frontend (frontend/.env)

  • NEXT_PUBLIC_API_BASE_URL — backend base URL (defaults to http://localhost:8000).
  • NEXT_PUBLIC_GOOGLE_CLIENT_ID — Google OAuth client id used by GoogleOAuthProvider/useGoogleLogin.

6. Summary judgement

This is a genuinely full-featured agentic Gmail assistant, not a toy demo:

  • Real Gmail read/write access via OAuth, covering essentially every mailbox action a webmail client needs.
  • A proper multi-agent LLM architecture (LangGraph router → specialized LangChain tool-calling agents) rather than a single monolithic prompt, with structured-output parsing and graceful error handling for content-filter/LLM failures.
  • A working RAG pipeline (PDF → chunks → HF embeddings → Pinecone) feeding both the interactive chat assistant and the fully autonomous auto-reply pipeline.
  • User-controllable "preferences" that are threaded through every agent as binding constraints, plus a full audit trail (ai_email_actions) of every AI-performed mailbox action, surfaced back to the user as dashboard stats.
  • A polished, Gmail-styled Next.js frontend covering the full CRUD surface (inbox, sent, drafts, compose/reply/forward, search, settings, document knowledge management) plus a dedicated full-screen AI chat page and an embeddable floating assistant widget.

The main things flagged as "unfinished/rough edges" rather than fundamental issues: the auto-reply scheduler is currently disabled at startup, chat history persistence tables exist but aren't wired up (memory is in-process only), and there's some minor code duplication/leftover artifacts (duplicate venv folder, a parse_recipients helper defined twice).


7. Anna AI OS Integration

Gmail Assistant Agent has been published as a live, user-facing App on Anna AI OS, qualifying it for the Anna AI App Builder Program (via DoraHacks).

What was done

  1. Environment setup & developer identity

    • Configured the local environment with uv (Python manager) and Node.js v22.
    • Established a developer namespace on Anna under the handle @nadeemmushtaq.
    • Authenticated the local environment with the Anna Partners network via device-flow login.
  2. App scaffolding & manifest configuration

    • Initialized the project with the Anna App CLI (anna-app).
    • Wrote a custom manifest.json (schema v2) defining the app's identity, permissions, and UI behavior.
    • Implemented a remote-URL bridge so the app loads the live-deployed Next.js frontend (https://gmail-assistant-eight.vercel.app) inside the secure Anna sandbox.
  3. Validation & publishing

    • Passed schema and ACL validation via the anna-app validate suite.
    • Staged and cut version 0.1.0, uploading the app bundle to Anna's infrastructure.
    • Published the app to the Anna Marketplace.

Official Anna App link

https://anna.partners/@nadeemmushtaq/gmail-assistant-agent

Program alignment

  • Fully runnable — a live, functional app inside Anna OS, not just a repository.
  • User-facing interface — the existing Next.js UI, running inside the Anna sandbox.
  • Backend logic — the same Python/FastAPI agentic backend described above.
  • Ready for MAU — prepared for Qualified App Runs via Anna's native execution infrastructure, for the Anna AI App Builder Program's September Launch Boost.

About

An intelligent LangGraph-powered Gmail Assistant that helps users manage their Gmail accounts using natural language. Users securely connect their Google account via OAuth, allowing the agent to read, organize, search, summarize, draft, and send emails on their behalf while respecting Google permissions.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages