Разделы · 8/11
Вопросы человеку
POST …/dialogs и sparku ask — варианты, подтверждение, таймаут, вложение; как агент спрашивает разрешения.
Как это работает#
POST /v1/integrations/{slug}/dialogs показывает вопрос на островке и держит
соединение открытым, пока человек не ответит (или вопрос не снят). Ответ приходит
в теле того же HTTP-ответа — ждать нужно curl или HTTP-клиенту, который умеет
не закрывать соединение по таймауту раньше срока timeout из тела запроса.
У интеграции — не больше одного вопроса без ответа одновременно: второй dialogs
раньше ответа на первый получает 409 dialog_pending. Диалоги должны быть отдельно
включены в настройках интеграции.
Тело запроса#
Вопрос с вариантами — есть options или custom:
{
"message": "Выкатить в прод?",
"title": "Деплой",
"options": ["yes", {"id": "no", "label": "Отмена", "detail": "ничего не делать"}],
"multiple": false,
"custom": false,
"timeout": "10m"
}
Подтверждение — без options и custom:
{"message": "Удалить ветку feature/x?", "accept": "Удалить", "decline": "Оставить", "comment": true}
| Поле | Тип | По умолчанию | Правило |
|---|---|---|---|
message |
строка | — | обязательное, до 600 символов |
title |
строка | адрес интеграции | до 60 символов |
options |
массив строк или {id, label, detail?} |
— | до 9 вариантов; строка — сама себе и id, и label |
multiple |
bool | false |
выбор нескольких — нужно ≥ 2 вариантов |
custom |
bool | false |
добавляет поле свободного ответа |
accept / decline |
строка | «Да» / «Нет» | подписи кнопок подтверждения, до 30 символов |
comment |
bool | false |
у отказа можно оставить комментарий |
timeout |
число секунд или "90s" / "10m" / "2h" |
600 (10 мин) |
от 5 секунд до суток |
attachment |
абсолютный путь | — | файл, который человек может открыть из вопроса; должен существовать |
С options или custom — вопрос с вариантами; иначе — подтверждение двумя
кнопками. Указать одновременно options/custom и accept/decline нельзя —
accept/decline относятся только к подтверждению.
Ответ#
Всегда 200 OK, форма тела зависит от исхода:
| Ситуация | Тело |
|---|---|
| выбрал вариант(ы) | {"answer": "chose", "options": ["yes"]} |
свой ответ (custom) |
{"answer": "custom", "text": "…"} |
| подтвердил | {"answer": "accepted"} |
| отказал | {"answer": "declined"} или {"answer": "declined", "comment": "…"} |
истёк timeout |
{"answer": "expired"} |
| вопрос снят | {"answer": "withdrawn"} |
withdrawn приходит, если: клиент отключился до ответа (тогда, впрочем, отвечать
уже некому — вопрос просто снимается с островка), SparkU закрывается, API выключили
или интеграцию выключили/удалили, пока вопрос ждал ответа.
Спрятать вопрос кнопкой «Скрыть» можно только у интеграции с карточкой — вернуть его на экран можно кнопкой «Ответить» в карточке; до этого он остаётся без ответа на сервере.
Пример: curl#
curl --unix-socket ~/.sparku/run/api.sock \
-H "Authorization: Bearer $SPARKU_TOKEN_DEPLOY" \
-d '{"message": "Выкатить в прод?", "accept": "Да", "decline": "Нет"}' \
http://sparku/v1/integrations/deploy/dialogs
{"answer": "accepted"}
sparku ask#
sparku ask <slug> "вопрос" [-o id:подпись …] [--multi] [--custom]
[--accept Да --decline Нет --comment] [--title …] [--timeout 10m] [--attach файл]
sparku ask deploy "Деплоить в прод?" -o yes:Да -o no:Нет
sparku ask deploy "Куда катить?" -o prod:Прод -o stage:Стейджинг --custom
sparku ask deploy "Удалить ветку?" --accept Удалить --decline Оставить --comment
Выбранные варианты печатаются в stdout по одному на строку (id, не подпись),
свой ответ (custom) — текстом, комментарий отказа — тоже в stdout.
Коды выхода ask#
Отдельные от <sysexits.h>, которыми пользуются push/end/doctor — чтобы в
shell работало if sparku ask deploy "Деплоить?"; then …:
| Код | Значение |
|---|---|
0 |
ответ получен (выбор или свой текст — в stdout) |
1 |
отказ (declined) |
2 |
время вышло, вопрос снят или «Скрыть», SparkU закрылся |
Ошибки транспорта (нет сокета, неверный токен, 409 dialog_pending) возвращают
обычные коды sparku — 69, 77, 69 соответственно, см.
CLI sparku.
if sparku ask deploy "Выкатить в прод?"; then
./deploy.sh
else
echo "деплой отменён"
fi
Для ИИ-агентов#
Агент вроде Claude Code или Codex, который выполняет команды в shell, может
спросить подтверждения у человека тем же путём, каким это делает CI-скрипт: через
sparku ask в интеграцию, которую человек завёл заранее (например, «Агент»
с адресом agent; если у неё есть карточка, вопрос можно спрятать и вернуться к нему). Это не отдельный протокол — агент такой же клиент API, как
любой другой процесс.
if sparku ask agent "Удалить ветку feature/old и её PR на GitHub?" \
--accept Удалить --decline "Не трогать" --timeout 90s; then
git push origin --delete feature/old
gh pr close 42
else
echo "отменено человеком" >&2
exit 1
fi
Пока вопрос висит на островке, агент блокируется на вызове sparku ask — это
ожидаемо: решение принимает человек, и до его ответа выполнять опасный шаг нельзя.
Если человек не отвечает --timeout, по умолчанию 10 минут, ask вернёт 2, и
агент должен трактовать это как отказ, а не как разрешение продолжать.
TIP
У инструмента, которым агент запускает команды, обычно свой таймаут (у Claude Code —
2 минуты по умолчанию). Ставьте --timeout меньше него, иначе агент прервёт ожидание
раньше, чем человек успеет ответить, а вопрос снимется с островка.
Строку-инструкцию для агента (в CLAUDE.md, AGENTS.md и т. п.) можно написать так:
Перед необратимыми действиями (удаление, force-push, деплой, миграции) спроси
человека: sparku ask agent "<что и зачем>" --accept Да --decline Нет --timeout 90s
Код 0 — можно, 1 — отказ, 2 — ответа нет: считай отказом.