Перейти до вмісту

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 або параметр запиту опущено.

Перш ніж агент зможе працювати, йому потрібен 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 }

Отримання ключа (замаскованого)

Section titled “Отримання ключа (замаскованого)”

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, а maskedKeynull.

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.

Очищення історії та завершення сесії

Section titled “Очищення історії та завершення сесії”

DELETE /api/agent/:profileId очищає збережені повідомлення та знищує in-memory сесію агента для цього профілю. Наступний чат починається з чистого аркуша (і повторно інжектує скіл).

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.