Schemas — schemas.py
Pydantic models define the HTTP contract: what FastAPI accepts (request schemas) and what it serializes back (response schemas with from_attributes = True).
Purpose
backend/app/schemas.py is the single source of request/response shapes. Request schemas reject malformed bodies with 422 before handlers run; response schemas (declared via response_model=) filter ORM objects down to the public contract.
Conventions
- Response schemas set
class Config: from_attributes = Trueso FastAPI can serialize SQLAlchemy objects directly. - Optionality is expressed as
field: T | None = None; defaults mirror the ORM defaults (language="English",tone="Professional",top_k=3). - Naming:
XCreate/XRequestfor inputs,XResponsefor outputs.
Schema catalog
Agents & chat
| Schema | Direction | Fields |
|---|---|---|
AgentCreate | request | name, type, description?, system_prompt, language="English", tone="Professional", enabled_tools="" |
AgentResponse | response | all of the above + id, created_at |
ChatRequest | request | message: str |
ChatResponse | response | agent_id, user_message, assistant_response, run_id, latency_ms |
MessageResponse | response | id, agent_id, role, content, created_at |
AgentRunResponse | response | id, agent_id, input_text, output_text?, latency_ms?, status, error_message?, created_at |
Email & tasks
| Schema | Direction | Fields |
|---|---|---|
EmailAnalyzeRequest | request | email_text: str |
EmailAnalysisResponse | (declared, unused as response_model) | summary, intent, priority: Literal["low","medium","high","urgent"], deadline?, action_items: list[str], suggested_reply |
TaskResponse | response | id, agent_id, title, description?, priority, status, due_date?, source_type, created_at |
TaskStatusUpdate | request | status: str (validated in the handler against open/in_progress/completed) |
EmailAnalysisResponse allows "urgent", but the analysis prompt instructs the model to use only low | medium | high — and the endpoint returns the analysis as a raw dict anyway (no response_model), so this Literal is never enforced in practice. Logged in Known Issues.
Tool calls
ToolCallResponse — id, agent_id, agent_run_id?, tool_name, tool_input?, tool_output?, success: str, error_message?, latency_ms?, created_at, model_name?, estimated_tokens?, estimated_cost?. Mirrors the ToolCall model exactly, string-typed success included.
Documents & RAG
| Schema | Direction | Fields |
|---|---|---|
DocumentResponse | response | id, agent_id, filename, file_type, status, chunks_count, created_at |
DocumentChunkResponse | response | id, document_id, agent_id, chunk_text, chunk_index, created_at |
DocumentSearchRequest | request | query: str, top_k: int = 3 |
DocumentSearchResult | nested | chunk_text, score?, document_id, filename, chunk_index |
DocumentSearchResponse | response | query, results: list[DocumentSearchResult] |
RAGAnswerRequest | request | question: str, top_k: int = 3 |
RAGSource | nested | filename, document_id, chunk_index, score? |
RetrievalEvaluation | nested | has_answer: bool, confidence: float, reason: str |
RAGAnswerResponse | response | question, answer, sources: list[RAGSource], retrieval_evaluation? |
Workflows
| Schema | Direction | Fields |
|---|---|---|
MultiAgentEmailWorkflowRequest | request | email_text: str, create_tasks: bool = True |
WorkflowReviewResponse | nested | approved: bool, quality_score: float, issues: list[str], recommendation: str |
MultiAgentEmailWorkflowResponse | response | email_text, analysis: dict, tasks_created: list[TaskResponse], suggested_reply, review: WorkflowReviewResponse |
WorkflowRunResponse | response | id, agent_id, workflow_name, input_text, final_output?, status, quality_score?, error_message?, created_at |
WorkflowStepResponse | response | id, workflow_run_id, step_name, input_data?, output_data?, status, latency_ms?, error_message?, created_at |
Note analysis: dict — the analysis JSON is passed through untyped, so its shape is guaranteed only by the prompt contract, not by Pydantic.
Dashboard & stats
AgentDashboardResponse — the aggregated metrics contract the frontend dashboard renders: task counts (total/open/in_progress/completed), tool-call counts (total/successful/failed), workflow counts, average_latency_ms?, estimated_total_tokens, estimated_total_cost: str, average_quality_score?. See Observability.
AgentStatsResponse — declared for the stats endpoint but inconsistent with what the handler returns (and agent_name is typed int); that endpoint is broken practice code — see Known Issues.
Validation examples
# Missing required field → 422 with field pointer
curl -X POST http://localhost:8001/agents/ -H "Content-Type: application/json" -d '{"name": "X"}'{
"detail": [
{"type": "missing", "loc": ["body", "type"], "msg": "Field required"},
{"type": "missing", "loc": ["body", "system_prompt"], "msg": "Field required"}
]
}The frontend proxy flattens this array shape into a single message for the UI — see API Proxy.
Future improvements
- Enforce
EmailAnalysisResponseas the analysisresponse_model(and align the Literal with the prompt). - Replace
analysis: dictwith the typed schema. - Add
Fieldconstraints (max_lengthon names,ge=1ontop_k).
Related files
- ORM Models — the persistence twin of these shapes
- API Reference — the endpoints these schemas bind to