Pritoo/my-openenv-email-env
Email Classification Environment
An OpenEnv environment that simulates email triage — classifying incoming emails as spam or important. The agent must learn to identify phishing/junk emails vs. legitimate work emails using contextual signals like urgency, links, and content keywords.
Environment Overview
Action Space
`MyAction` — a Pydantic model with one field:
Observation Space
`MyObservation` — returned after every step() and reset():
Task Difficulties
The environment supports three difficulty levels, randomly selected on reset():
Easy (3 steps)
- Emails: Only high-signal emails (spam with links, important with urgency ≥ 0.8)
- Rewards: +1.0 correct, −0.25 incorrect
- Bonuses: Full bonuses for catching spam-with-links (+0.5) and urgent emails (+0.5)
- Streak: Enabled (+0.1 × consecutive correct)
Medium (5 steps)
- Emails: All emails in the dataset
- Rewards: +1.0 correct, −0.5 incorrect
- Bonuses: Full bonuses
- Streak: Enabled
Hard (7 steps)
- Emails: All emails (including ambiguous ones)
- Rewards: +0.5 correct, −1.0 incorrect
- Bonuses: Halved (×0.5)
- Streak: Disabled
- Penalty: −1.0 for missing urgent important emails
Reward Function
The reward is multi-signal and provides partial progress feedback:
- Base reward: Correct/incorrect classification (varies by difficulty)
- Spam-with-link bonus: Extra reward for correctly flagging spam that contains links
- Urgent important bonus: Extra reward for correctly keeping urgent important emails
- Missed-urgent penalty: Penalty for misclassifying urgent important emails as spam
- Streak bonus (easy/medium only): Incremental reward for consecutive correct classifications
The final episode score (from the grader) is:
score = clamp(0.7 × accuracy + 0.3 × avg_reward, 0.0, 1.0)Quick Start
Running Locally
# Install dependencies
pip install -r requirements.txt
# Start the server
uvicorn server.app:app --reloadThe web UI is available at http://localhost:8000/web.
Using the Client
from client import MyEnv
from models import MyAction
with MyEnv(base_url="http://localhost:8000").sync() as client:
state = client.reset()
for _ in range(5):
# Classify the email
action = MyAction(action_type="spam") # or "important"
result = client.step(action)
print(f"Email: {result.observation.email}")
print(f"Reward: {result.observation.reward}")
if result.observation.done:
breakRunning the Baseline Agent
The included baseline agent (client.py) uses keyword matching to classify emails:
# Start the server first, then:
python client.pyThe baseline agent checks for spam keywords (win, free, offer, lottery, click) and important keywords (meeting, project, invoice, deadline) to make classification decisions.
Building & Deploying
Docker
# Build
docker build -t email-agent-env:latest .
# Run
docker run -p 7860:7860 email-agent-env:latestHugging Face Spaces
# Deploy using openenv CLI
openenv push
# Or with options
openenv push --repo-id your-username/email-agent-env --privateAfter deployment, the Space will be available at https://huggingface.co/spaces/<repo-id> with:
- Web Interface at
/web - API Docs at
/docs - WebSocket at
/ws
Project Structure
my-openenv-email-env/
├── openenv.yaml # OpenEnv manifest (tasks, entry point)
├── models.py # Pydantic models: MyAction, MyObservation, State
├── emails.csv # Email dataset (text, label, has_link, urgency)
├── email_loader.py # CSV/Gmail email data loader
├── client.py # Baseline agent + EnvClient
├── grader.py # Episode grader (score clamped to 0.0–1.0)
├── Dockerfile # Container for HF Spaces (port 7860)
├── requirements.txt # Python dependencies
├── __init__.py # Module exports
└── server/
├── app.py # FastAPI app with /web UI and /api endpoints
└── my_env_environment.py # Core environment logic (step/reset/state)Dataset
The environment uses emails.csv with 10 pre-labeled emails:
An optional Gmail loader (load_from_gmail()) is available for real email data but defaults to CSV for consistent grading.
