Multi-Agent Email Workflow
One email in; structured analysis, persisted tasks, a drafted reply, and a 0–1 quality verdict out — with a complete trace of every stage.
POST /agents/{id}/workflows/email · handler: run_multi_agent_email_workflow in routers/agents.py · agents: multi_agent_email_service
Request & gating
{ "email_text": "…", "create_tasks": true }| Guard | Failure |
|---|---|
| Agent exists | 404 |
Agent has email_analyzer | 403 — the workflow's entry ticket |
Then a WorkflowRun (multi_agent_email_workflow, status="running") is created and committed before any stage runs.
The four stages
Stage 1 — Analysis Agent (LLM, temp 0.2)
Delegates to analyze_email — the same strict-JSON extraction used by the single-agent endpoint. Its output shape drives everything downstream. Persisted: analysis_agent step + multi_agent_analysis_agent ToolCall with cost estimates.
Stage 2 — Task Agent (deterministic, conditional)
Runs only when create_tasks=true and the agent has task_creator. For each action_item, a Task is built with the analysis's priority, a description citing the intent, and a deadline sanitized by normalize_due_date (keeps "today"/"tomorrow"-style words, drops past ISO dates, passes other text through). No LLM — the "agent" is a loop. Persisted: task_agent step + multi_agent_task_agent ToolCall (uncosted, correctly).
Stage 3 — Reply Agent (LLM, temp 0.3, with fallback)
With reply_generator enabled, run_reply_agent drafts a fresh professional reply seeing both the raw email and the analysis. Without it, the workflow falls back to the analysis's own suggested_reply — the stage never leaves the response empty. Persisted either way: reply_agent step + costed ToolCall.
Stage 4 — Reviewer Agent (LLM, temp 0)
Tasks are committed and refreshed first (so the reviewer sees real IDs), then run_reviewer_agent judges the entire package:
{ "approved": true, "quality_score": 0.92, "issues": [], "recommendation": "…" }The verdict is advisory — nothing is blocked or rolled back on rejection (Evaluation). Persisted: reviewer_agent step + costed ToolCall.
Finalization
WorkflowRun gets status="success", quality_score=str(review.quality_score), and a final_output JSON snapshot (analysis, tasks with IDs, reply, review). The HTTP response mirrors that snapshot as MultiAgentEmailWorkflowResponse.
Tool gating summary
| Tool on agent | Effect |
|---|---|
email_analyzer | required — 403 without it |
task_creator | stage 2 runs (when create_tasks=true) |
reply_generator | stage 3 uses the dedicated Reply Agent instead of the fallback |
Mix and match per agent — see Tools.
Failure semantics
Any exception in any stage triggers the triple record — failed multi_agent_email_workflow ToolCall, run flipped to failed with the error, workflow_error step — then 500. Stages already persisted keep their records, so the trace shows exactly how far the pipeline got. Note one consequence: tasks committed in stage 2 survive a stage-3/4 failure.
Single-agent vs. multi-agent
POST .../email/analyze | POST .../workflows/email | |
|---|---|---|
| LLM calls | 1 | 3 |
| Reply | analysis's suggested_reply only | dedicated Reply Agent (or fallback) |
| Quality verdict | none | reviewer score + issues |
| Tracing | ToolCalls only | full WorkflowRun + steps |
| Cost logging | ❌ | ✅ per LLM stage |
| Latency | ~1–3 s | ~3–9 s |
Rule of thumb: analyze for cheap triage, the workflow when you want a send-ready reply with a quality check and a full audit trail.
Related pages
- Workflows Overview — the engine
- Prompt Catalog — all three prompts verbatim
- Email Workflow Tutorial — run it yourself
- API Reference: Workflows — full contracts