gigmaEDUCATION API
v2 Education Backend
На этой странице

Создание активного урока или задания

Откройте ученику занятие по программе, теме или выбранному заданию. Backend сохранит состав заданий и свяжет занятие с одним учебным диалогом.

REST API v2Авторизация: cookie сессииИдемпотентные запросы
01 / ЗАНЯТИЕlesson_runИсточник и прогресс
02 / ЗАДАНИЯСостав заданийСостав на момент старта
03 / ДИАЛОГОдин общий чатВся история занятия

Выберите сценарий

Создать или продолжить занятие →

Один метод запускает занятие по выбранному источнику. Новое занятие получает общий чат и первую попытку без вызова ИИ. Повторное открытие сохраняет прогресс и чат.

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.

Подготовка к запросу

  1. Получите внутреннюю сессию ученика. Вызовите POST /api/v2/auth/gigma/exchange с внешним Gigma Bearer-токеном. Backend установит защищённую HttpOnly-cookie; токен внутренней сессии в JSON не возвращается. Пользователя и проект сервер определяет по этой сессии.
  2. Выберите доступный контент. Для программы и темы нужен доступ к соответствующему уроку. Для заданий и вариантов нужен профиль с выбранным exam_type; контент должен быть опубликован и соответствовать этому режиму ОГЭ/ЕГЭ.
  3. Создайте ключ операции. Idempotency-Key защищает от дублей при повторе запроса. Используйте новое уникальное значение для нового действия и прежнее значение для его повтора.
ЗаголовокЗначение
CookieCookie внутренней сессии, установленная при обмене.

Браузер отправляет её через credentials: "include"; cURL читает cookie jar через --cookie. Не извлекайте HttpOnly-cookie в JavaScript.

Originhttps://eg.gigma.ru

Обязателен для изменяющих запросов с cookie. В другой среде используйте её разрешённый Origin.

Content-Typeapplication/json
Idempotency-KeyОбязательныйСтрока от 1 до 255 символов после удаления пробелов по краям.

Обмен токена и сохранение cookie в cURL

В одной Bash-сессии подготовьте временный cookie jar и выполните обмен. Следующие примеры используют тот же COOKIE_JAR.

cURL · авторизация
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 продолжается: сохраняются чат и попытки, следующее задание автоматически не открывается.

POST/api/v2/lesson-runs

Параметры запроса

ПараметрОписание
run_modestringОбязательныйtraining — обучение с повторными ответами и помощью, без официального экзаменационного результата.

exam — экзамен с окончательным первым ответом и результатом после завершения.

sourceobjectОбязательныйИсточник заданий. Передайте type и только соответствующее ему поле из таблицы ниже. Неизвестные поля запрещены.
source.typestringОбязательныйprogram_lesson, topic, tasks или exam_variant. Поле идентификатора выбирается по этому значению.

В теле запуска нужны только run_mode и source. Идентификаторы ученика, проекта, чата и попытки сервер определяет сам. exam_type (ОГЭ/ЕГЭ) хранится в профиле и отличается от run_mode; в этот запрос его не передают.

source.typeПоле источника
program_lessonprogram_lesson_id · UUID

Место урока в программе. Это не lesson_id.

topiclesson_id · UUID

Урок, доступный ученику в программе.

taskstask_ids · UUID[]

От 1 до 100 уникальных заданий. Порядок массива определяет порядок заданий.

exam_variantexam_variant_id · UUID

Опубликованный экзаменационный вариант. Для официального результата укажите exam.

Примеры запросов

По теме

JSON · По теме
{
  "run_mode": "training",
  "source": {
    "type": "topic",
    "lesson_id": "44444444-4444-4444-4444-444444444444"
  }
}
Полный запрос cURL
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"
  }
}'

Из программы

JSON · Из программы
{
  "run_mode": "training",
  "source": {
    "type": "program_lesson",
    "program_lesson_id": "99999999-9999-9999-9999-999999999999"
  }
}
Полный запрос cURL
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"
  }
}'

Набор заданий

