Skip to content
3 min read · 635 words

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

bash
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

bash
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
}' | jq

Expect 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

bash
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}'
json
{"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:

bash
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

ExperimentExpected observation
New agent with only email_analyzer → run workflowno 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 toolsstage 2 skipped by flag instead of by tool — same trace shape
Agent without email_analyzer403 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 500 with the ValueError in detail.
  • workflow-runs → newest run: status: "failed", error_message populated.
  • Its steps → a single workflow_error step (stage 1 died first, so no stage steps precede it).
  • tool-calls → a failed multi_agent_email_workflow entry.

Restore the key. Compare with chat's quiet failure — the three philosophies side by side.

6 · Close the loop on the dashboard

bash
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.