"""The triage verdict exchanged with the intake-gate model. Pure module: no FastAPI imports and no HTTPException. ``extra="forbid"`` is load-bearing — it emits ``additionalProperties: false``, which the structured-outputs schema dialect requires (same reason as app/models/scoring.py:22-23). Every field is required: structured outputs puts all declared properties in ``required``, so a defaulted field buys nothing here. Mirrors agent/models.py — this package's models.py holds the shape the LLM pass exchanges, not a SQLModel table. The triage TABLE lives in inbox/models.py beside Inbox_Messages, because it is an inbox-domain fact and this package never opens a session. """ from __future__ import annotations from pydantic import BaseModel, ConfigDict, Field from inbox_classifier.enums import Triage_Reason_Code class EmailTriageVerdict(BaseModel): """One intake decision about one email. ``confidence`` carries the model's doubt so the boolean does not have to. The prompt tells it to answer the boolean the way a recruiter would want and to report uncertainty here instead, which is what makes INBOX_TRIAGE_MIN_CONFIDENCE a usable knob rather than a second, contradictory gate. reason_code is the Triage_Reason_Code enum rather than a Literal, so the labels live in one place; Pydantic renders it as the same JSON-schema enum either way. """ model_config = ConfigDict(extra="forbid") is_application: bool reason_code: Triage_Reason_Code confidence: float = Field(ge=0.0, le=1.0) # One clause naming the signal used. Stored for the review screen, never logged: # the model is told not to quote personal data, but it is still model-authored # text derived from an email body. evidence: str = Field(min_length=1, max_length=200)