Создание активного урока или задания
Откройте ученику занятие по программе, теме или выбранному заданию. Backend сохранит состав заданий и свяжет занятие с одним учебным диалогом.
Выберите сценарий
Один метод запускает занятие по выбранному источнику. Новое занятие получает общий чат и первую попытку без вызова ИИ. Повторное открытие сохраняет прогресс и чат.
POST /api/v2/lesson-runs| Что открыть | Источник в JSON |
|---|---|
| Урок в конкретной программе | source.type=program_lesson и source.program_lesson_id — ID места урока в программе. |
| Доступный урок по теме | source.type=topic и source.lesson_id — ID урока. |
| Одно задание или свой набор | source.type=tasks и source.task_ids — массив ID заданий из каталога в нужном порядке. |
| Полный экзаменационный вариант | source.type=exam_variant и source.exam_variant_id — ID варианта. |
Для любого источника отдельно выберите run_mode: training — обучение с помощью и исправлениями, exam — экзамен с окончательным первым ответом. Название источника exam_variant само по себе не включает экзамен. Для запуска экзамена в непустом составе должно быть хотя бы одно обязательное задание role=exam, is_required=true; иначе сервер вернёт 409 lesson_tasks_missing. Пустой экзаменационный вариант даёт отдельную ошибку 409 exam_variant_tasks_missing.
Подготовка к запросу
- Получите внутреннюю сессию ученика. Вызовите
POST /api/v2/auth/gigma/exchangeс внешним Gigma Bearer-токеном. Backend установит защищённую HttpOnly-cookie; токен внутренней сессии в JSON не возвращается. Пользователя и проект сервер определяет по этой сессии. - Выберите доступный контент. Для программы и темы нужен доступ к соответствующему уроку. Для заданий и вариантов нужен профиль с выбранным
exam_type; контент должен быть опубликован и соответствовать этому режиму ОГЭ/ЕГЭ. - Создайте ключ операции.
Idempotency-Keyзащищает от дублей при повторе запроса. Используйте новое уникальное значение для нового действия и прежнее значение для его повтора.
| Заголовок | Значение |
|---|---|
Cookie | Cookie внутренней сессии, установленная при обмене. Браузер отправляет её через |
Origin | https://eg.gigma.ruОбязателен для изменяющих запросов с cookie. В другой среде используйте её разрешённый Origin. |
Content-Type | application/json |
Idempotency-KeyОбязательный | Строка от 1 до 255 символов после удаления пробелов по краям. |
Обмен токена и сохранение cookie в cURL
В одной Bash-сессии подготовьте временный cookie jar и выполните обмен. Следующие примеры используют тот же COOKIE_JAR.
umask 077
COOKIE_JAR="$(mktemp)"
curl --request POST \
'https://api.eg.gigma.ru/api/v2/auth/gigma/exchange' \
--header 'Authorization: Bearer <gigma_access_token>' \
--header 'Origin: https://eg.gigma.ru' \
--cookie-jar "$COOKIE_JAR"Cookie jar содержит сессию: не публикуйте его и удалите после проверки командой rm -- "$COOKIE_JAR". JSON-ответ обмена описывает сессию, но не содержит session_token.
Все UUID в примерах демонстрационные. Замените их идентификаторами доступного ученику контента. Примеры cURL рассчитаны на Bash.
Создание занятия
Метод создаёт lesson_run, фиксирует состав заданий, открывает общий чат и первую попытку. ИИ автоматически не вызывается; доступность Redis и модели для старта не требуется. Занятие того же ученика с тем же источником и режимом в статусе active или submitted продолжается: сохраняются чат и попытки, следующее задание автоматически не открывается.
/api/v2/lesson-runsПараметры запроса
| Параметр | Описание |
|---|---|
run_modestringОбязательный | training — обучение с повторными ответами и помощью, без официального экзаменационного результата.
|
sourceobjectОбязательный | Источник заданий. Передайте type и только соответствующее ему поле из таблицы ниже. Неизвестные поля запрещены. |
source.typestringОбязательный | program_lesson, topic, tasks или exam_variant. Поле идентификатора выбирается по этому значению. |
В теле запуска нужны только run_mode и source. Идентификаторы ученика, проекта, чата и попытки сервер определяет сам. exam_type (ОГЭ/ЕГЭ) хранится в профиле и отличается от run_mode; в этот запрос его не передают.
| source.type | Поле источника |
|---|---|
program_lesson | program_lesson_id · UUIDМесто урока в программе. Это не |
topic | lesson_id · UUIDУрок, доступный ученику в программе. |
tasks | task_ids · UUID[]От 1 до 100 уникальных заданий. Порядок массива определяет порядок заданий. |
exam_variant | exam_variant_id · UUIDОпубликованный экзаменационный вариант. Для официального результата укажите |
Примеры запросов
По теме
{
"run_mode": "training",
"source": {
"type": "topic",
"lesson_id": "44444444-4444-4444-4444-444444444444"
}
}Полный запрос cURL
curl --request POST \
'https://api.eg.gigma.ru/api/v2/lesson-runs' \
--cookie "$COOKIE_JAR" \
--header 'Origin: https://eg.gigma.ru' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: lesson-topic-001' \
--data '{
"run_mode": "training",
"source": {
"type": "topic",
"lesson_id": "44444444-4444-4444-4444-444444444444"
}
}'Из программы
{
"run_mode": "training",
"source": {
"type": "program_lesson",
"program_lesson_id": "99999999-9999-9999-9999-999999999999"
}
}Полный запрос cURL
curl --request POST \
'https://api.eg.gigma.ru/api/v2/lesson-runs' \
--cookie "$COOKIE_JAR" \
--header 'Origin: https://eg.gigma.ru' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: lesson-program-001' \
--data '{
"run_mode": "training",
"source": {
"type": "program_lesson",
"program_lesson_id": "99999999-9999-9999-9999-999999999999"
}
}'Набор заданий
{
"run_mode": "training",
"source": {
"type": "tasks",
"task_ids": [
"22222222-2222-2222-2222-222222222222"
]
}
}Полный запрос cURL
curl --request POST \
'https://api.eg.gigma.ru/api/v2/lesson-runs' \
--cookie "$COOKIE_JAR" \
--header 'Origin: https://eg.gigma.ru' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: lesson-tasks-001' \
--data '{
"run_mode": "training",
"source": {
"type": "tasks",
"task_ids": [
"22222222-2222-2222-2222-222222222222"
]
}
}'Экзаменационный вариант
{
"run_mode": "exam",
"source": {
"type": "exam_variant",
"exam_variant_id": "99999999-9999-9999-9999-999999999999"
}
}Полный запрос cURL
curl --request POST \
'https://api.eg.gigma.ru/api/v2/lesson-runs' \
--cookie "$COOKIE_JAR" \
--header 'Origin: https://eg.gigma.ru' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: lesson-exam-001' \
--data '{
"run_mode": "exam",
"source": {
"type": "exam_variant",
"exam_variant_id": "99999999-9999-9999-9999-999999999999"
}
}'Возьмите id занятия и current_attempt_id. Для следующего или явно выбранного задания используйте POST /api/v2/lesson-runs/{run_id}/task-attempts с новым ключом операции. При продолжении current_attempt_id может быть null; сданное занятие не открывается для ввода заново. Структура ответа →
Для одного задания укажите один ID в source.task_ids. Поддерживаются text, single, multi, graphic, sequence, matching, open_response. Отсутствующий эталон не блокирует запуск. Для новых open_response отсутствие эталона или критериев даёт failed без оценки; для остальных типов сохраняется проверка по эталонам с 0 баллов при отсутствии эталона. При запуске экзамена с непустым составом отсутствие обязательных экзаменационных заданий даёт 409 lesson_tasks_missing. Формат ответа и правила сравнения →
Обработка ответа
201 Created Новое занятие создано.
200 OK Найдено прежнее занятие или повторён запрос с тем же ключом. Запуск возвращает актуальное состояние этого занятия, включая текущий прогресс.
Создание занятия: объект RunResponse
Идентификатор id находится на верхнем уровне: дополнительной оболочки run у запуска нет. Ниже ответ на запуск одного задания.
{
"id": "33333333-3333-3333-3333-333333333333",
"lesson_id": null,
"lesson": null,
"variant": null,
"run_mode": "training",
"source_type": "tasks",
"source_ref_id": "6e494baf-b392-5a16-a2ad-3ba53672a669",
"chat_session_id": "55555555-5555-5555-5555-555555555555",
"status": "active",
"tasks": [
{
"lesson_run_task_id": "77777777-7777-7777-7777-777777777777",
"lesson_task_id": null,
"task_id": "22222222-2222-2222-2222-222222222222",
"title": "Сложение чисел",
"taxonomy": {"topic_ids": [], "subtopic_ids": [], "skill_ids": [], "ancestor_topic_ids": [], "topics": [], "ancestor_topics": [], "subtopics": [], "skills": []},
"position": 1,
"role": "practice",
"is_required": true,
"prompt": "Вычислите: 2 + 2.",
"prompt_content": {
"format": "rich_text_v1",
"blocks": [
{
"type": "paragraph",
"text": "Вычислите: 2 + 2."
}
]
},
"answer_type": "text",
"answer_options": null,
"visual": null,
"assets": [],
"attempt": {
"id": "66666666-6666-6666-6666-666666666666",
"lesson_task_id": "77777777-7777-7777-7777-777777777777",
"lesson_run_task_id": "77777777-7777-7777-7777-777777777777",
"chat_session_id": null,
"status": "active",
"wrong_answer_count": 0,
"hint_used": false,
"earned_points": 0,
"solution_revealed": false,
"hint_status": "none"
},
"max_points": 1,
"grading_status": null,
"revealed_solution": null,
"actions": {
"can_answer": true,
"can_hint": true,
"can_reveal_solution": true,
"can_skip": true,
"can_retry_grading": false
}
}
],
"current_attempt_id": "66666666-6666-6666-6666-666666666666",
"result_id": null,
"completed_count": 0,
"submitted_count": 0,
"mastered_count": 0,
"assisted_count": 0,
"skipped_count": 0,
"total_count": 1
}Полный вариант с заданиями
Вариант возвращается в variant: название, инструкции, продолжительность и все задания снимка в variant.tasks. Ниже вариант из двух заданий: у каждого своё условие и материалы; попытка пока открыта у первого. Для урока такое же содержимое находится в lesson.tasks. Корневой tasks используется для отдельных заданий и повторной отработки.
Пример полного варианта в обучении
{
"id": "33333333-3333-3333-3333-333333333333",
"lesson_id": null,
"lesson": null,
"variant": {
"id": "99999999-9999-9999-9999-999999999999",
"code": "DEMO-VARIANT-01",
"title": "Демонстрационный вариант",
"instructions_content": {},
"duration_minutes": 45,
"tasks": [
{
"lesson_run_task_id": "77777777-7777-7777-7777-777777777777",
"lesson_task_id": null,
"task_id": "22222222-2222-2222-2222-222222222222",
"title": "Сложение чисел",
"taxonomy": {"topic_ids": [], "subtopic_ids": [], "skill_ids": [], "ancestor_topic_ids": [], "topics": [], "ancestor_topics": [], "subtopics": [], "skills": []},
"position": 1,
"role": "practice",
"is_required": true,
"prompt": "Вычислите: 2 + 2.",
"prompt_content": {
"format": "rich_text_v1",
"blocks": [
{
"type": "paragraph",
"text": "Вычислите: 2 + 2."
}
]
},
"answer_type": "text",
"answer_options": null,
"visual": null,
"assets": [],
"attempt": {
"id": "66666666-6666-6666-6666-666666666666",
"lesson_task_id": "77777777-7777-7777-7777-777777777777",
"lesson_run_task_id": "77777777-7777-7777-7777-777777777777",
"chat_session_id": null,
"status": "active",
"wrong_answer_count": 0,
"hint_used": false,
"earned_points": 0,
"solution_revealed": false,
"hint_status": "none"
},
"max_points": 1,
"grading_status": null,
"revealed_solution": null,
"actions": {
"can_answer": true,
"can_hint": true,
"can_reveal_solution": true,
"can_skip": true,
"can_retry_grading": false
}
},
{
"lesson_run_task_id": "88888888-8888-8888-8888-888888888888",
"lesson_task_id": null,
"task_id": "11111111-1111-1111-1111-111111111111",
"title": "Умножение чисел",
"taxonomy": {"topic_ids": [], "subtopic_ids": [], "skill_ids": [], "ancestor_topic_ids": [], "topics": [], "ancestor_topics": [], "subtopics": [], "skills": []},
"position": 2,
"role": "practice",
"is_required": true,
"prompt": "Вычислите: 12 × 5.",
"prompt_content": {
"format": "rich_text_v1",
"blocks": [
{
"type": "paragraph",
"text": "Вычислите: 12 × 5."
}
]
},
"answer_type": "text",
"answer_options": null,
"visual": null,
"assets": [],
"attempt": null,
"max_points": 1,
"grading_status": null,
"revealed_solution": null,
"actions": {
"can_answer": false,
"can_hint": false,
"can_reveal_solution": false,
"can_skip": false,
"can_retry_grading": false
}
}
]
},
"run_mode": "training",
"source_type": "exam_variant",
"source_ref_id": "99999999-9999-9999-9999-999999999999",
"chat_session_id": "55555555-5555-5555-5555-555555555555",
"status": "active",
"tasks": [],
"current_attempt_id": "66666666-6666-6666-6666-666666666666",
"result_id": null,
"completed_count": 0,
"submitted_count": 0,
"mastered_count": 0,
"assisted_count": 0,
"skipped_count": 0,
"total_count": 2
}| Поле | Как использовать |
|---|---|
id | Идентификатор занятия для чтения, сообщений и завершения. |
run_mode | Закреплённый режим training или exam. |
source_type, source_ref_id | Тип и идентификатор источника. Для набора заданий source_ref_id вычисляет сервер из упорядоченного списка ID; это не ID одного задания. У повторной отработки он указывает на исходный результат. |
lesson_id, lesson, variant | Урок и его содержимое либо содержимое варианта. Отсутствующий идентификатор/объект равен null. У отдельного задания оба объекта равны null. |
chat_session_id | Общий учебный диалог. Не создавайте отдельный чат на каждое задание. |
status | active — занятие активно; возможность команды зависит от доступа и состояния задания. submitted — ввод закрыт, завершение ожидает проверки. completed — занятие завершено. |
current_attempt_id | Текущая попытка или null, в том числе после сдачи или завершения. Состояние попытки находится в attempt соответствующей карточки задания. |
completed_count, total_count | Прогресс прохождения, а не число правильных ответов. В обработанные входят освоенные, выполненные с помощью, отправленные на экзамене и пропущенные задания; после завершения completed_count=total_count. |
submitted_count, mastered_count, assisted_count, skipped_count | Счётчики отправленных, освоенных, выполненных с помощью и пропущенных заданий. Официальные баллы читайте в результате. |
result_id | ID готового официального результата либо null. В обучении официальный результат не создаётся. |
variant.tasks / lesson.tasks / tasks | Полные карточки допустимых заданий снимка: условие, формат ответа, варианты выбора, visual/assets, максимум, состояние проверки и действия. Решения доступны только по правилам обучения. |
Отсутствующие lesson и variant равны null; неиспользуемый корневой tasks пуст. Изображения загружаются по ссылкам content_url из материалов.
Поля карточки задания
Эти поля находятся внутри каждого элемента variant.tasks, lesson.tasks или tasks.
| Поле карточки | Назначение |
|---|---|
lesson_run_task_id | ID задания в снимке занятия: передавайте его при выборе задания. Каталожный task_id для этой команды не подходит. |
lesson_task_id, task_id | Связь с заданием урока (может быть null) и ID задания в каталоге. Они отличаются от attempt.id. |
position, role, is_required | Порядок, роль и обязательность. В официальный экзаменационный итог входят только role=exam и is_required=true. |
prompt, prompt_content, answer_type, answer_options | Условие, структурированное условие, тип ответа и варианты выбора. Формат отправки задаётся типом ответа; answer_options может быть null. |
visual, assets | Визуальные данные или null и список изображений условия/вариантов ответа. assets[].content_url открывается с той же сессией ученика. |
attempt | Созданная попытка либо null. Её chat_session_id может быть null; для общего диалога используйте run.chat_session_id. Для ответа, подсказки, решения и пропуска используйте её id в URL. Внутри находятся status, wrong_answer_count, hint_used, hint_status, solution_revealed и earned_points. |
max_points, grading_status | Закреплённый максимум и состояние последней проверки либо null. До завершения экзамена attempt.earned_points и attempt.wrong_answer_count скрыты как null; максимум известен заранее. |
actions | can_answer, can_hint, can_reveal_solution, can_skip, can_retry_grading — доступность действий на момент чтения. До открытия попытки действия карточки недоступны; команда повторно проверяет своё состояние. |
revealed_solution | Эталоны, разбор и разрешённые изображения решения после раскрытия в обучении; иначе null. В экзамене решение не выдаётся и после завершения. |
Продолжение и завершение
Во всех запросах передавайте cookie внутренней сессии. Для изменяющих запросов, включая PUT, нужен разрешённый Origin; при JSON-теле — Content-Type: application/json. Каждое новое действие через перечисленные POST-команды получает свой Idempotency-Key; повтор отправляется с прежним ключом. Для PUT оценки сообщения этот ключ не требуется.
- GET
/api/v2/lesson-runs/{run_id}Восстановите состояние после перезагрузки: текущую попытку, прогресс и статус занятия.
- POST
/api/v2/lesson-runs/{run_id}/task-attemptsДля явного выбора передайте
lesson_run_task_idиз карточки. Без тела сервер продолжит выбранную допустимую/активную попытку либо откроет первое задание без попытки. Сохранитеidпопытки из ответа. - GET
/api/v2/lesson-runs/{run_id}/messagesВосстановите весь учебный экран: занятие, чат-сессию ИИ, переписку, задания и состояние обучения. Блоки ответа и загрузка истории →
- POST
/api/v2/lesson-runs/{run_id}/messagesТолько в обучении: передайте обязательное поле
message— строку от 1 до 4000 символов и не более 8192 байт UTF-8. Это вопрос ИИ, а не официальный ответ на задание. Ответ202означает постановку сообщения в очередь; на экзамене учебный чат отключён. - POST
/api/v2/lesson-runs/{run_id}/task-attempts/{attempt_id}/answersПередайте обязательное поле
answer— массив из 1–100 строк, каждая от 1 до 4000 символов. Числа передаются строками. Формат зависит от типа задания. Обычная проверка синхронна (200); сохранённые состоянияpending/queuedвозвращаются с202. На экзамене ответ окончательный. Для новыхopen_responseоценка и разбор доступны сразу после проверки; прежние оценки скрыты до завершения. - POST
/api/v2/lesson-runs/{run_id}/task-attempts/{attempt_id}/hintТолько в обучении: запросите подсказку без тела запроса. Её использование фиксируется в попытке и отмечает выполнение с помощью; баллы определяются проверкой ответа для его типа задания.
- POST
/api/v2/lesson-runs/{run_id}/finalizeЗавершите занятие без тела запроса. Для
examсервер учитывает только обязательные экзаменационные задания снимка и создаёт один официальный результат, когда проверки завершены. Пока они не завершены, возвращает202,run.status=submittedиresult=null, ввод закрыт. Дляtrainingофициальный результат не создаётся,result=null. - POST
/api/v2/lesson-runs/{run_id}/task-attempts/{attempt_id}/solutionВ обучении раскройте сохранённое решение. Незавершённая попытка сразу завершается с помощью, переписывать эталон в ответ не требуется. Ранее полученное самостоятельное освоение сохраняется.
- POST
/api/v2/lesson-runs/{run_id}/task-attempts/{attempt_id}/skipПропустите задание. До сдачи к нему можно вернуться явным выбором при открытии попытки.
- POST
/api/v2/lesson-runs/{run_id}/task-attempts/{attempt_id}/grading-retriesПовторите проверку со статусом
failedна том же ответе и снимке канона. Новое значение не передаётся. Ответ содержитgrading_status:pending/queuedвозвращаются с202,completed/failed/unknown— с200. Приunknownавтоматического повтора нет. - GET
/api/v2/lesson-runs/{run_id}/resultПолучите готовый официальный результат; пока его нет — 404. В учебном экране до готовности result=null.
- POST
/api/v2/lesson-runs/{run_id}/reinforcement-runsСоздайте отдельное обучение по готовому официальному результату: задания с баллом меньше максимума, включая пропуски. Без результата — 409 lesson_result_not_ready. Исходный результат сохраняется.
- GET
/api/v2/lesson-runs/resultsЗагрузите историю официальных результатов с limit/cursor.
- PUT
/api/v2/lesson-runs/{run_id}/task-attempts/{attempt_id}/messages/{message_id}/feedbackПередайте обязательное поле
rating: число1или-1. Оценить можно сообщениеassistant, связанное с указанной попыткой;message_idиattempt_idберите из одной записи истории. Возвращается201при создании оценки или200при обновлении. Баллы за задание не меняются.
JSON для команд продолжения
Во всех этих телах неизвестные поля запрещены. run_id, attempt_id и message_id передаются в URL соответствующей команды.
{
"lesson_run_task_id": "77777777-7777-7777-7777-777777777777"
}{
"answer": ["4"]
}{
"message": "Объясни условие"
}{
"rating": 1
}Команды hint, solution, skip, grading-retries, finalize и reinforcement-runs вызываются без тела запроса.
Формат ответа и оценивание
| Тип задания | Как сравнивается answer |
|---|---|
text, single, graphic | Одно строковое значение должно совпасть с одним из допустимых эталонов. |
multi | Набор значений должен совпасть с эталонным; порядок не влияет, повторяющиеся значения не дают правильного ответа. |
sequence, matching | Значения должны совпасть с эталонной последовательностью в том же порядке. |
open_response | Новые ответы оценивает агент по сохранённым эталону и критериям (agent_rubric_v1). Старые проверки не пересчитываются. |
Для типов со сравнением у каждого значения ответа и эталона убираются пробелы по краям, игнорируется регистр и запятая заменяется точкой. Например, " 4,0 " и "4.0" совпадают; "4" и "4.0" остаются разными строками. Пустое после такой обработки значение даёт ошибку валидации 422. Для перечисленных типов со сравнением отсутствие эталона даёт 0 баллов. Новый развёрнутый ответ передаётся агенту вместе с условием, материалами, эталоном и критериями закреплённой версии задания; максимум берётся из снимка занятия. POST сохраняет ответ и ждёт проверку до 30 секунд. При pending/queued работа продолжается в фоне; до completed баллы и правильность равны null. При отсутствии канона или окончательной ошибке возвращается failed; при неизвестном исходе — unknown, без оценки.
Максимум фиксируется в занятии. При сравнении совпадение даёт полный максимум задания, несовпадение — 0. Агент выставляет целые баллы от 0 до максимума и разбор по критериям; полный балл означает правильный ответ, частичный не означает освоение. В официальный экзаменационный итог входят только задания role=exam с is_required=true; неотвеченные из них дают 0. passed означает полный балл платформы, а не официальную сдачу ОГЭ/ЕГЭ.
Обучение и экзамен
В обучении каждая принятая отправка сохраняется отдельным ответом для истории и статистики, включая повторные ошибки. Правильный ответ после ошибки может стать самостоятельным освоением; полученная помощь отмечается отдельно. Повтор запроса с тем же ключом и техническая повторная проверка не создают новый ответ ученика. Доступны подсказки, раскрытие решения и пропуск. Решение сразу завершает незавершённую попытку с помощью, сохраняя ранее полученное самостоятельное освоение; подсказка без сохранённого текста генерируется асинхронно, ошибка генерации помощью не считается. К пропуску можно вернуться явным выбором задания до сдачи. При pending/queued/unknown новый ответ, подсказка, решение и пропуск той же попытки заблокированы.
На экзамене первый принятый ответ окончательный; другой ответ получает 409, повтор с тем же ключом возвращает подтверждение. Для новых open_response баллы, правильность, разбор и критерии доступны сразу после completed и в экзамене; показом управляет фронтенд. Для прежних проверок баллы и правильность скрыты до завершения. Помощь ИИ, подсказки и решения отключены; эталоны и решения не раскрываются и после завершения. При failed/unknown официальный итог не создаётся. Сдача закрывает ввод, повторная отработка создаёт отдельное обучение по заданиям ниже максимума.
Учебный экран и чат-сессия ИИ
Один GET возвращает состояние занятия на момент запроса. Чтение не создаёт чат, попытку, сообщение или привязку к программе. Незавершённое занятие продолжает прежний чат.
| Блок ответа | Назначение |
|---|---|
run | Идентификаторы занятия и чата, источник, run_mode, статус, текущая попытка и счётчики. Полное содержимое снимка находится в run.variant.tasks, run.lesson.tasks или run.tasks; оно не зависит от страницы сообщений. |
chat_session | id совпадает с run.chat_session_id; title может быть null. has_pending_response учитывает незавершённые генерации всего чата, включая неопределённый исход, независимо от страницы. Это не индикатор печатания. При отсутствии привязки блок равен null; чужая или несуществующая привязанная сессия даёт 404. |
items | Сообщения страницы: прежние поля и nullable-связи attempt_id, lesson_run_task_id, lesson_task_id, parent_message_id, dialog_sequence, answer, feedback_rating. У ответа ученика и его проверки одинаковый answer.id, даже на разных страницах. answer.is_correct — историческая проверка ответа; оценка сообщения — -1, 1 или null. |
next_cursor | Курсор следующей страницы истории или null. Он не служит курсором изменений сообщений. |
current_task | Ссылки lesson_run_task_id, lesson_task_id, attempt_id. До открытия попытки её id равен null. Выбор: явно выбранное допустимое задание → активная попытка → первое допустимое задание без попытки → null. У сданного (submitted) и завершённого занятия текущего задания нет. |
interaction | can_continue и disabled_reason: completed, submitted, transition_required, access_closed, chat_missing либо null. Это общее право продолжения; готовность конкретной команды проверяется при её вызове. |
result | Готовый официальный результат; null в обучении и до создания экзаменационного результата. Не подменяет историческую проверку отдельного ответа или текущие баллы попытки. |
Страницы и обновление сообщений
Для первого открытия используйте GET /api/v2/lesson-runs/{run_id}/messages?view=latest&limit=100. Последние сообщения возвращаются в порядке чтения; следующий запрос сохраняет view=latest и передаёт cursor из next_cursor, загружая более раннюю историю. Сортировка: created_at, dialog_sequence (отсутствующее значение считается 0), затем id.
limit: 1–200, по умолчанию 100. Без view сохраняются прежние порядок created_at/id и курсоры. Курсор другого режима или занятия недопустим: 422. Пустая история возвращает items=[] и next_cursor=null, остальные блоки состояния сохраняются.
Завершение генерации обновляет сообщение по его id. Используйте существующие события /api/v2/chat/sessions/{session_id}/events и WebSocket для chat_session.id; после переподключения перечитайте соответствующую страницу. Состояние занятия и сессии актуально и при загрузке старой страницы. Формат событий общий для поддерживаемых ИИ-провайдеров.
Просмотр после закрытия доступа
Свою переписку и уже открытые задания с изображениями можно читать после закрытия доступа к связанному зачислению. Продолжение и новые задания недоступны. Открытие подтверждается попыткой или сохранённой связью сообщения, включая предварительное объяснение ИИ; GET сам подтверждением не становится. Свободная практика без связи с зачислением не закрывается из-за отказа от другой программы.
MVP-занятия версии правил 1 исключены из нового процесса: начните новое занятие. У поддерживаемого занятия без привязанного чата chat_session=null; GET не создаёт чат. Потерянные или противоречивые учебные связи возвращаются как null; старому сообщению не подставляется текущее задание.
Ответ персональный: Cache-Control: private, no-store. Проверка доступа к изображениям выполняется и перед ответом 304. Секреты и внутренние настройки провайдера не возвращаются.
Ошибки и повторные запросы
Одинаковый ключ и то же тело запроса не выполняют действие повторно. У POST /api/v2/lesson-runs повтор возвращает 200 и актуальное состояние того же занятия; новая попытка не открывается. Если это занятие уже завершено, повтор исходного запроса вернёт его с status=completed. Для других команд сохранённый ответ может отражать момент их выполнения: актуальное состояние читайте через GET /api/v2/lesson-runs/{run_id}.
Не меняйте тело запроса при повторе. Новый ключ для того же незавершённого источника и вида занятия также может продолжить существующее занятие: новый ключ не гарантирует новый lesson_run.
| HTTP / причина | Что делать |
|---|---|
401Ошибка сессии | Проверьте наличие cookie, срок действия сессии и авторизацию ученика. |
403Нет доступа | Проверьте роль ученика, доступ к программе и разрешённый Origin при cookie-авторизации. |
404Ресурс недоступен | Проверьте идентификаторы, публикацию задания или варианта, выбранный режим ОГЭ/ЕГЭ и принадлежность ресурса пользователю. |
409
| Тот же ключ использован с другим телом. Для нового действия создайте новый ключ; для повтора восстановите исходное тело. |
409
| Команда ещё выполняется. Повторите позже с прежним ключом и телом. |
409
| В выбранном уроке нет заданий или в непустом составе экзамена нет обязательных заданий role=exam, is_required=true. Выберите подходящий контент. |
409
| У выбранного опубликованного экзаменационного варианта нет заданий. Ошибка возникает при разрешении источника exam_variant в обоих режимах, до проверки экзаменационного состава. |
409
| Попытка больше не принимает ответы: экзаменационный ответ принят либо учебная попытка завершена. При потере подтверждения повторите исходный запрос с тем же ключом. |
422Параметры или предусловия | Проверьте обязательные поля, UUID, единственный источник, отсутствие дублей заданий. При complete_onboarding_required проверьте режим подготовки в профиле. |
503Зависимость недоступна | Если передан Retry-After, выдержите указанную задержку. Сохраните ключ и исходное тело; не запускайте бесконечные автоматические повторы. |
Пример бизнес-ошибки
{
"detail": "idempotency_conflict"
}При структурной ошибке валидации поле detail может содержать список ошибок с указанием поля, а не строку.
Справочник API
Полные схемы, допустимые типы ответов и остальные методы учебного процесса.