| """Pydantic schemas for structured model responses.""" |
|
|
| from pydantic import BaseModel, ConfigDict, Field, model_validator |
|
|
| from gcmd_classifier.models import SupportType |
|
|
|
|
| class CandidateDecision(BaseModel): |
| """One model-selected application-supplied candidate.""" |
|
|
| model_config = ConfigDict(extra="forbid", frozen=True) |
|
|
| candidate_id: str = Field(min_length=1) |
| confidence: float | None = Field(default=None, ge=0.0, le=1.0) |
| evidence: str = Field(min_length=1) |
| support_type: SupportType |
| reason: str | None = None |
|
|
|
|
| class TopicResponse(BaseModel): |
| """Structured multi-label Topic routing response.""" |
|
|
| model_config = ConfigDict(extra="forbid", frozen=True) |
|
|
| selected: list[CandidateDecision] = Field(default_factory=list) |
| ambiguous_alternatives: list[str] = Field(default_factory=list) |
| no_selection_reason: str | None = None |
|
|
|
|
| class _ChildSelectionResponse(BaseModel): |
| """Shared response invariants for Term and Variable-level descent decisions.""" |
|
|
| model_config = ConfigDict(extra="forbid", frozen=True) |
|
|
| selected: list[CandidateDecision] = Field(default_factory=list) |
| stop_at_parent: bool |
| stop_reason: str | None = None |
| ambiguous_alternatives: list[str] = Field(default_factory=list) |
|
|
| @model_validator(mode="after") |
| def validate_stop_and_selection_invariants(self) -> "_ChildSelectionResponse": |
| """Reject contradictory child-selection responses before orchestration can use them.""" |
| if self.stop_at_parent and self.selected: |
| raise ValueError("stop_at_parent=true requires selected to be empty") |
| if self.selected and self.stop_at_parent: |
| raise ValueError("non-empty selected requires stop_at_parent=false") |
| if self.stop_at_parent and not self.stop_reason: |
| raise ValueError("stop_at_parent=true requires a non-empty stop_reason") |
| return self |
|
|
|
|
| class TermResponse(_ChildSelectionResponse): |
| """Structured Term routing response beneath a selected Topic.""" |
|
|
|
|
| class VariableResponse(_ChildSelectionResponse): |
| """Structured Variable-level descent response beneath a selected parent.""" |
|
|