Перейти к содержимому

API чата с агентом

В Santiago встроен AI-агент, который работает внутри демона: вы отправляете ему инструкцию на естественном языке, и он сам управляет запущенным профилем с помощью API автоматизации и скилла агента. На этой странице описана собственная HTTP-поверхность агента — проверка того, настроен ли LLM, сохранение API-ключа, стриминг чата как Server-Sent Events и управление историей по каждому профилю.

Все эндпоинты находятся под базовым адресом демона http://localhost:7891/api и используют стандартную обёртку: { "ok": true, "data": {...} } при успехе или { "ok": false, "error": { "code", "message" } } при ошибке. Демон слушает только localhost.

МетодПутьНазначение
GET/api/agent/statusНастроен ли LLM? Список доступных моделей.
GET/api/agent/api-keyПолучить настроенный ключ для провайдера (замаскированный).
POST/api/agent/api-keyУстановить API-ключ для провайдера.
DELETE/api/agent/api-keyУдалить API-ключ для провайдера.
GET/api/agent/:profileId/historyПрочитать сохранённые сообщения чата для профиля.
POST/api/agent/:profileId/chatОтправить сообщение → SSE-стрим выполнения агента.
POST/api/agent/:profileId/stopПрервать текущее выполнение агента.
DELETE/api/agent/:profileIdОчистить историю и уничтожить сессию.

Провайдер по умолчанию — openai, если поле provider или query-параметр опущены.

Прежде чем агент сможет работать, ему нужен API-ключ LLM. Ключи хранятся по каждому провайдеру в локальном хранилище авторизации демона, а не в профиле.

GET /api/agent/status сообщает, настроен ли ключ хотя бы одного провайдера и какие модели доступны.

Check if the agent is ready
curl -s http://localhost:7891/api/agent/status | jq .data
Response
{
"configured": true,
"models": [
{ "provider": "openai", "id": "gpt-5", "name": "GPT-5" }
]
}

Когда ключ не задан, демон возвращает { "configured": false, "models": [] } — на этом эндпоинте он никогда не отдаёт ошибку.

POST /api/agent/api-key сохраняет ключ для провайдера. Поле apiKey обязательно; пустое значение или значение из одних пробелов вернёт 400 BAD_REQUEST.

Store an API key
curl -s http://localhost:7891/api/agent/api-key -X POST \
-H 'Content-Type: application/json' -d '{
"provider": "openai",
"apiKey": "sk-..."
}'
Response
{ "ok": true }

GET /api/agent/api-key возвращает сохранённый ключ для провайдера, замаскированный до первых и последних четырёх символов. Передайте ?provider=, чтобы указать провайдера, отличного от значения по умолчанию.

Read the stored key for a provider
curl -s "http://localhost:7891/api/agent/api-key?provider=openai" | jq .data
Response
{ "provider": "openai", "hasKey": true, "maskedKey": "sk-1…7f9c" }

Если ключ не сохранён, hasKey равно false, а maskedKey равно null.

Remove the stored key for a provider
curl -s "http://localhost:7891/api/agent/api-key?provider=openai" -X DELETE
Response
{ "ok": true }

POST /api/agent/:profileId/chat отправляет одно пользовательское сообщение и стримит выполнение агента обратно как Server-Sent Events. Профиль должен быть запущен — если это не так, демон отвечает 404 с PROFILE_NOT_RUNNING. Пустое message вернёт 400 BAD_REQUEST.

Send a message and stream the run
curl -N -s http://localhost:7891/api/agent/$PROFILE/chat -X POST \
-H 'Content-Type: application/json' -d '{
"message": "Go to example.com and tell me the page title"
}'

Флаг -N отключает буферизацию curl, чтобы вы видели события по мере их поступления. Ответ имеет Content-Type: text/event-stream; каждое событие — строка вида data: <json>\n\n.

Каждая строка data: несёт JSON-объект с дискриминатором type. Это события, которые демон отправляет в ходе выполнения:

typeПоляЗначение
tool_startname, paramsАгент начал вызов инструмента автоматизации (например, navigate, click).
tool_endname, okЭтот вызов инструмента завершился; ok: false означает ошибку.
text_deltacontentФрагмент текстового ответа агента — соединяйте дельты по порядку.
usageinput, output, totalИтоги по токенам, отправляются один раз после завершения выполнения.
doneАгент завершил этот ход.
errormessageВыполнение завершилось ошибкой; сообщение также сохраняется в истории.
Example event stream
data: {"type":"tool_start","name":"navigate","params":{"url":"https://example.com"}}
data: {"type":"tool_end","name":"navigate","ok":true}
data: {"type":"tool_start","name":"snapshot","params":{}}
data: {"type":"tool_end","name":"snapshot","ok":true}
data: {"type":"text_delta","content":"The page title is "}
data: {"type":"text_delta","content":"\"Example Domain\"."}
data: {"type":"done"}
data: {"type":"usage","input":4821,"output":137,"total":4958}

Чтобы прервать долгий ход, вызовите эндпоинт остановки с тем же id профиля. Он возвращает, было ли прервано активное выполнение.

Abort the current run
curl -s http://localhost:7891/api/agent/$PROFILE/stop -X POST | jq .data
Response
{ "aborted": true }

Каждый профиль хранит свою собственную историю чата в демоне. Сообщения сохраняются по мере общения — пользовательские сообщения, вызовы инструментов агентом, текст агента и любые ошибки.

Read stored messages for a profile
curl -s http://localhost:7891/api/agent/$PROFILE/history | jq .data
Response (shape)
{
"messages": [
{ "type": "user", "content": "Go to example.com and tell me the page title" },
{ "type": "tool", "content": "", "toolName": "navigate", "params": { "url": "https://example.com" } },
{ "type": "agent", "content": "The page title is \"Example Domain\"." }
]
}

Поле type сообщения принимает одно из значений user, tool (несёт toolName и params), agent или error.

DELETE /api/agent/:profileId очищает сохранённые сообщения и уничтожает находящуюся в памяти сессию агента для этого профиля. Следующий чат начинается с чистого листа (и заново подключает скилл).

Reset the agent for a profile
curl -s http://localhost:7891/api/agent/$PROFILE -X DELETE
Response
{ "ok": true }
СтатусcodeКогда
400BAD_REQUESTapiKey или message отсутствует/пустое.
404PROFILE_NOT_RUNNINGЦелевой профиль не запущен.
500AGENT_ERRORНе удалось создать сессию.
500INTERNAL_ERRORСохранение или удаление ключа завершилось ошибкой.

Сбои в середине стрима во время чата не являются HTTP-ошибками — соединение уже вернуло 200, поэтому сбой приходит как SSE-событие error.

  • Локальный HTTP API — базовые пути, обёртка и модель безопасности localhost.
  • Установка скилла агента — запуск собственного агента поверх API автоматизации вместо встроенного.
  • Справочник API — полный каталог действий автоматизации по каждому действию, которым управляет агент.
  • Автономный режим — долгие сессии агента с заданной продолжительностью работы.