Spaces:
Build error
Email Assistant β Full Project Walkthrough
Everything built so far, organized by component. Last updated: April 4, 2026.
1. Project Overview
The AI Email Assistant is an OpenEnv-compliant email triage and response environment built for the OpenEnv Hackathon. It wraps a production-grade FastAPI backend into a Gymnasium-style EmailEnv environment that AI agents can interact with, be benchmarked on, and scored against a dense reward rubric.
graph TD
A["Agent / LLM"] -- Action --> B["EmailEnv (OpenEnv)"]
B -- "Observations + Rewards" --> A
B -- "Internal Calls" --> C["EmailAssistantCore"]
C -- "AI Logic" --> D["AIEngine"]
C -- "Persistence" --> E["SQLite Memory"]
B -- "Task Logic" --> F["Task Handlers"]
B -- "Scoring" --> G["Rubric Graders"]
H["Next.js Frontend"] -- "HTTP" --> I["FastAPI Routes"]
I -- "Delegates" --> C
J["inference.py"] -- "OpenEnv Client" --> B
2. Backend β Core Application (app/)
2.1 Entry Point β main.py
- Creates a FastAPI app (
v1.0.0) with:- CORS middleware (all origins for dev)
- API routes from
app/routes.py - OpenEnv environment routes from
app/openenv_env/api.py - Optional static frontend mount at
/ui - Custom Swagger UI at
/docswith branded CSS - Health + root endpoints
2.2 Service Layer β core.py
The EmailAssistantCore class is the central service powering both HTTP routes and the OpenEnv environment directly. It provides:
| Method | Description |
|---|---|
fetch_emails() |
Fetches unread emails via IMAP and persists them to SQLite |
classify_email() |
Classifies email intent (Support/Sales/Spam/General) via AIEngine |
generate_reply() |
Drafts a reply with tone control + thread context from SQLite memory |
send_email() |
Sends via SMTP and records the result |
2.3 AI Engine β ai_engine.py
OpenAI API wrapper (AIEngine class) with:
- Async-friendly execution (runs sync OpenAI SDK in
asyncio.to_thread) - Retry with exponential backoff (3 attempts, 0.6s Γ 2^i delay)
classify_intent(): Structured JSON prompting β{intent, confidence, reasoning}generate_reply(): Context-aware reply generation with tone control (formal/casual/neutral)- Graceful fallback: Returns dummy responses when no valid API key is provided
- Auto-detects support for
responses.create(newer SDK) vschat.completions.create
2.4 Memory / Persistence β memory.py
SQLite-backed conversation memory with three tables:
| Table | Purpose |
|---|---|
emails |
Stores incoming emails (indexed by from_email + subject) |
generated_replies |
Stores AI-generated reply drafts |
sent_emails |
Logs sent email status (sent/failed) |
Key function: load_thread_context() β Retrieves chronological conversation history (user + assistant messages) for a given thread, enabling context-aware replies.
Auto-rebuilds corrupt/invalid SQLite databases on startup.
2.5 API Routes β routes.py
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/emails |
GET | Fetch unread emails via IMAP |
/classify |
POST | Classify email intent |
/generate-reply |
POST | Generate AI-powered reply |
/send |
POST | Send email via SMTP |
2.6 Supporting Modules
- schemas.py: Pydantic models for
EmailMessage,ClassifyRequest/Response,GenerateReplyRequest/Response,SendEmailRequest/Response,Tone,Intenttypes - classifier.py:
EmailClassifierwrapper aroundAIEngine.classify_intent() - email_reader.py: IMAP email fetcher (unread emails from inbox)
- email_sender.py: SMTP email dispatcher
- utils.py: Logging setup, subject normalization
3. OpenEnv Environment (app/openenv_env/)
This is the core innovation β the Gymnasium-style environment wrapper.
3.1 Environment β env.py (591 lines)
The EmailEnv class implements Environment[Action, Observation, EmailEnvState]:
Core API:
reset(task_id)β Returns initialObservationstep(action)/astep(action)β Returns(Observation, Reward, done, info)stateproperty β FullEmailEnvState
Action Handling:
| Action Type | What It Does |
|---|---|
classify |
Classifies email intent (tool-driven or agent-provided) |
prioritize |
Sets priority for a specific message |
reply |
Drafts a reply (tool-driven or agent-provided) |
send |
Sends the drafted reply (dry-run or live SMTP) |
skip |
Skips email (optionally escalates) |
Reward System β Multi-Dimensional Dense Rewards:
reward = 0.3 Γ classification_score + 0.3 Γ priority_score + 0.3 Γ reply_score β penalties
Penalties include: unnecessary duplicate actions, wrong send target, delay/SLA violations, escalation, errors.
Features:
- Simulated time tracking (each action costs time: classify=1min, reply=4min, etc.)
- SLA deadline enforcement with urgency scoring
- Deterministic mode (no LLM needed) + Live mode (uses
EmailAssistantCore) - Dry-run send mode for evaluation
3.2 Tasks β tasks.py
Three benchmark tasks with hardcoded email fixtures:
| Task ID | Difficulty | Description | Max Steps |
|---|---|---|---|
easy_classification |
Easy | Classify a single email (expected: "Support") | 4 |
medium_prioritization |
Medium | Pick most urgent from 3 emails (invoice w/ 60min deadline) | 5 |
hard_workflow |
Hard | Full workflow: classify 2 emails β prioritize β draft β send for VIP outage | 10 |
3.3 Models β models.py
Rich type system built on Pydantic + OpenEnv base types:
Action(type + payload dict)Observation(current email, inbox summary w/ deadlines + urgency, action history, step count, time elapsed)InboxSummaryItem(message_id, urgency_score, deadline_minutes, predicted_intent, handled status)Reward/RewardComponents(classification, priority, reply scores + penalty dict)EmailEnvState(full state: task, time, intents, drafts, sent, history)StepInfo/StepResult(episode-level scoring)
3.4 Graders β graders.py
Scoring functions:
grade_classification(predicted, expected)β 0.0 or 1.0 exact matchgrade_priority(chosen, expected)β 0.0 or 1.0grade_reply(body, keywords)β 0.0β1.0 based on keyword coverage
3.5 Deterministic Engine β deterministic_engine.py
Keyword-based, no-LLM classification and reply generation for reproducible evaluation. Enables running the full pipeline without an OpenAI API key.
3.6 API Router β api.py
FastAPI router exposing the OpenEnv environment at /openenv/*:
POST /openenv/resetβ Reset environmentPOST /openenv/stepβ Execute actionGET /openenv/stateβ Get current state
4. Extended Server Environment (server/)
my_environment.py (427 lines)
A secondary environment (MyEmailEnvironment) extending EmailEnv with:
- Custom
EmailAssistantRubric(categorize: +0.10, respond: +0.50, move_email: +1.00, skip: β0.10, etc.) - Simulated inbox loaded from
server/simulated_emails.jsonor programmatic fallback - Extended action types:
categorize,respond,create_folder,move_email,tag_email,schedule,archive,delete - Inbox-zero done condition
- Full state tracking via
EmailAssistantStatedataclass
5. Client & Inference
5.1 Client β client.py
EmailAssistantEnvClient extending OpenEnv's EnvClient:
- Serializes
Actionβ JSON for step payloads - Parses server responses β
StepResult[Observation] - Parses state β
EmailEnvState
5.2 Inference Script β inference.py
Full evaluation loop that:
- Connects to the running environment server
- Runs all 3 tasks (easy β medium β hard) or a specific task
- Uses OpenAI GPT-4o-mini for action selection (with structured JSON prompting)
- Falls back to deterministic policy when no API key is available
- Logs step-level and episode-level metrics
- Reports average reward across all episodes
CLI options: --base-url, --episodes, --max-steps, --model, --task
6. Frontend (frontend/)
6.1 Framework
Next.js app with:
- TypeScript
- Tailwind CSS + custom CSS variables
date-fnsfor relative timestamps
6.2 Design System β globals.css
Premium "Elite Concierge" glassmorphic design:
| Token | Light | Dark |
|---|---|---|
| Background | #F9F7F3 (warm off-white) |
#0A0A0B (deep black) |
| Primary | #C49A6C (warm gold) |
#E2C28B (soft gold) |
| Accent | #9B59B6 (purple) |
#C39BD3 (lavender) |
| Surface | White glass (80% opacity) | Dark glass (60% opacity) |
Typography: Playfair Display (headings), Inter (body), JetBrains Mono (code)
Components: .glass-card, .glass-panel, .btn-primary, .btn-outline, .btn-icon, .luxury-input, .luxury-tag
All with smooth animations, hover effects, glassmorphism (backdrop-filter blur), and custom scrollbars.
6.3 Main Page β page.tsx
Single-page Luxury Concierge email client:
- Header: "Elite Concierge β Executive Inbox" with tab navigation (Inbox / Concierge)
- Sidebar: Email list with sender, subject, body preview, relative timestamps, intent badges + confidence %
- Main Panel: Selected email details with:
- "Engage Concierge" button β auto-classifies + drafts reply
- AI reasoning display
- Full email body
- Composition area with editable draft
- "Dispatch Securely" send button
- Toast notifications with animated pulse dot
- Decorative blur orbs for premium atmosphere
Integrates with backend via: /emails, /classify, /generate-reply, /send
7. Extended Backend (backend/)
A separate, more production-focused backend with:
| Directory | Purpose |
|---|---|
app/api/v1, app/api/v2 |
Versioned API routers |
app/core/ |
Core business logic |
app/services/ |
16 service modules (see below) |
app/db/ |
Database layer |
app/schemas/ |
Pydantic schemas |
app/security/ |
Authentication & authorization |
app/middleware/ |
Request middleware |
app/observability/ |
Monitoring & logging |
app/repositories/ |
Data access layer |
app/workers/ |
Background workers |
app/errors/ |
Error handling |
alembic/ |
Database migrations |
Backend Services (backend/app/services/)
| Service | Description |
|---|---|
agent_tools.py |
AI agent tool definitions |
attachments.py |
Attachment handling |
autopilot.py |
Automated email processing |
classifier.py |
Email classification |
evaluation.py |
Performance evaluation |
events.py |
Event system |
gmail_api.py |
Gmail API integration |
graph_api.py |
Microsoft Graph API |
imap_legacy.py |
Legacy IMAP support |
llm.py |
LLM integration |
niche.py |
Specialized processing |
prioritizer.py |
Email prioritization |
rag_service.py |
RAG-based knowledge retrieval |
safety.py |
Content safety checks |
smtp_send.py |
SMTP sending |
8. OpenEnv Client Package (email_assistant_env/)
Standalone Python package for interacting with the environment:
- client.py β Environment client
- models.py β Shared data models
- pyproject.toml β Package configuration
- README.md β Documentation
server/β Server-side environment utilities
9. Deployment & Configuration
9.1 Docker β Dockerfile
Multi-stage build:
- Builder stage: Python 3.11-slim +
uvfor fast dependency install - Runtime stage: Copies installed packages, exposes port 8000
- Health check:
curl -f http://localhost:8000/health - Entry:
uvicorn app.main:app --host 0.0.0.0 --port 8000
9.2 OpenEnv Config β openenv.yaml
Full OpenEnv-compliant configuration with:
- Hugging Face Spaces metadata (emoji: π§, SDK: docker)
- Action space schema (
ClassifyEmailAction,DraftReplyAction,RequestMoreInfoAction,EscalateAction) - Observation space schema
- Dense reward definition with component weights
- Task definitions (3 difficulty levels)
9.3 Environment Variables
Configured via .env:
OPENAI_API_KEYβ For AI classification and reply generation- IMAP/SMTP credentials β For live email integration
- SQLite path β For conversation memory
- Model selection β Default:
gpt-4o-mini
10. Summary of Key Innovations
- Multi-Dimensional Dense Reward Rubric: Beyond binary correct/incorrect β rewards classification precision (1.0), reasoning quality (0.2), tone compliance (0.3), workflow efficiency (β0.01/step), full resolution (2.0)
- Dual Mode: Deterministic (keyword-based, no API key needed) + Live (OpenAI GPT-4o-mini)
- SLA-Aware Time Simulation: Each action costs simulated time; deadline breaches incur penalties
- Thread Memory: SQLite-backed conversation context for coherent multi-turn interactions
- Premium UI: Glassmorphic "Elite Concierge" interface with luxury design tokens
- Full Pipeline: classify β prioritize β draft β send, all within a Gymnasium-style reset/step loop