from pydantic import BaseModel, Field from api.domain.captcha_state import CaptchaState class CaptchaNotifyRequest(BaseModel): """Запрос от browser-use tool о том, что задача упёрлась в капчу.""" browser_view_url: str | None = Field(default=None, description="URL noVNC/прокси для ручного решения") captcha_kind: str | None = Field(default=None, description="Тип капчи (recaptcha_v2/hcaptcha/turnstile/unknown)") reason: str | None = Field(default=None, description="Свободное описание ситуации от агента") timeout_seconds: int = Field(default=300, ge=1, le=3600, description="Сколько ждать решения до timeout-prompt") class CaptchaSolvedRequest(BaseModel): """Уведомление от детектора, что капча больше не блокирует страницу.""" detector: str | None = Field(default=None, description="Имя детектора (dom_poller/2captcha/user)") class CaptchaExtendRequest(BaseModel): """Пользовательский ответ «продлить» на timeout-prompt.""" extra_seconds: int = Field(default=300, ge=1, le=3600, description="На сколько ещё ждать решения") class CaptchaAbortRequest(BaseModel): """Пользовательский ответ «отменить» на timeout-prompt.""" reason: str | None = Field(default=None, description="Свободный текст причины") class CaptchaStatusResponse(BaseModel): """Снимок captcha-состояния задачи.""" task_id: str state: CaptchaState captcha_kind: str | None = None reason: str | None = None browser_view_url: str | None = None notified_at: float | None = None solved_at: float | None = None deadline: float | None = None extra_seconds: int = 0 remaining_seconds: float | None = None class CaptchaActionResponse(BaseModel): """Универсальный ответ на действие над captcha-flow.""" task_id: str state: CaptchaState accepted: bool = True message: str | None = None