Spaces:
Build error
Build error
| """ | |
| schemas.py β Pydantic models for all API inputs and outputs. | |
| Design choice: Every external boundary (request in, response out) is typed and validated | |
| via Pydantic. This gives automatic HTTP 422 errors on malformed input without writing | |
| any validation logic by hand, and makes the contract explicit and machine-readable. | |
| Interview Q: "Why Pydantic over dataclasses?" | |
| A: Pydantic models give JSON serialization, validation, and OpenAPI schema generation | |
| for free. Dataclasses require manual validators and don't integrate with FastAPI's | |
| schema generation. | |
| Trade-off: Pydantic v2 is stricter and faster than v1, but we use v1-compatible syntax | |
| (model_validator, Field) for broader compatibility with HF Spaces base images. | |
| """ | |
| from typing import List, Optional | |
| from pydantic import BaseModel, Field, field_validator | |
| class Message(BaseModel): | |
| """ | |
| A single turn in the conversation. | |
| role must be 'user' or 'assistant' β anything else is rejected at the boundary. | |
| content must be a non-empty string. | |
| """ | |
| role: str = Field(..., description="'user' or 'assistant'") | |
| content: str = Field(..., min_length=1, description="Turn content, non-empty") | |
| def role_must_be_valid(cls, v: str) -> str: | |
| # Explicit allowlist keeps prompt-injection via role spoofing out. | |
| if v not in ("user", "assistant"): | |
| raise ValueError("role must be 'user' or 'assistant'") | |
| return v | |
| class ChatRequest(BaseModel): | |
| """ | |
| Stateless chat request: the caller sends the FULL conversation history on every call. | |
| No session IDs, no server-side memory. | |
| Design rationale: statelessness makes the service trivially horizontally scalable | |
| and removes any sticky-session / cache-invalidation complexity. | |
| """ | |
| messages: List[Message] = Field( | |
| ..., | |
| min_length=1, | |
| description="Full conversation history; must contain at least one message." | |
| ) | |
| class Recommendation(BaseModel): | |
| """ | |
| A single catalog item returned to the caller. | |
| Only fields that exist in the catalog are returned β no hallucinated metadata. | |
| """ | |
| name: str | |
| url: str | |
| test_type: str | |
| class ChatResponse(BaseModel): | |
| """ | |
| Exact schema the SHL evaluator expects. | |
| - reply: the agent's natural-language response. | |
| - recommendations: [] when clarifying or refusing; 1β10 items when shortlisting. | |
| - end_of_conversation: True when the agent detects the conversation is complete. | |
| """ | |
| reply: str | |
| recommendations: List[Recommendation] = Field(default_factory=list) | |
| end_of_conversation: bool = False | |