igerasimov's picture
MVP Milestone 4
0539596
Raw
History Blame Contribute Delete
2.15 kB
"""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."""