Справочник инструментов#
Агент разговаривает с платформой инструментами MCP. Наборов два, и живут они
на разных адресах: ученический — <адрес сервиса>/mcp, кураторский —
<адрес сервиса>/authoring. Токен у них один и тот же; что человеку
доступно, решают роли во Frappe, а не выбор адреса.
Инструменты вызывает агент, а не вы. Поэтому в каждом разделе есть пример просьбы обычными словами — вызов агент подберёт сам.
Раздел устроен одинаково: назначение, параметры, что приходит в ответ и отказы, которые возвращает именно этот метод. Общие правила отказов — в конце страницы.
Обзор#
Инструменты ученика — их получает агент, который ведёт занятие.
| Инструмент | Назначение |
|---|---|
artifact |
прочитать документы курса ученика — перечень или один целиком |
choose |
предложить ученику выбор кнопками |
complete_lesson |
закрыть урок, у которого нет обязательной проверки знаний |
course_outline |
программа курса: главы, уроки, цели уроков со статусами |
enroll |
записать ученика на курс из каталога |
forget |
удалить заметку об ученике по ключу |
get_my_progress |
сводка по ученику: курсы, просрочки, последние занятия |
lesson_item |
подробности пункта урока по ключу |
list_catalog |
курсы, на которые ученик может записаться сам, и анонсы |
list_my_courses |
курсы ученика с прогрессом и дедлайнами |
mark_goal |
отметить разобранный пункт урока со свидетельством |
my_homework |
домашние задания ученика: статус, срок, комментарий куратора |
my_notes |
показать ученику, что о нём запомнено |
my_reports |
репорты ученика: статус и ответ автора |
notify_when_released |
подписать ученика на письмо о выходе анонсированного курса |
org_report |
отчёт по обучению своей организации (для руководителя) |
remember |
запомнить об ученике то, что пригодится дальше |
report_issue |
сообщить авторам курса, что мешает учиться |
request_quiz |
начать проверку знаний и получить первый вопрос |
start_lesson |
начать занятие: карта урока, указания агенту, с чего начать |
store_homework_file |
сдать файлы из окна домашнего задания (зовёт окно, не модель) |
student_detail |
подробности по одному сотруднику (для руководителя) |
submit_answer |
отправить ответ ученика и получить вердикт |
submit_homework |
сдать или поправить текст домашнего задания |
update_artifact |
записать раздел документа курса: строки или поля |
upload_homework_file |
показать ученику окно сдачи файлов домашнего задания |
whoami |
под какой учётной записью вошёл ученик |
Инструменты куратора — ими агент работает с курсом вместе с куратором: смотрит релиз, публикует курс, ведёт заметки и репорты. Сам курс меняется только новым релизом — командой конвейера, не этими инструментами.
| Инструмент | Назначение |
|---|---|
add_note |
задать куратору вопрос на месте релиза |
announce_course |
показать курс в каталоге как анонс, до выхода |
course_notes |
заметки куратора по ключам релиза |
course_release |
действующий релиз курса — с ответами квиза и пакетом агента урока |
course_releases |
история релизов курса: версии, даты, какой действует |
course_reports |
репорты агентов учеников о курсе |
create_course |
завести курс до первого релиза — для анонса |
goal_runs |
прохождения учеников: уроки, цели, отмеченные пункты со свидетельствами |
list_courses |
курсы платформы, их ключи и действующие релизы |
publish_course |
открыть курс из релиза ученикам |
reply_note |
ответить в нить заметки |
resolve_note |
отметить заметку сделанной и сказать, что поменялось |
resolve_report |
сменить статус репорта и ответить ученику, что сделано |
unpublish_course |
убрать курс из каталога |
update_course |
поправить название и описания анонса |
Инструменты ученика#
Этот набор получает агент, подключённый к ученическому адресу /mcp. Он же
работает в веб-чате платформы: маршрут занятия там тот же, и различает
каналы сама платформа, а не набор инструментов.
Здесь же лежат два инструмента отчётности — org_report и
student_detail. Их видит всякий подключившийся, и это
осознанно: данные закрыты правами, у не-руководителя отчёт пуст.
Пространства. У ученика одна учётная запись, а курсы и документы
разложены по пространствам: личному и каждой организации, где он состоит.
Прогресс общий: урок, пройденный лично, пройден и для компании. Документ у
каждого пространства свой — один курс может дать два документа. Ученик
выбирает пространство в интерфейсе платформы или просит агента
(set_space); инструменты списков работают в выбранном, а
инструменты курса — в пространстве начатого занятия по этому курсу, иначе в
выбранном. Параметр space называет пространство явно; пространство, которого
у ученика нет, — отказ space_not_available, курса в названном пространстве
нет — course_not_in_space.
Занятие по цепочке. Агент открывает урок start_lesson:
в ответе — карта урока (цели и их пункты со статусами), указания автора
агенту и опора для объяснения, рамка курса, что известно об ученике и с чего
начать. Подробности пункта агент берёт lesson_item, когда
дошёл до него, а разобранный пункт сразу отмечает mark_goal со
свидетельством — что ученик сделал или сказал. Когда обязательные пункты
закрыты, урок проверяет квиз (request_quiz,
submit_answer), а урок без обязательного квиза закрывает
complete_lesson. Правила ведения приходят тремя
пакетами: «старт и разбор» — в ответе start_lesson, «квиз» — в
request_quiz, «закрытие» — в последнем ответе квиза и в complete_lesson.
Поле next в ответах start_lesson, lesson_item, mark_goal и квиза
называет следующий шаг. В веб-чате все три пакета
стоят в системных инструкциях, и в ответах их нет.
Пункты урока и свидетельства видят агент и авторы курса — чтобы улучшать
курс (goal_runs). Ученику и руководителю платформа показывает
цели урока и их статусы: на странице курса, в
course_outline, в шапке веб-чата и в
student_detail. Занятие с агентом идёт по курсу,
выпущенному релизом; у другого курса методы занятия отказывают
course_not_released.
Домашнее задание. У урока может быть задание от автора — одно на всех
учеников. Ученик получает его, когда урок закрыт, и сдаёт текстом, файлами
или тем и другим — как задал автор: агенту (submit_homework,
upload_homework_file) или на странице урока. Каждое
сохранение — новая версия ответа, и куратор видит все. На зачёт урока
домашка не влияет. Сдача живёт в пространстве, как документ: занятие в
организации даёт сдачу, которую видит её руководитель, личное — личную.
Идентификаторы курсов, уроков и занятий агент между сессиями не помнит. Он берёт их из ответов: курс — из списка курсов, урок — из программы курса, занятие и попытку — из ответа на начало занятия и на запрос проверки знаний.
artifact#
Показывает агенту документы, которые ученик собирает по ходу курса, — список или один документ целиком.
Параметры
course— идентификатор курса. Обязательный.artifact— ключ документа (напримерagreements_log). Необязательный; без него приходит перечень.space— чей документ: организация илиpersonal. Необязательный; без него — пространство начатого занятия по курсу, иначе выбранное. В ответеspace— чей прочитан.
В ответе. Без ключа — перечень документов курса: ключ, название, зачем документ ученику, сколько разделов всего и сколько заполнено. С ключом — документ по разделам, в порядке, который задал автор курса.
Раздел бывает двух видов — rows:
many— раздел ведётся строками, как журнал: строка — одна договорённость, один риск. Строки приходят вitems, у каждой —id(A1,A2…) и заполненные клетки.one— раздел заполняется один раз, как анкета: его колонки — поля. Значения приходят вvalues.
Пустые клетки не приходят. У раздела есть columns — колонки (у one —
поля) с названием и обязательностью required: true — обязательна,
false — нет, {"if_column": "driver"} — обязательна, когда заполнена
названная колонка той же строки (у раздела one — поле того же раздела).
description — что записывают в раздел, словами для ученика: он видит его
на странице «Мои документы». lesson — урок, на котором раздел обычно
собирают.
filled — раздел готов: у many есть строки и у каждой заполнены
обязательные колонки, у one непусто хоть одно поле и все обязательные.
empty_cells —
каких обязательных клеток не хватает: row и column у many, field у
one.
{ "key": "agreements", "title": "Договорённости",
"description": "Что сюда записывают", "lesson": "<id урока>", "rows": "many",
"columns": [ { "key": "topic", "title": "Тема", "required": true },
{ "key": "area", "title": "Область",
"required": { "if_column": "driver" } } ],
"items": [ { "id": "A1", "topic": "Ретро раз в две недели" } ],
"filled": true, "empty_cells": [] }
Отказы
not_enrolled— ученик не зачислен на курс; курс ему открывать нечем.organization_suspended— организация ученика приостановлена; зачисление цело, доступ вернётся вместе со статусом.artifact_not_found— в курсе нет документа с таким ключом; посмотрите перечень вызовом без ключа.
Пример просьбы. Ученик: «покажи, что у нас уже записано в журнале договорённостей».
choose#
Предлагает ученику выбор кнопками прямо в чате: вопрос и несколько вариантов. Пример — начало курса, где агент спрашивает, разобрать ли сначала тему или сразу работать на задаче ученика.
Параметры
prompt— вопрос. Обязательный.options— варианты, по кнопке на каждый. Обязательный.title— заголовок карточки. Необязательный.
В ответе. Клиент, который умеет показывать интерфейс в чате (MCP Apps — Claude, ChatGPT и другие), рисует карточку с кнопками. Нажатая кнопка приходит в разговор репликой ученика ««вопрос» — выбираю: вариант». Клиент без MCP Apps кнопок не покажет, поэтому сервер отвечает ему текстом: задай этот вопрос словами. Агент не ждёт клика, которого не будет. В веб-чате платформы кнопки рисует сама страница.
После вызова агент заканчивает реплику и ждёт ответа. Ответ своими словами тоже засчитывается как выбор.
Отказы. Своих нет — только общие.
Пример просьбы. Отдельно просить не нужно: агент зовёт инструмент сам, когда нужен выбор из готовых вариантов.
complete_lesson#
Закрывает урок, у которого нет обязательной проверки знаний: квиза нет или он не обязателен по политике организации. Как и квиз — только когда закрыты все обязательные пункты урока.
Параметры
session— идентификатор занятия из ответаstart_lesson. Обязательный.
В ответе. Идентификатор урока, статус занятия, следующий урок курса и
empty_blocks — разделы документа этого урока, которые остались
незаполненными. Урок закрывается и с ними; агент говорит ученику, что
осталось дописать.
teaching_rules — правила закрытия урока: домашнее задание, вопрос о том,
помогло ли занятие, следующий урок.
Отказы
not_your_session— занятие принадлежит другому ученику.session_closed(с полемstatus) — занятие уже закрыто или брошено; возвращаться к уроку нужно черезstart_lesson, он заведёт новое занятие.goals_open— открыты обязательные пункты урока; в отказе —goals:[{objective, goal, title}]. Агент разбирает их и отмечаетmark_goal.quiz_required— у урока обязательная проверка знаний. Закрыть его можно только сдачей: этот инструмент не обход проверки, и зачёт ставит сервер.not_enrolled,organization_suspended— доступ к курсу отозван.course_not_released,lesson_not_in_release,run_archived,busy— см. отказы цепочки урока.
Пример просьбы. Ученик: «всё понятно, давай закроем урок».
course_outline#
Показывает программу курса целиком — главы, уроки, цели уроков и что из этого пройдено.
Это единственный способ узнать идентификатор уже пройденного урока:
start_lesson без аргумента ведёт только вперёд.
Параметры
course— идентификатор курса. Обязательный.
В ответе. Главы курса с описанием и прогрессом — сколько уроков начато и
пройдено; в каждой — уроки с идентификатором (id), ключом, названием,
зачином, признаком пройденного и отметкой текущего. У урока — его цели со
статусами (not_started, touched, covered), разделы документа и домашнее
задание. Пунктов целей здесь нет: они только в карте урока у агента. В
programs — цепочки курсов (программы), в которые входит курс: место курса
(«2 из 3»), предыдущий и следующий курс, участник ли ученик. Если ученик
участник цепочки с обязательным порядком, а предыдущий курс ещё не пройден, в
locked_by приходит курс, который пройти раньше.
Инструмент только читает: прохождения уроков не заводит и не сверяет.
Отказы
not_enrolled— ученик не зачислен на курс.organization_suspended— организация ученика приостановлена.course_not_released— курс не выпущен релизом.
Пример просьбы. Ученик: «а что мы проходили в начале курса? хочу вернуться к главе про циклы».
enroll#
Записывает ученика на курс из каталога.
Параметры
course— идентификатор курса изlist_catalog. Обязательный.space— пространство: имя организации изwhoamiилиpersonal. Необязательный; без него — выбранное учеником.
В пространстве организации запись — её назначение ученику по его выбору: курс идёт за её счёт и виден её руководителю в отчёте.
В ответе. Курс, его название и первый урок — занятие можно начинать сразу, отдельный вызов списка курсов не нужен.
Отказы
course_not_published— курс ещё черновик.course_upcoming— курс анонсирован и ещё готовится. Вместо записи —notify_when_released.already_enrolled— ученик уже записан; курс есть вlist_my_courses.course_not_allowed— курс не открыт ни одной организации ученика.program_order(сprogram,program_titleиprevious) — ученик участник программы, где курсы идут по порядку, а предыдущий курс ещё не пройден целиком. Сначала — курс изprevious.
Пример просьбы. Ученик: «запиши меня на курс про переговоры».
fill_document#
Собирает с учеником документ курса, который он уже прошёл, — без повторного обучения. Нужен, когда курс пройден лично, а компания назначила его позже, или человек перешёл в другую компанию: прогресс у него общий, а документ для компании свой и пока пустой.
Параметры
course— идентификатор курса. Обязательный.artifact— ключ документа. Необязательный; без него приходит перечень.space— чей документ: организация изwhoamiилиpersonal. Необязательный; без него — выбранное учеником.
В ответе. То же, что у artifact, и rules — правила
заполнения для агента: не вести уроки заново, идти по незаполненным разделам
в порядке документа, спрашивать о проекте этой организации, записывать словами
ученика через update_artifact с тем же space. Ученику
правила не зачитываются.
Веб-чат платформы этот режим не ведёт: он строится вокруг урока. Документ заполняют со своим агентом или вручную на странице документа.
Отказы. Как у artifact.
Пример просьбы. Ученик: «курс я уже проходил, давай заполним резюме проекта для компании».
forget#
Удаляет заметку об ученике по ключу.
Параметры
key— ключ заметки, напримерroleилиpace. Обязательный.course— идентификатор курса для проекта или наблюдения, записанного при курсе. Необязательный; без него ищется заметка-факт.
В ответе. Удалённый ключ.
Отказы
note_not_found— заметки с таким ключом нет. Проверьте ключ поmy_notes: проект и наблюдение ищутся вместе с курсом, факт — без него.
Пример просьбы. Ученик: «забудь, что я работаю в рознице, — я сменил работу».
get_my_progress#
Даёт сводку по ученику: сколько курсов, что просрочено, чем он занимался в последнее время.
Параметры
space— пространство: имя организации изwhoamiилиpersonal. Необязательный; без него — выбранное учеником.
В ответе. Число курсов и число просроченных; по каждому курсу — дедлайн,
признак просрочки, доля пройденного и documents — сколько разделов в каждом
документе курса и сколько заполнено; последние занятия со статусом и датой
начала. Доля уроков и заполненность документа — разные числа: урок
засчитывает проверка знаний, а не документ.
Отказы. Своих нет — только общие.
Пример просьбы. Ученик: «как у меня дела с обучением, много ли осталось?»
lesson_item#
Отдаёт подробности одного пункта урока — что разобрать с учеником и как понять, что он это умеет.
Карта урока в ответе start_lesson даёт только названия
пунктов; подробности агент берёт, когда дошёл до пункта. Текст адресован
агенту, ученику его не зачитывают.
Параметры
session— идентификатор занятия. Обязательный.goal— ключ пункта изlesson_map, напримерterm:T1. Обязательный.
В ответе. goal — ключ, вид, обязательный ли, название и статус пункта;
details — подробности из пакета урока. Свидетельства отметки в ответе нет.
У открытого пункта next — разобрать его и отметить mark_goal.
Инструмент только читает: прохождение урока не заводит и не сверяет.
Отказы
not_your_session— занятие принадлежит другому ученику.goal_unknown— в уроке нет такого пункта или он снят новым релизом курса; в отказе — ключи пунктов урока.not_enrolled,organization_suspended— доступ к курсу отозван.course_not_released,lesson_not_in_release— см. отказы цепочки урока.
Пример просьбы. Отдельно просить не нужно: агент берёт подробности, когда доходит до пункта.
list_catalog#
Показывает курсы, на которые ученик может записаться сам.
Показывает только доступное: уже начатые курсы сюда не попадают, а сотруднику компании видны курсы, открытые его организациям. У кого организаций нет — весь опубликованный каталог.
Параметры
space— пространство: имя организации изwhoamiилиpersonal. Необязательный; без него — выбранное учеником.
Здесь же анонсы — курсы, которые готовятся: записаться на них нельзя, можно попросить сообщить о выходе.
В ответе. Список курсов: идентификатор, название, краткое описание для
карточки и upcoming — анонс ли это. У анонса ещё objectives — цели курса,
о которых агент расскажет, — и notify: подписан ли ученик на письмо о
выходе. Срока выхода в ответе нет, и агент его не называет.
programs — цепочки курсов (программы), в которые входит курс: место курса
(«2 из 3»), предыдущий и следующий курс, участник ли ученик. Если ученик
участник цепочки с обязательным порядком, а предыдущий курс ещё не пройден,
в locked_by приходит курс, который пройти раньше. Запертый курс агент не
предлагает, а называет тот, что пройти раньше: запись на запертый откажет
program_order.
Отказы. Своих нет — только общие.
Пример просьбы. Ученик: «что ещё есть на платформе, чему можно поучиться?»
list_my_courses#
Показывает курсы ученика с прогрессом и дедлайнами.
Параметры
space— пространство: имя организации изwhoamiилиpersonal. Необязательный; без него — выбранное учеником.
В ответе. Пространство (space) и курсы. В личном — все курсы
ученика, в пространстве организации — назначенные ею или взятые из её
каталога. По каждому курсу: название, организация, признак обязательности,
дедлайн и просрочка, число уроков и пройденных, следующий урок. У ученика,
записавшегося самостоятельно, поля назначения пустые.
programs — цепочки курсов (программы), в которые входит курс: место курса
(«2 из 3»), предыдущий и следующий курс, участник ли ученик. Если ученик
участник цепочки с обязательным порядком, а предыдущий курс ещё не пройден,
в locked_by приходит курс, который пройти раньше. Курс пройден — агент
предлагает следующий курс цепочки.
Курсы приостановленной организации в список не попадают, а зачисление на них сохраняется.
Отказы. Своих нет — только общие.
Пример просьбы. Ученик: «что у меня в работе и что горит?» — или «что проходить после этого курса?»
mark_goal#
Отмечает пункт урока, как только его разобрали: термин, выбор, исполнение или заблуждение, которое нужно было опровергнуть. Следующее занятие опирается на отметки — даже если это занятие прервётся.
Параметры
session— идентификатор занятия. Обязательный.goal— ключ пункта изlesson_mapответаstart_lesson. Обязательный.status— обязательный:done— ученик показал это на своей задаче;planned— запланировал применить;not_needed— необязательный пункт не понадобился (заблуждение не проявилось); обязательному так отметить нельзя;open— вернуть пункт в работу; свидетельство не нужно и стирается.evidence— что именно ученик сделал или сказал, не длиннее 500 знаков. Нужен для всех статусов, кромеopen; пустой не передаётся, и требует его сервер (evidence_required). Свидетельство видят авторы курса, чтобы улучшать курс (goal_runs): в нём — что ученик сделал или сказал, без личных данных. Жалоба ученика на урок идёт не сюда, а вreport_issue.resume_from— одна фраза, с чего продолжить урок, если занятие прервётся, не длиннее 500 знаков. Необязательный; без него прежняя заметка остаётся. Следующий агент строит от неё мостик (start.opening: return).
В ответе. goal и status; objective — цель пункта: ключ, статус
(not_started, touched, covered) и open — её обязательные пункты, которые
ещё открыты; lesson — статус урока; next_step — следующий шаг данными и
next — тот же шаг фразой для агента:
next_step |
Что дальше |
|---|---|
{"kind": "goal", "objective", "goal", "title"} |
следующий открытый обязательный пункт |
{"kind": "quiz"} |
обязательные пункты закрыты — проверка знаний |
{"kind": "complete"} |
закрыты, а обязательного квиза нет — complete_lesson |
null |
урок пройден |
Отметка «не по порядку» записывается: платформа не отказывает, а говорит, что
по цели ещё открыто и что дальше. Повторная отметка пункта заменяет прежнюю —
статус, свидетельство, время и занятие. Цель разобрана, когда закрыты (done
или planned) все её обязательные пункты; урок разобран, когда разобраны все
цели. Пункты и свидетельства видят агент и авторы курса
(goal_runs); ученик видит статусы целей —
на странице курса и в шапке веб-чата («темы урока: 2 из 5»). Отметка двигает
активность занятия: занятие, где агент только отмечает пункты, не считается
брошенным.
Отказы
not_your_session— занятие принадлежит другому ученику.session_closed(с полемstatus) — занятие уже закрыто или брошено; урок продолжают в новом занятии —start_lesson.not_enrolled,organization_suspended— доступ к курсу отозван.goal_unknown— в уроке нет такого пункта; в отказе — ключи пунктов урока.goal_removed— пункт снят из урока новым релизом.goal_status_unknown— статус не из четырёх; в отказе —allowed.not_needed_required— обязательный пункт отмеченnot_needed; в отказе —allowed.evidence_required— закрывающая отметка без свидетельства.evidence_too_long(сlimitиlength) — свидетельство длиннее предела.resume_from_too_long(сlimitиlength) — заметка «с чего продолжить» длиннее 500 знаков.course_not_released,lesson_not_in_release,run_archived,busy— см. отказы цепочки урока.
Пример просьбы. Отдельно просить не нужно: агент отмечает пункты сам, по ходу разбора.
my_homework#
Показывает домашние задания ученика: что выдано, что сдано, что вернули на доработку, какой срок.
Параметры
course— идентификатор курса. Необязательный; без него — все курсы пространства.lesson— идентификатор урока. Необязательный; с ним приходит одна домашка целиком — так агент читает текущий ответ, прежде чем его дополнить.space— пространство: имя организации изwhoamiилиpersonal. Необязательный; без него сcourseилиlesson— пространство начатого занятия по курсу, иначе выбранное учеником.
В ответе. space и список items, недавние сверху. У каждой домашки —
курс и урок с названиями, lesson_url — адрес урока, где она сдаётся в вебе,
название задания, статус, срок (due_at), признак просрочки (overdue),
номер текущей версии ответа и last_comment — комментарий куратора к
последнему возврату на доработку или отмене приёма. С lesson — ещё
homework (задание: описание, режим ответа, правило срока) и submission
(текущий ответ, файлы, журнал событий).
status |
Что значит |
|---|---|
Assigned |
выдана при закрытии урока, ещё не сдана |
Submitted |
сдана, ждёт куратора |
Returned |
куратор вернул на доработку или отменил приём |
Accepted |
куратор принял, правка закрыта |
Просрочка — признак, а не статус: срок прошёл, а от ученика ждут действия
(Assigned или Returned).
Отказы
not_enrolled— ученик не записан на курс.organization_suspended— организация пространства приостановлена.space_not_available— такого пространства у ученика нет.course_not_in_space— курса в названном пространстве нет.lesson_not_found— такого урока нет.
Пример просьбы. Ученик: «что у меня висит по домашкам?»
my_notes#
Показывает ученику, что о нём запомнено.
На занятии заметки приходят в history ответа start_lesson;
этот инструмент нужен, когда ученик спрашивает вне занятия.
Параметры
course— идентификатор курса. Необязательный; с ним к фактам добавляются проект и наблюдения этого курса.
В ответе. facts (о человеке), observations (как учится), project
(на чём учится в этом курсе) и projects_elsewhere — проекты других курсов,
пока у этого курса своего нет: агент спрашивает, берём ли тот же. У каждой
записи ключ, текст и даты — когда появилась и когда обновлялась; у проекта
другого курса — ещё курс и его название.
Отказы. Своих нет — только общие.
Пример просьбы. Ученик: «что ты обо мне запомнил?»
my_reports#
Показывает репорты, которые агент отправил авторам курса за ученика, и что с ними стало.
Видны только репорты с занятий самого ученика. Кто ещё жаловался на то же место, не приходит.
Параметры
course— идентификатор курса. Необязательный; без него приходят репорты по всем курсам.
В ответе. Список reports, свежие сверху. У каждого репорта номер
(id), вид, урок и его название, цель урока, текст, время отправки, статус,
ответ автора (resolution) и время, когда репорт закрыли (resolved_at).
status |
Что значит |
|---|---|
new |
автор ещё не смотрел |
in_progress |
автор разбирается |
fixed |
курс поправили |
rejected |
автор решил не менять курс |
duplicate |
о том же уже сообщали, правят по тому репорту |
Ответ автора агент пересказывает близко к тексту. У дубля без своего ответа приходит ответ на тот репорт, дублем которого он признан.
Отказы. Своих нет — только общие.
Пример просьбы. Ученик: «что там с моим замечанием про второй вопрос?»
notify_when_released#
Подписывает ученика на письмо о выходе анонсированного курса или снимает подписку. Подписка — то, что можно сделать с анонсом вместо записи.
Параметры
course— идентификатор анонса изlist_catalog(у негоupcoming). Обязательный.notify—falseснимает подписку. Необязательный, по умолчаниюtrue.
В ответе. Курс, его название и notify — подписан ли ученик теперь.
Повторный вызов ничего не меняет. Письмо уходит на почту ученика один раз,
когда курс откроют.
Отказы
course_not_upcoming— подписка на курс, который не анонсирован: он уже открыт, снят или его нет. Отписаться можно от любого курса.
Пример просьбы. Ученик: «напиши мне, когда выйдет курс про стыки между отделами» или «больше не присылай про этот курс».
org_report#
Отчёт руководителя по обучению своей организации.
Параметры
course— идентификатор курса, чтобы сузить отчёт до одного курса. Необязательный.status—not_started,in_progressилиcompleted. Необязательный.
В ответе. Строки «человек × курс»: имя и учётная запись, организация,
статус, доля пройденного, дедлайн, обязательность, просрочка, дата
последней активности и document — сколько разделов в документах курса и
сколько из них заполнил сотрудник. По второму числу видно, собран ли документ
у того, кто курс уже прошёл.
Отказы. Своих нет. Сотруднику без роли руководителя отчёт приходит пустым, а не отказом: данные закрыты правами, и ошибки здесь нет.
Пример просьбы. «Покажи, кто из моих сотрудников ещё не начал обязательный курс».
remember#
Записывает об ученике то, что пригодится на следующих занятиях.
Параметры
kind— вид заметки. Обязательный.fact— о человеке: роль, отрасль, размер компании. Живёт у ученика во всех курсах.project— на чём он учится в этом курсе: свой проект, учебный сценарий, роль в сценарии. Живёт при курсе: сценарий одного курса не приходит в другой молча.observation— как учится: темп, что даётся трудно. Живёт при курсе.key— короткий повторяемый ключ вродеrole,projectилиpace. Обязательный. Запись по существующему ключу замещает прежний текст, а не добавляет вторую. Что выяснять об ученике по курсу, говорит рамка курса (course_frameв ответеstart_lesson): агент пишет под её ключами, и по ним заметки приходят вhistoryследующих занятий.text— сама заметка. Обязательный.session— идентификатор занятия. Обязателен для проекта и наблюдения: из него берётся курс.
В ответе. Ключ и вид записанной заметки; посреди занятия — ещё прогресс урока по целям: статусы целей, без пунктов.
Профиль ученика. Для фактов о человеке есть канонические ключи: role,
industry, company, goal, current_task, background, tools,
learning_style, time_budget. Из них складывается профиль: ученик видит
его на странице профиля, правит сам и может заполнить в коротком разговоре с
наставником в боковой панели. Агент пишет под этими ключами, а не под
синонимами — role, а не position, — и роль, названная на уроке, сразу
появляется в профиле. В предел заметок канонические ключи не входят.
Отказы
unknown_note_kind— вид неfact,projectилиobservation.note_key_required— пустой ключ.not_your_session— для проекта или наблюдения не переданsessionили занятие чужое.note_limit_reached(с полемlimit) — ключей в наборе уже предельно много. Заметки по существующим ключам замещаются и предела не двигают.
Пример просьбы. Ученик: «запомни, что я веду две команды, — объясняй с оглядкой на это».
report_issue#
Сообщает авторам курса о том, что мешает учиться на этом уроке.
Параметры
session— идентификатор занятия. Обязательный. Курс, урок и релиз курса сервер проставляет сам.kind— вид репорта. Обязательный:stuck,misconception,material_issue,quiz_question_issue,directive_mismatch,out_of_scope.text— что не так. Обязательный; режется по 2000 символов.question—idвопроса квиза этого урока изrequest_quiz, если репорт о вопросе. Необязательный; автор курса увидит ключ вопроса.objective— цель урока изlesson_map. Необязательный; режется по 140 символов.
В ответе. Номер репорта (report) и его вид. Номер агент называет
ученику: по нему тот найдёт репорт в my_reports. Когда автор
ответит, агент скажет об этом на ближайшем занятии по курсу — через
closed_reports в ответе start_lesson.
Отказы
not_your_session— занятие принадлежит другому ученику.unknown_report_kind(с полемkind) — вид не из списка.report_text_required— описание пустое.question_mismatch(с полемquestion) — вопрос не из квиза этого урока.
Жалоба ученика идёт сюда, а не в свидетельство mark_goal:
на репорты автор отвечает, а свидетельство — о том, что сделал ученик.
Пример просьбы. Ученик: «передай методологу, что второй вопрос понять невозможно».
request_quiz#
Начинает проверку знаний урока и возвращает первый вопрос.
Квиз выдаётся, когда закрыты все обязательные пункты урока, и проверяет весь урок — вопросы из релиза курса. Инструмент всегда в списке: закрытый квиз — отказ со списком того, что осталось разобрать.
Параметры
session— идентификатор занятия. Обязательный.
В ответе. Идентификатор попытки и первый вопрос: текст, вид (choice),
варианты с идентификаторами без признака правильности, номер вопроса и
сколько их всего. Начатая попытка не заводится второй раз — возвращается
открытая. Поле next просит агента показать вопрос целиком — текст и все
варианты — и ждать ответа ученика: отвечать за него нельзя.
teaching_rules — правила проверки знаний.
Открытые попытки курса публикация новой версии переносит или аннулирует сама
— см. submit_answer. Попытку, которую публикация не
застала — её начали в момент публикации, — вызов аннулирует и сразу начинает
новую.
Новая попытка несёт previous_attempt_cancelled — attempt и reason
аннулированной попытки ученика по этому уроку, о которой агенту ещё не
сообщали, — в этом занятии или в прошлом; reason обычно attempt_outdated
(попытку аннулировал сам вызов) или quiz_changed (её аннулировала
публикация, пока ученика не было). next тогда просит агента сказать
ученику, что курс обновился и вопросы начались заново. Сообщается один раз:
если агент уже получил отказ quiz_attempt_cancelled в submit_answer, поля
нет.
В веб-чате это держит и сам сервис: вопрос, выданный в ходе модели, получает
ответ только в следующем ходе, после реплики ученика. submit_answer в том же
ходе модель получает обратно отказом, до платформы он не доходит.
Отказы
not_your_session— занятие принадлежит другому ученику.goals_open— открыты обязательные пункты урока; в отказе —goals:[{objective, goal, title}]. Агент разбирает их и отмечаетmark_goal.quiz_not_configured— у урока нет квиза; урок закрывается черезcomplete_lesson.quiz_attempts_exhausted(сattempts_used) — попытки кончились.retry_too_soon(сretry_after— моментом с часовым поясом) — не прошла пауза между попытками.not_enrolled,organization_suspended— доступ к курсу отозван.course_not_released,lesson_not_in_release(открытую попытку по снятому уроку вызов перед этим аннулирует),run_archived,busy— см. отказы цепочки урока.
Пример просьбы. Ученик: «давай проверим, как я это усвоил».
set_space#
Выбирает пространство, в котором ученик учится: одну из его организаций или личное. Выбор общий с интерфейсом платформы — после него списки курсов, каталог и документы относятся к этому пространству и в браузере, и у агента.
Параметры
space— имя организации изwhoamiилиpersonal. Обязательный.
В ответе. Выбранное пространство (current).
Отказы. space_not_available — такой организации у ученика нет или она
приостановлена.
Пример просьбы. Ученик: «давай теперь позанимаемся для себя, не по работе».
start_lesson#
Начинает занятие по уроку: карта урока, указания автора агенту и с чего начать.
Без аргументов берётся то, чем ученик занимался: урок последнего занятия,
если он не пройден, иначе следующий урок того же курса. Занятий ещё не было —
следующий незакрытый урок курса с ближайшим дедлайном: обязательные и
просроченные идут вперёд. С course —
следующий незакрытый урок этого курса: так агент продолжает курс, о котором
идёт речь, и не открывает урок другого, более срочного. Повторный вызов по
тому же уроку продолжает начатое занятие, а не заводит второе.
Параметры
lesson— идентификатор урока (idизcourse_outline). Необязательный.course— идентификатор курса: взять следующий урок в нём. Необязательный; при переданномlessonне действует.frame— отдавать ли рамку курса (course_frame). По умолчаниюtrue.falseагент передаёт, только если в этом же разговоре уже получил рамку этого курса: протокол сессий не хранит, и платформа не знает, что агент видел, — рамка длинная, и на каждом уроке повторялась бы целиком.space— в чей документ пишет занятие: организация илиpersonal. Необязательный; без него — пространство начатого занятия по курсу, иначе выбранное. Урок одного курса в двух пространствах — два разных занятия, а документ курса дальше пишется туда, где идёт занятие.
В ответе
sessionиspace— занятие и где оно идёт.lesson— урок: идентификатор, ключ, название, зачин (hook), глава, курс и признак просрочкиoverdue; в веб-чате ещё номер урока, сколько их всего, название курса и остаток пробных уроков.course_promise— обещание курса. Зачин и обещание адресованы ученику, и агент их произносит; пустые — если автор их не задал.start.opening— с чего начинать (таблица ниже).lesson_map— цели урока по порядку: ключ, текст, статус и пункты — ключ, вид, обязательный ли, название, статус. Пункты, снятые новым релизом, не приходят. Подробности пункта —lesson_item, отметка —mark_goal.next_step— следующий шаг данными, как уmark_goal;next— с чего начать фразой для агента: сигналы — первыми, затем репорты и домашнее задание прошлого урока, цели урока списком и в какой реплике их назвать, следующий пункт.resume_from— заметка «с чего продолжить» из прошлых занятий по уроку.directiveиmaterial— указания автора к уроку и опора для объяснения. Они адресованы агенту; ученику их не показывают и не пересказывают.course_frame— рамка курса и что выяснять об ученике; только приframe: true.history— что известно об ученике по курсу: прошлые уроки (ключ, название, статус) и их незакрытые цели, заметки — по ключам рамки и свободные. Объём ограничен несколькими прошлыми уроками.closed_reports— репорты ученика по этому курсу, которые авторы закрыли и о которых он ещё не знает; форма та же, что вmy_reports. Приходят один раз: агент в начале занятия, до зачина, одной-двумя фразами говорит, что с ними стало, — номер, статус, ответ автора, — и переходит к уроку.artifact_blocks— разделы документа курса, которые собирают на этом уроке: документ, ключ, название,descriptionи заполнен ли (filled). Строки и поля раздела — вartifact. Это подсказка «сегодня собираем этот раздел», а не ограничение: записать можно любой раздел.section_hints— по ключу раздела: что и в какие колонки записать на этом уроке. Адресованы агенту, какdirective; ученик видитdescriptionраздела.quiz— политика проверки знаний: нужна ли она (required), порог зачёта долей (pass_threshold) и сколько попыток осталось.homework,previous_homework— домашние задания (ниже).signals— наблюдения платформы (ниже).teaching_rules— правила старта и разбора в рамке с пометкой адресата: их ученику не показывают. В веб-чате поля нет: там правила уже стоят в системных инструкциях.
opening |
Когда | С чего начинать |
|---|---|---|
first_in_course |
первое занятие по курсу | знакомство, обещание, зачин, цели |
new_lesson |
новый урок | зачин и цели |
return |
прошло больше суток, и есть незакрытое | мостик от resume_from, затем цели |
repeat |
урок уже проходили: есть отметки пунктов или урок закрыт | одна фраза и выбор: продолжить или заново |
Домашнее задание приходит двумя полями; null — задания нет:
previous_homework— задание предыдущего по порядку курса урока и сдача ученика в пространстве занятия: статус, срок,overdue, номер версии иlast_comment— комментарий куратора к последнему возврату или отмене приёма. Ответа ученика здесь нет — его даётmy_homeworkсlesson. Агент начинает с него занятие, до зачина: не сдано — предлагает сдать.homework— задание этого урока целиком: описание, режим ответа и правило срока (due). Агент озвучивает его, когда урок засчитан.
signals — наблюдения платформы по истории ученика, фразами для агента; поля
нет, когда сказать нечего:
- ученик не раз начинал этот урок и бросал в самом начале, не отметив ни одного пункта, — агент спрашивает, что мешало, и начинает с его задачи;
- половина целей урока разобрана, а документ урока не начат — агент собирает первый раздел;
- срок курса прошёл или к нему нужно проходить от трёх уроков в неделю — агент говорит об этом один раз, без нажима.
Сигнал приходит один раз за занятие, в ответе — не больше трёх. Времени внутри занятия в них нет: агенты плохо толкуют его посреди урока, поэтому платформа считает сама и отдаёт вывод.
Отказы
not_enrolled— ученик не зачислен на курс.organization_suspended— организация ученика приостановлена.lesson_not_found— такого урока нет.nothing_to_study— незакрытых уроков не осталось (только при вызове безlesson; сcourse— в этом курсе, и в отказе естьcourse).web_demo_exhausted(сlessons_usedиlessons_limit) — в веб-чате пройдены все пробные уроки; занятие не заводится, продолжать нужно своим агентом.program_order— курс заперт программой, как уenroll: запись могла появиться раньше вступления в программу.unknown_channel— канал занятия неagentи неweb.course_not_released,busy— см. отказы цепочки урока.
Прошедший дедлайн отказом не является: урок отдаётся, в ответе overdue, а
зачёт фиксируется как поздний.
Пример просьбы. Ученик: «давай заниматься» — или «открой урок про дедлайны ещё раз».
store_homework_file#
Сдаёт файлы, которые ученик бросил в окно домашнего задания
(upload_homework_file). Его зовёт само окно, а не
модель (visibility: app): байты идут base64 мимо контекста модели, прямо на
платформу от имени ученика. Все файлы окна уходят одним вызовом
submit_homework — одной версией ответа; текст ответа
остаётся прежним.
Параметры
lesson— идентификатор урока. Обязательный.files— файлы из зоны загрузки: имя и содержимое base64. Обязательный, непустой.space— пространство сдачи. Необязательный; окно передаёт то, в котором его открыли: названное агентом, а если агент его не назвал — то, что при открытии выбрал сервер. Переключение пространства, пока окно открыто, сдачу не переносит.
В ответе. То же, что у submit_homework: space и
сдача с версиями.
Отказы. Как у submit_homework: больше десяти файлов в
ответе, файл больше предела, больше 30 МБ новых файлов за раз, тип, который
платформа не принимает, принятая домашка.
Пример просьбы. Отдельно просить не нужно: инструмент зовёт окно по кнопке «Сдать».
student_detail#
Подробности по одному сотруднику своей организации: чем занимался и как сдал проверки знаний.
Параметры
user— учётная запись сотрудника. Обязательный.
В ответе. Имя и учётная запись; курсы, назначенные вашими организациями,
с дедлайнами; занятия со статусами и целями урока (sessions[].objectives) —
цель и её статус по прохождению урока; попытки проверок знаний с баллом и
признаком зачёта. Попытка со статусом Cancelled — её аннулировала новая
версия курса: в счёт она не идёт, балл у неё 0, и следующая попытка урока
получает тот же номер.
Пункты целей, свидетельства отметок, тексты ответов ученика, его разговоры с агентом и заметки о нём не отдаются — отчёт про результат, а не про содержание диалога.
Отказы
not_your_student— сотрудник не состоит ни в одной вашей организации.
Пример просьбы. «Покажи подробности по Иванову: где он застрял».
submit_answer#
Отправляет ответ ученика и получает вердикт со следующим вопросом.
Вердикт выносит сервер. Проверять ответы самостоятельно агенту нельзя: зачёт ставится только по итогам этой проверки.
Параметры
attempt— идентификатор попытки изrequest_quiz. Обязательный.question— идентификатор вопроса, на который отвечают. Обязательный.answer— ответ строкой. Обязательный: ключ (id) выбранного варианта ("V2"); текст варианта тоже принимается — сервер сопоставляет его с ключом без учёта регистра и лишних пробелов. Верный вариант у вопроса один.student_words— что ученик написал в ответ на этот вопрос, дословно: не пересказ и не только номер варианта; ответил одной цифрой или буквой — передаётся она. Обязательный. Не проверяется и на вердикт не влияет: хранится в журнале проверки для разбора курса. Длинный текст обрезается.
В ответе. Вердикт (верно или нет; пояснение — только вместе с верным
ответом), следующий вопрос или null и признак завершения попытки. На
последнем вопросе добавляется результат: балл и порог долями, признак зачёта,
objective_results — сколько вопросов по каждой цели отвечено верно — и
статус занятия. У сданной попытки в результате ещё explanations (ниже),
next_lesson и empty_blocks — как у complete_lesson, —
а рядом teaching_rules — правила закрытия урока. Со
следующим вопросом приходит next, как у request_quiz:
показать вопрос и ждать ответа ученика.
Ответ — только то, что ученик написал на этот вопрос, увидев его целиком. Просьба показать вопрос ответом не считается.
Неверный ответ приходит без пояснения и без верного варианта, и агент не
называет его до конца попытки: иначе ученик получил бы ответ до пересдачи.
Сданная попытка приносит explanations — пояснения автора к вопросам, на
которые ученик ответил неверно.
Если попытка не засчитана, в результате есть retry_after — с какого
момента можно пересдать, с часовым поясом, — и attempts_left: сколько
попыток осталось, null — без лимита. Попытки кончились — attempts_left: 0
и retry_after: null: пересдачи не будет. Агент
называет ученику время пересдачи в его местном времени, если оно известно,
иначе с поясом, и не предлагает пересдачу раньше срока — сервер откажет
retry_too_soon.
Новая версия курса посреди попытки. Публикация курса переносит открытую
попытку на новую версию, если квиз урока не изменился: вопросы и данные
ответы остаются, порог — тот, что был у урока на старте попытки. Изменился
квиз или урок снят — попытка аннулируется: в лимит она не идёт и паузы перед
следующей не даёт. Попытку, которую публикация не застала (её начали в момент
публикации), аннулирует без сравнения первый ответ в неё. Ответ в
аннулированную попытку — отказ quiz_attempt_cancelled. Агент говорит
ученику, что курс обновился и проверка начнётся заново, и сам запрашивает
квиз; урок снят — говорит об этом и предлагает следующий урок.
Отказы
student_words_required— слова ученика не переданы или пустые.quiz_attempt_cancelled(сattempt,session,reason) — попытку аннулировала новая версия курса.reason:quiz_changed— квиз урока изменился;attempt_outdated— попытку начали на прежней версии в момент публикации;lesson_removed— урок снят из курса. При первых двух квиз запрашивают заново —request_quizпоsession; приlesson_removedквиза по уроку больше нет.attempt_finished— попытка уже завершена.question_mismatch— вопрос не из этой попытки или на него уже отвечено.not_your_session— попытка принадлежит другому ученику.not_enrolled,organization_suspended— доступ к курсу отозван, пока шла попытка. Доступ перепроверяется на каждом ответе.course_not_released— попытка не по уроку из релиза;busy— попытку в этот момент меняет другой запрос, ответ не принят. См. отказы цепочки урока.
Пример просьбы. Отдельно просить не нужно: агент передаёт ответ ученика сам и зачитывает вердикт сервера.
submit_homework#
Сдаёт или правит текст домашнего задания урока.
Текст заменяет прежний целиком: дополняя ответ, агент сначала читает его
через my_homework с lesson. Файлы ответа остаются как
были; сдают их окном upload_homework_file или на
странице урока. Сдать можно и до закрытия урока — тогда домашка сразу
Submitted.
Параметры
lesson— идентификатор урока. Обязательный.answer— текст ответа, markdown. Обязательный.space— в чьём пространстве сдача. Необязательный; без него — пространство начатого занятия по курсу, иначе выбранное.
В ответе. space и submission — статус, срок, текущая версия, ответ,
файлы (имя, тип, размер, адрес), журнал событий и versions — все
сохранённые версии ответа. Каждое сохранение — новая версия со статусом
Submitted, и куратор видит все версии.
Отказы
not_enrolled,organization_suspended,space_not_available,course_not_in_space,lesson_not_found— как уmy_homework.no_homework— у урока нет домашнего задания.empty_answer— в ответе нет ни текста, ни файлов.answer_mode— задание сдаётся только файлами.accepted_locked— домашку уже приняли: правка закрыта.too_many_files,file_too_large,answer_too_large,file_rejected— пределы файлов; касаются сдачи из окна и страницы урока.file_missing— файл не передан или пуст;invalid_files— список файлов пришёл не в той форме. Оба — от сдачи из окна.busy— эту же сдачу в тот же момент сохраняет другой запрос; повторить сдачу.
Пример просьбы. Ученик: «запиши в домашку: встречу провёл, спонсор согласовал бюджет».
update_artifact#
Записывает в раздел документа курса строки или поля — словами ученика.
Параметры
course— идентификатор курса. Обязательный.artifact— ключ документа. Обязательный.key— ключ раздела. Обязательный; регистр не важен.rows— строки разделаmany: список{"id": "A1", "колонка": "текст"}. Необязательный. Строка безid— новая: ID выдаёт платформа, номера не переиспользуются. Соidменяются только названные клетки, прочие остаются.delete_rows— ID строк разделаmanyна удаление. Необязательный.fields— поля разделаone:{"поле": "текст"}. Необязательный; меняются только названные поля.clear— очистить раздел: уmanyудалить все строки, уone— все поля. По умолчаниюfalse; вместе сrows,delete_rowsилиfieldsне передаётся.space— в чей документ. Необязательный; без него — пространство начатого занятия по курсу, иначе выбранное.
Значение клетки — текст: пробелы по краям обрезаются, пустое значение клетку
стирает, предел — 4000 знаков. Очистка нужна, когда записанное перестало быть
правдой — ученик сменил проект, — а заменить его пока нечем. Вызов без
rows, delete_rows, fields и clear сервер отклоняет: записывать
нечего.
В ответе. Документ, ключ раздела и заполненность: сколько разделов всего
и сколько готово; посреди занятия — ещё прогресс урока по целям: статусы
целей, без пунктов. created — ID строк, которые завела эта запись;
empty_cells — каких обязательных клеток разделу ещё не хватает (row и
column или field). Пустую клетку агент доводит с учеником или ставит
«уточнить у …» с именем и датой — такая клетка считается заполненной.
Сервер проверяет только форму — документ, раздел, колонки и строки есть, значение — текст в пределе. Отвечает ли запись описанию раздела, смотрит агент: на зачёт документ не влияет.
Отказы
not_enrolled,organization_suspended— курс ученику сейчас недоступен.artifact_not_found— в курсе нет документа с таким ключом.artifact_block_not_found— в документе нет такого раздела.artifact_nothing_to_write— не передано ниrows, ниdelete_rows, ниfields, ниclear.artifact_clear_with_content—clearвместе сrows,delete_rowsилиfields.artifact_wrong_section—rowsилиdelete_rowsу разделаone,fieldsу разделаmany; в отказе — вид раздела (rows).artifact_unknown_column,artifact_unknown_field— у раздела нет такой колонки или поля; в отказе — какие есть.artifact_unknown_row— строки с такимidнет.artifact_invalid_value— значение не текст и не число или длиннее 4000 знаков; в отказе — колонка или поле и предел (max). Сparam— параметр не той формы (например,rowsне список строк).artifact_too_many_rows— строк в разделе больше предела.
Пример просьбы. Ученик: «запиши договорённость: ретро раз в две недели, ведёт Аня» или «у нас решения принимаются согласием — так и запиши».
upload_homework_file#
Показывает ученику прямо в чате окно, чтобы сдать файлы домашнего задания урока.
Параметры
lesson— идентификатор урока. Обязательный.space— в чьём пространстве сдача. Необязательный; без него — пространство начатого занятия по курсу, иначе выбранное.
В ответе. Клиент с MCP Apps рисует окно: зона перетаскивания нескольких
файлов (в ответе до 10 файлов, каждый до 10 МБ, за раз — до 30 МБ) и кнопка
«Сдать». Пространство окно фиксирует при открытии.
Файлы уходят на платформу мимо модели одной версией ответа (через
store_homework_file), и окно пишет в разговор
реплику ученика «Сдал файлы домашнего задания…». Клиенту без MCP Apps
приходит текст со ссылкой на урок — агент просит ученика прикрепить файлы в
блоке «Домашнее задание» там.
Отказы.
no_homework— у урока нет домашнего задания;answer_mode— задание сдаётся только текстом: ответ передают черезsubmit_homework;accepted_locked— домашку уже приняли, окно не открывается;- а также
not_enrolled,organization_suspended,space_not_available,course_not_in_space,lesson_not_found.
Пример просьбы. Ученик: «протокол встречи у меня в файле, давай сдам».
whoami#
Говорит, под какой учётной записью вошёл ученик и в каких он организациях.
Нужен, когда список курсов или каталог пуст: «курсов нет» и «вошли не тем аккаунтом» выглядят одинаково, и различает их только это.
Параметры. Нет.
В ответе. Учётная запись, полное имя, организации — название, роль в
организации и признак suspended — и выбранное пространство (space).
Приостановленная организация закрывает доступ к своим курсам — без этого
признака пустой каталог необъясним.
Отказы. Своих нет — только общие.
Пример просьбы. Ученик: «почему у меня пусто? под кем я вообще вошёл?»
Инструменты куратора#
Этот набор живёт на кураторском адресе /authoring. Он требует авторской
роли — Course Creator, Moderator, System Manager или Administrator;
вызов без неё отклоняется ошибкой доступа
(403), а не кодом отказа — у агента ученика нет сценария, в котором он с этим
что-то сделает, и нарушение должно попадать в журнал как нарушение.
Отдельный адрес ничего не защищает: он известен, и токен у ученика тот же. Отказывает авторская роль на стороне Frappe.
Курс меняется только новым релизом. Релиз собирают из карты курса в
репозитории course-design и публикуют командой конвейера — как, сказано в
«Как собрать курс». Инструментов
правки курса здесь нет: набор куратора — чтобы видеть действующий релиз,
открывать и снимать курс, вести заметки и репорты по ключам релиза и смотреть,
как ученики проходят уроки. Тестеров курса выдаёт человек в кабинете автора, а
не агент.
Порядок работы агент получает в инструкциях сервера и в prompt author.
Курсы на платформе общие: список курсов, релизы, заметки и репорты доступны
любой авторской роли. Прохождения учеников (goal_runs) — только
кураторам, которые ведут курс, модераторам и администраторам.
add_note#
Задаёт куратору вопрос на месте курса.
Нужен, когда для правки требуется решение куратора, а его нет в чате. Вопрос
встаёт на своё место в кабинете автора и в очередь «Агент спрашивает»;
куратор отвечает в нити, а ответ агент читает в
course_notes.
Параметры
course— идентификатор курса. Обязательный.target— ключ места в действующем релизе курса:course,chapter.<ключ>,lesson.<ключ>,goal.<урок>/<пункт>и другие — полный перечень вcourse_notes. Ключи берутся изcourse_release. Обязательный.text— вопрос. Обязательный.quote— фрагмент текста, о котором вопрос. Необязательный.
В ответе. Идентификатор заметки, курс, ключ места target, release и
version — релиз, к которому она написана (действующий), lesson_key — урок
места (null у мест вне урока), label — место словами, missing: false,
статус open и waiting_on: author — ход куратора.
Отказы
course_not_found— курса с таким идентификатором нет.course_not_released— у курса нет релиза: ставить заметку не на что.invalid_target— адрес не по форме таблицы мест (where: target).note_target_unknown— адрес по форме, но места с таким ключом в действующем релизе нет (target,release).invalid_note— пустой текст.
Пример просьбы. «Если не уверен, какой пример взять для пункта про эскалацию, — спроси меня в кабинете».
announce_course#
Показывает курс в каталоге до выхода. Записаться на него нельзя, ученик может попросить сообщить о выходе. На странице курса видны только его цели: программа, уроки и документы закрыты.
Цели анонса зависят от того, есть ли у курса релиз:
- курс без релиза — цели задаются здесь, в
objectives, и хранятся в самом курсе; новый список заменяет прежний целиком; - курс из релиза — цели анонса это названия глав действующего релиза;
objectivesему не передаются.
Параметры
course— идентификатор курса. Обязательный.objectives— цели курса списком строк, по цели на пункт. Только для курса без релиза; без них анонс возьмёт цели, заданные раньше.
В ответе. Курс, published и upcoming — оба true — и цели курса в
objectives, ровно как их увидят в каталоге.
Открывает анонс publish_course — когда у курса есть
релиз: первый релиз привязывают к анонсу при публикации, и подписавшимся
уходит письмо. Снимает — unpublish_course.
Отказы
course_not_found— курса с таким идентификатором нет.course_objectives_missing— у курса без релиза нет целей: не переданы и не заданы раньше.course_from_release— цели переданы курсу из релиза.course_has_content— у курса без релиза есть уроки: программу курсу даёт релиз.course_already_published— курс уже открыт ученикам и анонсом не станет.
Пример просьбы. «Покажи курс про переговоры в каталоге как анонс, с тремя целями: подготовить разговор, удержать рамку, договориться о следующем шаге».
course_notes#
Показывает заметки куратора к курсу — очередь из кабинета автора.
Куратор вычитывает действующий релиз в кабинете и ставит заметку прямо на место. С этой очереди стоит начинать работу над курсом.
Параметры
course— идентификатор курса. Обязательный.status—open(в работе, по умолчанию),done(агент отметил сделанным, ждёт проверки куратора),accepted(принято);null— все.lesson— ключ урока: заметки к уроку и местам внутри него. Необязательный.
В ответе. Заметки, старые сверху. У каждой — release и version
(релиз, к которому она написана, а не действующий), ключ места target,
lesson_key — урок места (его хранит заметка: у снятого урока он тот же, что
при записи), label — место словами по действующему релизу,
quote — фрагмент, о котором речь, text, кто и когда написал, нить ответов
replies и waiting_on — чей ход: agent или author, у принятой null.
missing — места нет в действующем релизе: новый релиз снял этот ключ;
подпись тогда — вид места и ключ. Заметка без release — архив прежних мест:
адрес как есть и missing: true.
Фильтр lesson ищет по ключу урока, который хранит заметка: находятся и
заметки урока, уже снятого из программы. Курс без релиза отказом не отвечает — его
заметки только архивные.
Ключи мест:
| Ключ | Место |
|---|---|
course |
курс целиком |
chapter.<ключ> |
глава |
lesson.<ключ> |
урок |
objective.<ключ> |
цель урока |
goal.<урок>/<пункт> |
пункт цели урока |
question.<ключ> |
вопрос квиза |
section.<ключ> |
раздел документа курса |
agent.frame |
рамка курса в пакете агента |
agent.lesson.<ключ> |
срез пакета агента для урока |
agent.item.<урок>/<пункт> |
подробности пункта в пакете агента |
map.<узел> |
узел карты курса |
Отказы
course_not_found— курса с таким идентификатором нет.invalid_note— неизвестный статус.
Пример просьбы. «Посмотри, что я написал по курсу в кабинете».
course_release#
Показывает действующий релиз курса — то, что сейчас у учеников. Только чтение: правка — новым релизом.
Параметры
course— идентификатор курса. Обязательный.lesson— ключ урока. Необязательный: с ним в ответ добавляется срез пакета агента этого урока.
В ответе. course — карточка курса и действующего релиза: ключ курса,
название, release, version, когда и кто опубликовал. Без lesson — ещё
chapters и lessons по порядку релиза с ключами: у урока — глава, зачин,
порог зачёта, разделы документа, домашнее задание, цели с пунктами и
questions — вопросы квиза с вариантами, верным вариантом correct и
пояснением; и document — документ курса по разделам (null, если его нет).
С lesson — только этот урок (lesson, в том же виде) и agent — пакет
агента: рамка курса (frame, learn_about_student) и срез урока (lesson):
то, что агент ученика получает на занятии. Без lesson пакета агента в
ответе нет: он большой, а нужен для одного урока.
Ответы квиза видит только авторская роль: метод отдаёт их куратору, чтобы он проверил собственный квиз, а ученику отказывает в доступе.
Отказы
course_not_found— курса с таким идентификатором нет.course_not_released— у курса нет действующего релиза.lesson_not_in_release— урока с таким ключом в действующем релизе нет (course,lesson_key,release).
Пример просьбы. «Покажи, что сейчас в четвёртом уроке, вместе с указаниями агенту».
course_releases#
Показывает историю релизов курса.
Параметры
course— идентификатор курса. Обязательный.
В ответе. Релизы, свежие сверху: release, version, published_at,
published_by — кто опубликовал, digest — отпечаток файла релиза (тот же
файл — тот же отпечаток), commit — коммит course-design, из которого
версия впервые опубликована (null — опубликована без коммита),
document_key — ключ документа курса (null — документа нет) и active —
действует ли. Тот же релиз, опубликованный ещё раз, новой версии не даёт. У
курса без релиза список пуст.
Содержимое платформа хранит только у действующей версии — его показывает
course_release. От прежних версий остаётся запись из
этого списка; саму прежнюю версию смотрят в git course-design по commit.
У версии без коммита кандидата из истории карты проверяют по digest:
собранный из него релиз даёт тот же отпечаток. Не дал ни один кандидат —
восстановить такую версию нельзя.
Отказы
course_not_found— курса с таким идентификатором нет.
Пример просьбы. «Когда мы последний раз выпускали курс, какая версия сейчас у учеников и из какого она коммита?»
course_reports#
Показывает, на что жалуются агенты, ведущие этот курс.
Репорт шлёт агент ученика, когда курс мешает учиться: материал неверен, вопрос квиза двусмыслен, указание не подходит или ученик сказал об уроке что-то, чего автор не знает.
Параметры
course— идентификатор курса. Обязательный.kind— вид репорта:stuck,misconception,material_issue,quiz_question_issue,directive_mismatch,out_of_scope. Необязательный.lesson— ключ урока. Необязательный. Урок ищется по ключу на его записи: находятся и репорты урока, снятого из программы.status—open(новые и в работе),new,in_progress,fixed,rejectedилиduplicate. Необязательный; без него приходят все.
В ответе. Пятьдесят свежих репортов: номер id, вид, текст, когда
отправлен, release — действующий релиз на момент жалобы (курс с тех пор
могли выпустить заново), lesson_key — ключ урока, objective и
question_key — если репорт о цели или о вопросе квиза. У репорта,
отправленного до первого релиза курса, release — null, lesson_key —
тоже, если у урока нет ключа. У
каждого — status, ответ resolution и resolved_at, когда репорт закрыли.
Закрывают репорт resolve_report.
Кто пожаловался, не приходит: важно, что не так с курсом, а не кто сказал.
Отказы
course_not_found— курса с таким идентификатором нет.unknown_report_kind— вид не из списка.unknown_report_status— статус не из списка.
Пример просьбы. «Посмотри жалобы по курсу за последнее время» или «Покажи, что писали про четвёртый урок».
create_course#
Заводит курс до первого релиза — чтобы показать его в каталоге анонсом
(announce_course). Курс создаётся черновиком без уроков и
ученикам пока не виден.
Курс из релиза этим инструментом не заводят: его заводит первая публикация релиза. Если анонс уже есть, первый релиз привязывают к нему — подписчики «сообщить о выходе» сохраняются.
Параметры
title— название курса. Обязательный.summary— короткий текст для карточки в каталоге. Обязательный.description— полное описание на странице курса. Необязательный; без него берётсяsummary.
В ответе. Идентификатор курса, название и признак публикации.
Кто завёл курс, становится его инструктором. Первая публикация релиза со списком кураторов этот набор заменит.
Отказы. Своих нет — только общие.
Пример просьбы. «Заведи анонс курса „Переговоры для руководителей групп“, в каталоге пиши, что он про подготовку к сложному разговору».
goal_runs#
Показывает, как ученики проходят уроки курса: что разобрано, где застряли, что засчитано и на каком свидетельстве. По этому автор улучшает курс.
Параметры
course— идентификатор курса. Обязательный.lesson— ключ урока. Необязательный. Находятся и прохождения урока, снятого из действующего релиза.start— сколько прохождений пропустить. Необязательный, по умолчанию 0.limit— сколько прохождений на странице: не больше 20, оно же по умолчанию. Необязательный.
В ответе. Курс, lesson, start, limit, has_more — есть ли
следующая страница (её start — нынешний плюс число прохождений на этой) — и
runs: прохождения уроков, сначала недавно начатые. У каждого — ученик
(student: id пользователя и полное имя name), урок (ключ и название; у
урока, снятого из релиза, — последнее название, с которым он был; у
прохождения без записи урока название — null), status —
not_started, in_progress, covered или passed,
accepted_at — первый старт урока, started_at — первая отметка пункта,
passed_at — урок закрыт, resume_from — с чего агент продолжит. Цели урока
— статус и подтверждена ли квизом; пункты — статус, свидетельство
evidence, когда и в каком занятии отмечены. removed — цель или пункт
сняты новым релизом. Прохождения, сброшенные вместе с прогрессом ученика, не
приходят.
Свидетельства — слова учеников. Они открыты автору, а не другим ученикам и не руководителям: в ответы на репорты и в заметки их не переносят.
Доступ. Видят инструкторы курса — их задаёт публикация релиза списком кураторов из карты курса, — модераторы и администраторы платформы. Куратору, который курс не ведёт, и ученику — отказ доступа (403).
Отказы
course_not_found— курса с таким идентификатором нет.course_not_released— у курса нет релиза: прохождения ведутся только по урокам релиза.invalid_page—startилиlimitне целое или меньше допустимого (where,value).
Пример просьбы. «На каком пункте третьего урока ученики застревают чаще всего?»
list_courses#
Показывает курсы платформы — черновики, анонсы и опубликованные, свежие сверху.
С этого начинается работа: идентификатор курса нужен всем остальным инструментам, а между сессиями агент его не помнит.
Параметры
published— да или нет: сузить список до опубликованных или до черновиков. Необязательный; без него приходят все.
В ответе. По каждому курсу: идентификатор, название, краткое описание,
признаки публикации и анонса, course_key — ключ курса из релиза и
release — версия и дата публикации действующего релиза (у курса без релиза
оба null), число уроков и когда курс правили в последний раз.
Отказы. Своих нет — только общие.
Пример просьбы. «Найди курс про переговоры и скажи, какая версия сейчас у учеников».
publish_course#
Открывает курс ученикам.
Открыть можно только курс с действующим релизом: проверки курса прошли при публикации релиза. Новый релиз уже открытого курса действует сразу — открывать курс заново не нужно.
Параметры
course— идентификатор курса. Обязательный.
В ответе. Курс, признак публикации и warnings — предупреждения проверок
действующего релиза, те же, что вернула его публикация: пустой текст для
ученика, вопрос без пояснения. Их стоит пересказать куратору.
Публикация анонса (announce_course) открывает его для
записи. Тем, кто просил сообщить о выходе, уходит письмо, один раз: сколько
писем ушло — в notified.
Отказы
course_not_found— курса с таким идентификатором нет.course_not_released— у курса нет релиза; сначала его публикуют конвейером.
Пример просьбы. «Релиз вышел — открывай курс».
reply_note#
Отвечает в нить заметки, не меняя её статуса.
Уточнить, спросить, объяснить, почему правка сделана иначе. Ход переходит к куратору: в кабинете заметка встаёт в очередь «Агент спрашивает».
Параметры
note— идентификатор заметки. Обязательный.text— ответ. Обязательный.
В ответе. Идентификатор заметки, статус, waiting_on и число ответов в
нити.
Отказы
note_not_found— заметки с таким идентификатором нет.invalid_note— пустой текст.
Пример просьбы. «Спроси в заметке про эскалацию, какую отрасль взять для примера».
resolve_note#
Отмечает заметку сделанной и говорит куратору, что поменялось.
Отмечают, когда правка вышла новым релизом: куратор проверяет её в
действующем релизе. Комментарий уходит в нить: что и где изменено и в какой
версии — так, чтобы куратор проверил правку, не перечитывая курс целиком.
Принимает или возвращает заметку куратор в кабинете; вернёт — она снова
откроется в course_notes с его ответом.
Параметры
note— идентификатор заметки. Обязательный.comment— что поменяли. Обязательный.
В ответе. Идентификатор заметки, статус done, waiting_on: author и
число ответов в нити.
Отказы
note_not_found— заметки с таким идентификатором нет.invalid_transition— заметка не открыта — уже сделана или принята — или комментарий пуст.
Пример просьбы. «Релиз пятый вышел — отметь заметки, которые он закрывает».
resolve_report#
Меняет статус репорта и отвечает, что сделано.
Ответ видит ученик, с чьего занятия пришёл репорт: его агент перескажет ответ
на ближайшем занятии по курсу и покажет в my_reports.
Поэтому в ответе — что поменялось в курсе: урок и суть правки, а у отказа —
почему курс остаётся прежним. Без оценок ученика и без имён: кто пожаловался,
автору не приходит, и ответ — о курсе.
Параметры
report— номер репорта изcourse_reports. Обязательный.status—in_progress(взяли в работу),fixed(курс поправлен новым релизом),rejected(менять не будут) илиduplicate(о том же уже есть репорт). Обязательный.resolution— ответ ученику. Обязателен дляfixedиrejected.duplicate_of— номер репорта, дублем которого признан этот. Обязателен дляduplicate; репорт того же курса.
В ответе. Номер репорта, новый статус, ответ, время закрытия
resolved_at и duplicate_of.
Отказы.
report_not_found— репорта нет.unknown_report_status— статус не из списка.invalid_report_transition— переход не разрешён: закрытый репорт —fixed,rejected,duplicate— можно только вернуть вin_progress, а перевести в тот же статус нельзя; в отказе — текущий статус иallowed.report_resolution_required— уfixedилиrejectedпустой ответ.duplicate_of_required— уduplicateнетduplicate_of.invalid_duplicate_of— такого репорта нет, он из другого курса или это сам репорт.
Ответ перезаписывается при каждом вызове: не передан — ученик не увидит
прежний, например после возврата в in_progress.
Пример просьбы. «Я переписал второй вопрос четвёртого урока, релиз вышел — закрой репорт про него и напиши ученику, что поменялось».
unpublish_course#
Убирает курс из каталога — и анонс тоже. Прогресс учеников сохраняется.
Удаления курсов на платформе нет — снятие с публикации и есть способ убрать курс.
Параметры
course— идентификатор курса. Обязательный.
В ответе. Курс и признак публикации.
Отказы
course_not_found— курса с таким идентификатором нет.
Пример просьбы. «Сними курс с публикации, пока мы переписываем вторую главу».
update_course#
Правит название, описания или обещание курса до первого релиза — анонса. Карточку курса из релиза пишет релиз.
Параметры
course— идентификатор курса. Обязательный.title— новое название. Необязательный.summary— новый текст для карточки в каталоге. Необязательный.description— новое полное описание. Необязательный.promise— обещание курса: что человек получит к концу, так, чтобы в конце это можно было проверить. Агент ученика произносит его на первом занятии по курсу. Необязательный.
Поле, которое не передали, остаётся прежним.
В ответе. Идентификатор курса, название, краткое описание и обещание.
Отказы
course_not_found— курса с таким идентификатором нет.course_from_release— курс собран из релиза: карточку меняет новый релиз.course_has_content— у курса есть уроки.
Пример просьбы. «Перепиши описание анонса: курс для руководителей групп, а не для продавцов».
Когда сервер откажет#
Отказы бывают двух видов, и путать их не нужно.
Ожидаемый отказ — это нормальный ход дела: попытки кончились, урок уже в работе, у курса ещё нет релиза. Платформа отвечает на такой вызов успешно, а причину кладёт машинным кодом в тело ответа. Ошибкой транспорта ожидаемый отказ не приходит: HTTP-ошибку формирует фреймворк, и машинного кода в ней не остаётся — в проде она не несёт ничего, кроме имени исключения.
Вот настоящий ответ платформы на просьбу о квизе, пока в уроке не разобран обязательный пункт:
{ "ok": false,
"error": { "code": "goals_open",
"message": "Сначала разберите обязательные пункты урока: mark_goal",
"goals": [ { "objective": "l-2-D1", "goal": "term:T1",
"title": "Термин «пример»" } ] } }
Три вещи в этом ответе важны по отдельности. code — по нему агент решает,
что делать дальше. message — то, что можно пересказать человеку.
Остальные поля — подробности именно этого отказа: какие пункты урока ещё
открыты, когда можно повторить попытку.
Ветвиться нужно по коду, а не по тексту. Тексты меняются и переводятся, коды — нет. Именно поэтому в разделах этой страницы перечислены коды: они и есть контракт.
MCP-сервис доносит отказ до агента целиком — тем же кодом и теми же
подробностями, — но подаёт его как ошибку инструмента. Агент видит строку
вида Сначала разберите обязательные пункты урока: mark_goal [goals_open]
goals: [{"objective": "l-2-D1", "goal": "term:T1", "title": "Термин «пример»"}].
Сбой — другое дело. Он приходит HTTP-статусом, кода отказа в нём нет, и тело разбирать не следует: там внутренние структуры. Сервис переводит такой ответ в одну фразу для агента:
| Что случилось | Что говорит сервис |
|---|---|
| Токен истёк или отозван | «сессия истекла, требуется повторная авторизация» |
| Нет прав на эти данные (403) | «нет доступа к этим данным» |
| Объекта не существует (404) | «запрошенного объекта не существует» |
| Запрос нарушает инвариант (417) | «сервис отклонил запрос как некорректный» |
| Слишком много запросов (429) | «слишком много запросов, попробуйте чуть позже» |
| Сбой или недоступность (5xx, обрыв связи) | «учебный сервис сейчас недоступен, попробуйте позже» |
Автоматических повторов нет: решение о повторе принимает агент — у него есть контекст занятия.
Отказы цепочки урока#
Методы занятия — start_lesson, lesson_item,
mark_goal, request_quiz,
submit_answer, complete_lesson и
course_outline — отказывают одинаково:
| Код | Что случилось | Что делать |
|---|---|---|
course_not_released |
курс не выпущен релизом, и занятия с агентом по нему нет | сказать ученику и предложить другой курс |
goals_open |
квиз или закрытие урока, пока открыты обязательные пункты; в отказе — goals: [{objective, goal, title}] |
разобрать пункты и отметить mark_goal |
run_archived |
прогресс ученика по курсу сброшен, прохождение в архиве | начать урок заново через start_lesson |
busy |
то же занятие в этот момент меняет другой запрос | повторить вызов один раз |
quiz_attempt_cancelled |
только submit_answer: ответ в попытку квиза, которую аннулировала новая версия курса (attempt, session, reason) |
quiz_changed, attempt_outdated — запросить квиз заново request_quiz; lesson_removed — перейти к следующему уроку |
lesson_not_in_release |
урок снят из действующего релиза курса (course, lesson_key, release) |
перейти к следующему уроку; какие уроки есть — course_outline |
goal_unknown |
в уроке нет такого пункта; в отказе — ключи пунктов | взять ключ из lesson_map |
goal_removed |
отметка пункта, снятого из урока новым релизом курса (lesson_item по такому пункту отвечает goal_unknown) |
пропустить его |
goal_status_unknown |
статус пункта не из open, done, planned, not_needed |
передать статус из allowed |
not_needed_required |
обязательный пункт отмечен not_needed |
разобрать пункт или вернуть open |
evidence_required |
закрывающая отметка без свидетельства | передать, что ученик сделал или сказал |
evidence_too_long |
свидетельство длиннее 500 знаков (limit, length) |
сократить до одной-двух фраз |
resume_from_too_long |
заметка «с чего продолжить» длиннее 500 знаков (limit, length) |
одна фраза, не пересказ |
busy и run_archived возвращают только пишущие методы. course_outline и
lesson_item только читают: прохождение они не блокируют и не сверяют, и этих
отказов у них нет.
Отказы пишущих методов приходят до первой записи: отказанный вызов ничего не
меняет, кроме сверки прохождения с действующим релизом курса. Исключение —
попытка квиза, отставшая от новой версии: submit_answer в неё и
request_quiz с отказом lesson_not_in_release сначала аннулируют попытку,
потом отказывают.
Отказы курса из релиза#
Курс на платформе меняется только новым релизом, и кураторские инструменты отказывают одинаково, когда просьба с этим расходится:
| Код | Что случилось | Что делать |
|---|---|---|
course_not_released |
у курса нет релиза: открыть его (publish_course), посмотреть релиз (course_release), прохождения (goal_runs) или поставить заметку (add_note) нельзя |
опубликовать релиз конвейером |
course_from_release |
правка карточки (update_course) или целей анонса (announce_course) у курса из релиза |
поправить карту курса и выпустить новый релиз |
course_has_content |
правка карточки или анонс курса без релиза, у которого есть уроки | то же: программу и карточку курсу даёт релиз |
lesson_not_in_release |
урока с таким ключом нет в действующем релизе (course_release) |
взять ключ из релиза целиком |
invalid_target |
адрес заметки (add_note) не по форме таблицы мест |
поправить адрес по course_notes |
note_target_unknown |
адрес по форме, но такого ключа в действующем релизе нет | взять ключ из course_release |
Отдельно стоит ошибка доступа у кураторских инструментов. Вызов без
авторской роли (Course Creator, Moderator, System Manager,
Administrator) отклоняется именно 403, а не кодом отказа:
это нарушение доступа, и оно должно попадать в журнал как нарушение.