76 lines
2.4 KiB
Python
76 lines
2.4 KiB
Python
"""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)
|