Tutorial: The Email Workflow
Goal: run the platform's flagship pipeline and learn to read its telemetry — the skill you'll use every time a workflow misbehaves. 20 minutes.
Prereq: Your First Agent. Concept reference: Email Workflow.
1 · Create a fully-equipped agent
curl -X POST http://localhost:8001/agents/ -H "Content-Type: application/json" -d '{
"name": "Email Ops Pro",
"type": "Email Ops",
"system_prompt": "You handle inbound business email for an operations team.",
"enabled_tools": "email_analyzer,task_creator,reply_generator"
}'Note the id (assume 3). All three email tools granted — we'll remove them later to see behavior change.
2 · Run the pipeline
curl -X POST http://localhost:8001/agents/3/workflows/email \
-H "Content-Type: application/json" -d '{
"email_text": "Hi team, our staging environment has been down since this morning and we have a client demo tomorrow at 10am. Please restore it today and send me a confirmation. Also, can someone prepare a short incident summary for the client?",
"create_tasks": true
}' | jqExpect a multi-second wait — three sequential LLM calls. In the response, connect each field to its stage: analysis (stage 1), tasks_created (stage 2 — likely two tasks with priority: "high"), suggested_reply (stage 3 — notice it acknowledges the deadline, per the reply prompt), review (stage 4 — quality_score, issues).
3 · Read the flight recorder
curl http://localhost:8001/agents/3/workflow-runs | jq '.[0] | {id, status, quality_score}'
curl http://localhost:8001/agents/workflow-runs/<RUN_ID>/steps | jq \
'.[] | {step_name, status, latency_ms}'{"step_name": "analysis_agent", "status": "success", "latency_ms": 1740}
{"step_name": "task_agent", "status": "success", "latency_ms": 2}
{"step_name": "reply_agent", "status": "success", "latency_ms": 2210}
{"step_name": "reviewer_agent", "status": "success", "latency_ms": 1880}Read what the numbers teach: task_agent at ~2 ms is not an LLM (it's a Python loop — stage 2); the other three each cost a full OpenAI round trip. Now the costed tool calls:
curl http://localhost:8001/agents/3/tool-calls | jq \
'.[] | select(.estimated_cost != null) | {tool_name, estimated_tokens, estimated_cost}'Only the three LLM stages carry cost data — you're looking at the cost coverage map in the wild.
4 · Experiment: change the tool mix
| Experiment | Expected observation |
|---|---|
New agent with only email_analyzer → run workflow | no tasks (stage 2 skipped silently); reply falls back to the analysis's suggested_reply; trace has no task_agent step |
Same, create_tasks: false with all tools | stage 2 skipped by flag instead of by tool — same trace shape |
Agent without email_analyzer | 403 before any run is created — nothing in workflow-runs |
This is gate vs. enhancement semantics made visible.
5 · Break it and read the wreckage
Sabotage the key in backend/app/.env (as in the first tutorial), rerun the workflow, and observe the loud-failure path:
- HTTP
500with theValueErrorindetail. workflow-runs→ newest run:status: "failed",error_messagepopulated.- Its steps → a single
workflow_errorstep (stage 1 died first, so no stage steps precede it). tool-calls→ a failedmulti_agent_email_workflowentry.
Restore the key. Compare with chat's quiet failure — the three philosophies side by side.
6 · Close the loop on the dashboard
curl http://localhost:8001/agents/3/dashboard | jq \
'{total_workflow_runs, failed_workflow_runs, average_quality_score, estimated_total_cost}'Then open http://localhost:3000/dashboard pointed at this agent (set AGENTOPS_DASHBOARD_API_URL=http://localhost:8001/agents/3/dashboard for the frontend) — the numbers you generated, rendered (Observability).
What you learned
Stage anatomy and which stages are LLMs · reading run/step/tool-call telemetry to localize failures · tool gating vs. graceful degradation in a pipeline · advisory quality scoring. Next: RAG Tutorial.