models

Pydantic-модели для запросов и ответов Яндекс Диалогов.

Определяют структуры данных, используемые для валидации входящих запросов от Алисы и формирования ответов навыка.

  1"""
  2Pydantic-модели для запросов и ответов Яндекс Диалогов.
  3
  4Определяют структуры данных, используемые для валидации входящих
  5запросов от Алисы и формирования ответов навыка.
  6"""
  7
  8from typing import Any, Dict, List
  9from pydantic import BaseModel
 10
 11
 12class Meta(BaseModel):
 13    """Мета-информация о запросе: локаль, часовой пояс, идентификатор клиента."""
 14
 15    locale: str
 16    timezone: str
 17    client_id: str
 18    interfaces: Dict[str, Any]
 19
 20
 21class User(BaseModel):
 22    """Информация о пользователе Яндекс Диалогов."""
 23
 24    user_id: str
 25
 26
 27class Application(BaseModel):
 28    """Информация о приложении, с которого отправлен запрос."""
 29
 30    application_id: str
 31
 32
 33class Session(BaseModel):
 34    """Данные сессии запроса: идентификаторы сообщения, сессии, навыка и пользователя."""
 35
 36    message_id: int
 37    session_id: str
 38    skill_id: str
 39    user: User
 40    application: Application
 41    user_id: str
 42    new: bool
 43
 44
 45class Entity(BaseModel):
 46    """
 47    Сущность, распознанная NLU Алисы.
 48
 49    value и tokens намеренно типизированы как Any: это граница с внешним
 50    сервисом, и Алиса присылает разные JSON-типы в зависимости от типа
 51    сущности —
 52
 53        YANDEX.NUMBER   -> int или str   («шестьсот двадцать девять» -> 629)
 54        YANDEX.DATE     -> str           ("2026-09-29")
 55        YANDEX.DATETIME -> dict          ({"year": 2026, "month": 9, "day": 29})
 56        прочие          -> list / null
 57
 58    Любая узкая аннотация здесь превращается в HTTP 422 на живом трафике:
 59    запрос отбрасывается на валидации до парсера, и Алиса отвечает
 60    «не нашла задач», хотя NLU разобрал фразу корректно. Именно так сломался
 61    список задач 2026-09-29 — типизация Union[str, int, float, bool, None]
 62    отвергала value-объект YANDEX.DATETIME.
 63
 64    Нужное нам число (YANDEX.NUMBER) приводится к int в
 65    command_parser._entity_number, который для любого другого типа
 66    возвращает None.
 67    """
 68
 69    type: str
 70    value: Any = None
 71    tokens: Any = None
 72
 73
 74class Nlu(BaseModel):
 75    """NLU-составляющая запроса: токены, сущности и интенты."""
 76
 77    tokens: List[str]
 78    entities: List[Entity] = []
 79    intents: Dict[str, Any] = {}
 80
 81
 82class Markup(BaseModel):
 83    """Разметка запроса, указывающая на опасный контекст."""
 84
 85    dangerous_context: bool
 86
 87
 88class Request(BaseModel):
 89    """Тело запроса от Яндекс Алисы: команда, оригинальная фраза, NLU и разметка."""
 90
 91    command: str
 92    original_utterance: str
 93    nlu: Nlu
 94    markup: Markup
 95    type: str
 96
 97
 98class AliceRequest(BaseModel):
 99    """
100    Полный входящий запрос от Яндекс Алисы.
101
102    Содержит мета-информацию, данные сессии, тело запроса и версию протокола.
103    """
104
105    meta: Meta
106    session: Session
107    request: Request
108    version: str
109
110
111class AliceResponse(BaseModel):
112    """
113    Модель ответа навыка Яндекс Алисы.
114
115    Включает текст ответа, данные сессии и версию протокола.
116    """
117
118    response: Dict[str, Any]
119    session: Dict[str, Any]
120    version: str = "1.0"
class Meta(pydantic.main.BaseModel):
13class Meta(BaseModel):
14    """Мета-информация о запросе: локаль, часовой пояс, идентификатор клиента."""
15
16    locale: str
17    timezone: str
18    client_id: str
19    interfaces: Dict[str, Any]

Мета-информация о запросе: локаль, часовой пояс, идентификатор клиента.

locale: str = PydanticUndefined
timezone: str = PydanticUndefined
client_id: str = PydanticUndefined
interfaces: Dict[str, Any] = PydanticUndefined
class User(pydantic.main.BaseModel):
22class User(BaseModel):
23    """Информация о пользователе Яндекс Диалогов."""
24
25    user_id: str

Информация о пользователе Яндекс Диалогов.

user_id: str = PydanticUndefined
class Application(pydantic.main.BaseModel):
28class Application(BaseModel):
29    """Информация о приложении, с которого отправлен запрос."""
30
31    application_id: str

Информация о приложении, с которого отправлен запрос.

application_id: str = PydanticUndefined
class Session(pydantic.main.BaseModel):
34class Session(BaseModel):
35    """Данные сессии запроса: идентификаторы сообщения, сессии, навыка и пользователя."""
36
37    message_id: int
38    session_id: str
39    skill_id: str
40    user: User
41    application: Application
42    user_id: str
43    new: bool

