| from __future__ import annotations |
|
|
| from typing import Literal |
|
|
| from pydantic import BaseModel, ConfigDict, Field, field_validator |
|
|
|
|
| class StrictModel(BaseModel): |
| model_config = ConfigDict(extra="forbid", str_strip_whitespace=True) |
|
|
|
|
| class Clearing(StrictModel): |
| creature: str = Field(min_length=3, max_length=80) |
| strength: str = Field(min_length=3, max_length=100) |
| line: str = Field(min_length=12, max_length=360) |
| reflection: str = Field(min_length=12, max_length=260) |
| spell: str = Field(min_length=3, max_length=80) |
| image_prompt: str = Field(min_length=8, max_length=300) |
|
|
| @field_validator("spell") |
| @classmethod |
| def validate_spell(cls, value: str) -> str: |
| if not value.lower().startswith(("i ", "i'm ", "i am ")): |
| raise ValueError("spell must be a first-person present-tense mantra") |
| if len(value.split()) > 12: |
| raise ValueError("spell must contain at most 12 words") |
| return value |
|
|
|
|
| class ForestDraft(StrictModel): |
| forest_title: str = Field(min_length=3, max_length=120) |
| proposed_strengths: list[str] = Field(min_length=3, max_length=6) |
| clearings: list[Clearing] = Field(min_length=1, max_length=6) |
|
|
| @field_validator("proposed_strengths") |
| @classmethod |
| def validate_unique_strengths(cls, values: list[str]) -> list[str]: |
| normalized = {value.casefold() for value in values} |
| if len(normalized) != len(values): |
| raise ValueError("proposed strengths must be unique") |
| return values |
|
|
|
|
| class CriticScore(StrictModel): |
| index: int = Field(ge=0, le=5) |
| specificity: int = Field(ge=1, le=5) |
| warmth: int = Field(ge=1, le=5) |
| non_genericness: int = Field(ge=1, le=5) |
| non_toxic_positivity: int = Field(ge=1, le=5) |
| reason: str = Field(min_length=3, max_length=240) |
|
|
|
|
| class CriticDecision(StrictModel): |
| keep_indices: list[int] = Field(min_length=1, max_length=6) |
| revise_indices: list[int] = Field(default_factory=list, max_length=6) |
| reasons: dict[str, str] = Field(default_factory=dict) |
| scores: list[CriticScore] = Field(default_factory=list, max_length=6) |
|
|
| @field_validator("keep_indices", "revise_indices") |
| @classmethod |
| def validate_unique_indices(cls, values: list[int]) -> list[int]: |
| if len(set(values)) != len(values): |
| raise ValueError("indices must be unique") |
| if any(index < 0 or index > 5 for index in values): |
| raise ValueError("indices must be between zero and five") |
| return values |
|
|
|
|
| class GuardResult(StrictModel): |
| allowed: bool |
| category: Literal["ok", "invalid", "crisis", "abuse", "medical"] |
| message: str = "" |
|
|
|
|
| class StreamEvent(StrictModel): |
| type: Literal["status", "support", "forest", "clearing", "complete", "error"] |
| message: str = "" |
| data: dict[str, object] = Field(default_factory=dict) |
|
|
|
|