JSON · Набор заданий
{
  "run_mode": "training",
  "source": {
    "type": "tasks",
    "task_ids": [
      "22222222-2222-2222-2222-222222222222"
    ]
  }
}
Полный запрос cURL
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"
    ]
  }
}'

Экзаменационный вариант

JSON · Экзаменационный вариант
{
  "run_mode": "exam",
  "source": {
    "type": "exam_variant",
    "exam_variant_id": "99999999-9999-9999-9999-999999999999"
  }
}
Полный запрос cURL
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 у запуска нет. Ниже ответ на запуск одного задания.

201 Created · отдельное задание
{
  "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 используется для отдельных заданий и повторной отработки.

Пример полного варианта в обучении
201 Created · вариант с двумя заданиями
{
  "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Общий учебный диалог. Не создавайте отдельный чат на каждое задание.
statusactive — занятие активно; возможность команды зависит от доступа и состояния задания. submitted — ввод закрыт, завершение ожидает проверки. completed — занятие завершено.
current_attempt_idТекущая попытка или null, в том числе после сдачи или завершения. Состояние попытки находится в attempt соответствующей карточки задания.
completed_count, total_countПрогресс прохождения, а не число правильных ответов. В обработанные входят освоенные, выполненные с помощью, отправленные на экзамене и пропущенные задания; после завершения completed_count=total_count.
submitted_count, mastered_count, assisted_count, skipped_countСчётчики отправленных, освоенных, выполненных с помощью и пропущенных заданий. Официальные баллы читайте в результате.
result_idID готового официального результата либо null. В обучении официальный результат не создаётся.
variant.tasks / lesson.tasks / tasksПолные карточки допустимых заданий снимка: условие, формат ответа, варианты выбора, visual/assets, максимум, состояние проверки и действия. Решения доступны только по правилам обучения.

Отсутствующие lesson и variant равны null; неиспользуемый корневой tasks пуст. Изображения загружаются по ссылкам content_url из материалов.

Поля карточки задания

Эти поля находятся внутри каждого элемента variant.tasks, lesson.tasks или tasks.

Поле карточкиНазначение
lesson_run_task_idID задания в снимке занятия: передавайте его при выборе задания. Каталожный 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; максимум известен заранее.
actionscan_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 соответствующей команды.

POST …/task-attempts · выбрать задание
{
  "lesson_run_task_id": "77777777-7777-7777-7777-777777777777"
}
POST …/answers · официальный ответ
{
  "answer": ["4"]
}
POST …/messages · вопрос ИИ
{
  "message": "Объясни условие"
}
PUT …/feedback · оценка сообщения
{
  "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_sessionid совпадает с 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) и завершённого занятия текущего задания нет.
interactioncan_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

idempotency_conflict

Тот же ключ использован с другим телом. Для нового действия создайте новый ключ; для повтора восстановите исходное тело.
409

idempotency_in_progress

Команда ещё выполняется. Повторите позже с прежним ключом и телом.
409

lesson_tasks_missing

В выбранном уроке нет заданий или в непустом составе экзамена нет обязательных заданий role=exam, is_required=true. Выберите подходящий контент.
409

exam_variant_tasks_missing

У выбранного опубликованного экзаменационного варианта нет заданий. Ошибка возникает при разрешении источника exam_variant в обоих режимах, до проверки экзаменационного состава.
409

task_answer_locked

Попытка больше не принимает ответы: экзаменационный ответ принят либо учебная попытка завершена. При потере подтверждения повторите исходный запрос с тем же ключом.
422

Параметры или предусловия

Проверьте обязательные поля, UUID, единственный источник, отсутствие дублей заданий. При complete_onboarding_required проверьте режим подготовки в профиле.
503

Зависимость недоступна

Если передан Retry-After, выдержите указанную задержку. Сохраните ключ и исходное тело; не запускайте бесконечные автоматические повторы.

Пример бизнес-ошибки

409 Conflict · application/json
{
  "detail": "idempotency_conflict"
}

При структурной ошибке валидации поле detail может содержать список ошибок с указанием поля, а не строку.

Справочник API

Полные схемы, допустимые типы ответов и остальные методы учебного процесса.