"""Durable investigation questions; answers are user input, not field evidence.""" from typing import Annotated, Literal from uuid import UUID from pydantic import Field, model_validator from app.domain.schemas.shared import StrictModel, PositiveInt from app.domain.schemas.workbench_runtime import WorkbenchDateTime Id = Annotated[str, Field(min_length=1, max_length=128)] class TaskQuestionOption(StrictModel): id: Id label: Annotated[str, Field(min_length=1, max_length=200)] class TaskQuestion(StrictModel): question_id: Id title: Annotated[str, Field(min_length=1, max_length=200)] body: Annotated[str, Field(min_length=1, max_length=2000)] options: list[TaskQuestionOption] = Field(max_length=12) mode: Literal["single", "multiple"] allow_custom: bool required: bool @model_validator(mode="after") def valid_options(self): if len({o.id for o in self.options}) != len(self.options): raise ValueError("duplicate option ids") if not self.options and not self.allow_custom: raise ValueError("question must offer an answer input") return self class TaskQuestionAnswer(StrictModel): question_id: Id selected_option_ids: list[Id] = Field(max_length=12) custom_text: Annotated[str, Field(max_length=2000)] class TaskQuestionCreate(StrictModel): request_id: UUID source_session_id: Id run_id: UUID questions: list[TaskQuestion] = Field(min_length=1, max_length=3) @model_validator(mode="after") def unique_questions(self): if len({q.question_id for q in self.questions}) != len(self.questions): raise ValueError("duplicate question ids") if len(self.model_dump_json().encode()) > 32768: raise ValueError("question definition too large") return self class TaskQuestionReply(StrictModel): request_id: UUID expected_version: PositiveInt answers: list[TaskQuestionAnswer] = Field(max_length=3) class TaskQuestionRequest(StrictModel): question_request_id: UUID task_id: UUID run_id: UUID execution_generation: PositiveInt source_session_id: Id questions: list[TaskQuestion] status: Literal["pending", "answered", "cancelled"] version: PositiveInt created_at: WorkbenchDateTime answered_at: WorkbenchDateTime | None = None answered_by: str | None = None answers: list[TaskQuestionAnswer] = Field(default_factory=list)