Skip to content
3 min read · 657 words

Request Lifecycle

This page traces POST /agents/{id}/chat — the canonical request — through every layer, then shows how the other endpoint families differ.

Chat request, end to end

Rendering diagram…

The exact code path

  1. Route match & validation. FastAPI matches POST /agents/{agent_id}/chat; the body must satisfy schemas.ChatRequest (a single required message: str) or FastAPI returns 422 before the handler runs.
  2. Session injection. db: Session = Depends(get_db) opens a session from SessionLocal; get_db() guarantees db.close() in its finally block (Database Layer).
  3. Agent lookup. Missing agent → 404 Agent not found. This guard opens nearly every endpoint in the codebase.
  4. Persist the user message (added to the session; committed later).
  5. LLM call inside try/except. generate_agent_response composes the runtime system prompt from the agent's stored system_prompt, language, and tone (Prompt Catalog) and calls OpenAI at temperature 0.3. On any exception the handler substitutes the fallback text and captures status="failed" + error_message — the request still succeeds.
  6. Persist the assistant message and the AgentRun with wall-clock latency_ms measured around the whole handler.
  7. Single db.commit() flushes user message, assistant message, and run atomically, then the ChatResponse is returned.

A failed LLM call still produces a well-formed conversation turn and a recorded failed run. The client sees the fallback text; operators see the real error in GET /agents/{id}/runs. Contrast this with the tool/workflow endpoints below, which return 500 on failure. Rationale in Error Handling.

How other endpoint families differ

FamilyExtra steps vs. chatFailure mode
CRUD reads (GET /agents, /tasks, /runs, …)None — fetch, serialize via response_model404 if the parent agent is missing
Email analyze (POST .../email/analyze)Tool gate (email_analyzer required, else 403) → LLM analysis → optional task creation → 1–2 ToolCall logs500 + failed ToolCall logged
Multi-agent workflow (POST .../workflows/email)Creates a WorkflowRun first (status="running"), then logs a WorkflowStep + ToolCall per stage, finalizes run status/quality500; run marked failed; error step logged
Document upload (POST .../documents/upload)File-type/encoding guards (400) → chunk → embed each chunk → write SQLite + Chroma400 for bad input; embedding errors propagate as 500
RAG ask (POST .../documents/ask)Tool gate (document_search) → LangGraph graph (retrieve → evaluate → answer/refuse) → ToolCall log500 + failed ToolCall logged

Full traces for the workflow and RAG pipelines are in Data Flow.

Latency anatomy

For a typical chat request, nearly all time is the OpenAI round trip:

SegmentTypical share
FastAPI routing + Pydantic validation~1 ms
SQLite queries (lookup + 3 inserts + commit)a few ms
OpenAI chat completion500–3000 ms

This is why latency_ms on AgentRun/ToolCall is effectively an LLM latency metric — and why the multi-agent workflow (3 sequential LLM calls) takes several seconds. Performance discussion: Design Decisions.