How we built the Email Triage demo
Read an inbound email once, and come out the other side with a category, an urgency level, who should own it, and a draft reply — the four decisions a human triaging a shared inbox actually makes.
The problem
A shared inbox mixes sales inquiries, support tickets, complaints, spam, and the occasional legal notice. Triage isn't one decision — it's classify, prioritize, route, and often draft a first response, all before anyone with the right context has read the message.
One call, five decisions
Rather than chain separate classify → route → draft calls, the route asks for one JSON object with all five fields at once: category, urgency, sentiment, routing destination, a one-line summary, a suggested reply, and extracted key entities. Fewer round trips, and the fields stay consistent with each other since one call reasons about all of them together.
Every field is a closed enum, not free text
category: Sales | Support | Complaint | Partnership | Spam | Internal | Invoice | Legal
urgency: low | medium | high | critical
sentiment: positive | neutral | negative | frustrated | urgent
routeTo: Sales | Support | Finance | Legal | Management | Spam | HR
Why enums, not open categories
An open-ended "category": string field looks more flexible, but it pushes the hard part downstream: whatever consumes this output — a routing rule, a dashboard filter, a ticketing integration — now has to handle arbitrary strings a model might invent. Naming the exact set of allowed values in the prompt turns validation into a one-line membership check instead of fuzzy string matching against however the model phrased something this time. It's a small constraint that removes an entire category of downstream bugs.