Данные сессии запроса: идентификаторы сообщения, сессии, навыка и пользователя.

message_id: int = PydanticUndefined
session_id: str = PydanticUndefined
skill_id: str = PydanticUndefined
user: User = PydanticUndefined
application: Application = PydanticUndefined
user_id: str = PydanticUndefined
new: bool = PydanticUndefined
class Entity(pydantic.main.BaseModel):
46class Entity(BaseModel):
47    """
48    Сущность, распознанная NLU Алисы.
49
50    value и tokens намеренно типизированы как Any: это граница с внешним
51    сервисом, и Алиса присылает разные JSON-типы в зависимости от типа
52    сущности —
53
54        YANDEX.NUMBER   -> int или str   («шестьсот двадцать девять» -> 629)
55        YANDEX.DATE     -> str           ("2026-09-29")
56        YANDEX.DATETIME -> dict          ({"year": 2026, "month": 9, "day": 29})
57        прочие          -> list / null
58
59    Любая узкая аннотация здесь превращается в HTTP 422 на живом трафике:
60    запрос отбрасывается на валидации до парсера, и Алиса отвечает
61    «не нашла задач», хотя NLU разобрал фразу корректно. Именно так сломался
62    список задач 2026-09-29 — типизация Union[str, int, float, bool, None]
63    отвергала value-объект YANDEX.DATETIME.
64
65    Нужное нам число (YANDEX.NUMBER) приводится к int в
66    command_parser._entity_number, который для любого другого типа
67    возвращает None.
68    """
69
70    type: str
71    value: Any = None
72    tokens: Any = None

Сущность, распознанная NLU Алисы.

value и tokens намеренно типизированы как Any: это граница с внешним сервисом, и Алиса присылает разные JSON-типы в зависимости от типа сущности —

YANDEX.NUMBER   -> int или str   («шестьсот двадцать девять» -> 629)
YANDEX.DATE     -> str           ("2026-09-29")
YANDEX.DATETIME -> dict          ({"year": 2026, "month": 9, "day": 29})
прочие          -> list / null

Любая узкая аннотация здесь превращается в HTTP 422 на живом трафике: запрос отбрасывается на валидации до парсера, и Алиса отвечает «не нашла задач», хотя NLU разобрал фразу корректно. Именно так сломался список задач 2026-09-29 — типизация Union[str, int, float, bool, None] отвергала value-объект YANDEX.DATETIME.

Нужное нам число (YANDEX.NUMBER) приводится к int в command_parser._entity_number, который для любого другого типа возвращает None.

type: str = PydanticUndefined
value: Any = None
tokens: Any = None
class Nlu(pydantic.main.BaseModel):
75class Nlu(BaseModel):
76    """NLU-составляющая запроса: токены, сущности и интенты."""
77
78    tokens: List[str]
79    entities: List[Entity] = []
80    intents: Dict[str, Any] = {}

NLU-составляющая запроса: токены, сущности и интенты.

tokens: List[str] = PydanticUndefined
entities: List[Entity] = []
intents: Dict[str, Any] = {}
class Markup(pydantic.main.BaseModel):
83class Markup(BaseModel):
84    """Разметка запроса, указывающая на опасный контекст."""
85
86    dangerous_context: bool

Разметка запроса, указывающая на опасный контекст.

dangerous_context: bool = PydanticUndefined
class Request(pydantic.main.BaseModel):
89class Request(BaseModel):
90    """Тело запроса от Яндекс Алисы: команда, оригинальная фраза, NLU и разметка."""
91
92    command: str
93    original_utterance: str
94    nlu: Nlu
95    markup: Markup
96    type: str

Тело запроса от Яндекс Алисы: команда, оригинальная фраза, NLU и разметка.

command: str = PydanticUndefined
original_utterance: str = PydanticUndefined
nlu: Nlu = PydanticUndefined
markup: Markup = PydanticUndefined
type: str = PydanticUndefined
class AliceRequest(pydantic.main.BaseModel):
 99class AliceRequest(BaseModel):
100    """
101    Полный входящий запрос от Яндекс Алисы.
102
103    Содержит мета-информацию, данные сессии, тело запроса и версию протокола.
104    """
105
106    meta: Meta
107    session: Session
108    request: Request
109    version: str

Полный входящий запрос от Яндекс Алисы.

Содержит мета-информацию, данные сессии, тело запроса и версию протокола.

meta: Meta = PydanticUndefined
session: Session = PydanticUndefined
request: Request = PydanticUndefined
version: str = PydanticUndefined
class AliceResponse(pydantic.main.BaseModel):
112class AliceResponse(BaseModel):
113    """
114    Модель ответа навыка Яндекс Алисы.
115
116    Включает текст ответа, данные сессии и версию протокола.
117    """
118
119    response: Dict[str, Any]
120    session: Dict[str, Any]
121    version: str = "1.0"

Модель ответа навыка Яндекс Алисы.

Включает текст ответа, данные сессии и версию протокола.

response: Dict[str, Any] = PydanticUndefined
session: Dict[str, Any] = PydanticUndefined
version: str = '1.0'