🤖 AI-агенты для бизнеса

8. HTTP API

🔵 Сервер отдаёт HTTP-управляющую плоскость плюс чат-эндпоинт, стримящий Server-Sent Events (SSE). Список эндпоинтов печатается при старте в логе.


8.1 Эндпоинты

Страницы и статика (публичные)

Endpoint Описание
GET / markdown-сайт (лендинг)
GET /site/ · GET /site/:page тот же сайт в подпути
GET /sessions · /budgets · /cron · /workflows · /dashboard админ-UI
GET /agents/:name страница одного агента
GET /widget · /widget.js · /dist/* виджет и его ассеты
GET /demo · /demo/overlay демо виджета / оверлей поверх живых сайтов
GET /distrib/* архивы дистрибутива (linux/windows zip + sha256, android apk)
GET /proxy?url=… · /proxy/content?url=… HTTP-прокси для фронтенда
GET /login · POST /login · POST /logout web-логин админ-UI
GET /login/oidc/:provider · GET /login/oidc/:provider/callback OIDC-логин админ-UI (Google/Яндекс/Тинькофф)
GET /v1/login/methods список включённых OIDC-провайдеров
GET /v1/login/widget/:provider · GET /v1/login/widget/:provider/callback OIDC-логин конечного пользователя в виджете (popup)
POST /v1/login/widget/password логин конечного пользователя по auth.users (выдаёт x-user-token)
GET /v1/connectors/callback callback OAuth-коннекторов (Google Drive и т.п.)
GET /v1/allowed-senders/:template · POST /v1/allowed-senders/:template динамический allowlist отправителей (список · добавить) 🔒
DELETE /v1/allowed-senders/:template/:identity удалить отправителя из allowlist 🔒

Публичный API

Endpoint Описание
GET /health healthcheck
GET /v1/models доступные модели
GET /v1/templates шаблоны агентов (welcome, tools)
POST /v1/chat/completions чат с агентом (SSE, собственный формат)
POST /v1/continuations следующая страница лениво-пагинированной таблицы
POST /v1/uploads загрузка вложений (файл/скриншот/фото) в scratch сессии
POST /v1/input-response ответ на агентский запрос вложения (request_attachment)
POST /v1/approval-response ответ конечного пользователя на inline-одобрение (виджет)
POST /v1/sessions/:id закрыть сессию (публичный — виджет шлёт sendBeacon)
POST /v1/inbound/:template разовый ход агента от внешней системы (JSON, опционально bearer)
POST /v1/user-ticket выдать HMAC-подписанный токен идентичности
POST /v1/feedback like/dislike по ответу
POST /v1/workflows/:name/webhook webhook-триггер воркфлоу (защищён токеном воркфлоу)
/ext/** (кастомные) http_route / static_route — пользовательские REST-эндпоинты и статика, добавленные глобально (config/routes/) или агентами (route_files:); auth public/bearer/token_env/user на маршрут (см. §21)

Админ-API 🔒

Endpoint Описание
GET /v1/agents · POST /v1/agents список агентов · создать агента
GET /v1/agents/:name снапшот одного агента
DELETE /v1/agents/:pid убить агента и потомков
POST /v1/agents/:name/bench/run запустить бенчмарк шаблона
GET /v1/agents/:name/bench/runs · /bench/runs/:id история и деталь бенчмарка
GET /v1/sessions список сессий
GET /v1/sessions/:id · DELETE /v1/sessions/:id деталь сессии · закрыть
GET /v1/budgets бюджетные группы и процессы
GET /v1/cron · DELETE /v1/cron/:name задания cron и история · удалить
GET /v1/workflows · POST /v1/workflows/:name/run воркфлоу · запустить
GET /v1/workflows/runs/:id · /runs/:id/events запуск воркфлоу · его события
GET /v1/dashboard системный дашборд (нагрузка, токены, серии)
GET /v1/feedback/stats статистика оценок
GET /v1/users соответствия канал → пользователь
POST /v1/users/link · POST /v1/users/:id/unlink слить/разъединить идентичности
GET /v1/memory/:scope инспекция долгой памяти скоупа
GET /v1/approvals очередь ожидающих одобрений (операторский inbox)
POST /v1/approvals/:request_id одобрить/отклонить {approved, comment}
GET/POST /v1/approvals/roles логические роли апруверов · создать/обновить
DELETE /v1/approvals/roles/:name удалить роль
POST/DELETE /v1/approvals/roles/:name/members… добавить/удалить участника роли

🔒 = требует Authorization: Bearer <токен>, когда настроена админ-auth (см. §8.3).

Пагинация

Списочные эндпоинты (/v1/sessions, /v1/agents, /v1/templates, /v1/budgets) принимают ?limit=N&offset=M. limit — размер страницы (обрезается к 1–1000, по умолчанию 100), offset — сколько строк пропустить (по умолчанию 0). Ответы включают total/v1/sessions — ещё history_total). /v1/sessions добавляет history_truncated: true, когда прошлых сессий больше текущей страницы.


8.2 Chat completions

POST /v1/chat/completions стримит Server-Sent Events (SSE). Путь и форма запроса похожи на OpenAI, но формат ответа свой — он не совместим с OpenAI-SDK (нет choices[].delta, нет data: [DONE]).

curl http://127.0.0.1:3000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "ngu-agent",
    "messages": [{"role": "user", "content": "Как поступить в НГУ?"}]
  }'

Поля запроса:

Поле Обязат. Смысл
model да имя шаблона (ngu-agent, drom-agent, …) или встроенный assistant
messages да список {role, content}; в контекст попадают роли user и system
session нет токен сессии — одна сессия = один изолированный агент. Опусти — legacy-режим (общий агент шаблона)
attachments нет список [{name, mime, size}] файлов, уже загруженных через POST /v1/uploads в scratch сессии — сервер впрыснет сообщение с их описанием
stream нет принимается для совместимости, игнорируется — всегда стрим
temperature нет принимается, игнорируется
max_tokens нет принимается, игнорируется

Заголовок X-User-Id задаёт user_id для per-user-бюджетов и скоупа памяти. Когда настроен auth.web_user_secret_env, сервер требует HMAC-подписанный X-User-Token (из POST /v1/user-ticket); см. §8.8.

Ответ (события SSE)

Тело — поток именованных SSE-событий; done — единственное, которое есть всегда.

event Полезная нагрузка data
token {"content": "<токен>", "final": bool}
tool_call {"name": "<инструмент>", "body": "<рендер вызова>"}
tool_progress {"name": "<инструмент>", "body": "<прогресс>"}
tool_result {"name": "<инструмент>", "body": "<рендер результата>"}
result_blocks `{"name": "<инструмент>", "blocks": [ {type: "text"
input_request {"request_id": "<id>", "kind": "file"|"screenshot"|"photo", "description": "..."} — агент запросил вложение; ответить через POST /v1/input-response
budget {"tokens": n, "prompt": n, "completion": n, "cached": n, "total": n, "cost": "$x.xxxx"}
done {} — стрим завершён

result_blocks несёт визуальный слой инструмента (графики, таблицы, текст, файлы); блок table может включать continuation: {id}POST /v1/continuations с этим id вернёт блоки следующей страницы, а блок file несёт name, mime и data (base64) для скачивания. См. общие поля.

Ошибки (неизвестная модель, ошибка сессии, исчерпание бюджета, rate-limit) сообщаются как token-события внутри 200, а не HTTP-кодом ошибки.

8.2.1 Вложения (uploads / input-response)

Загрузка файлов от пользователя (виджет, Android) в scratch-каталог сессии — POST /v1/uploads (multipart/form-data):

Ответ — {"session_id": "...", "files": [{"name", "mime", "size"}, …]}. Файлы пишутся в <scratch>/<session>/, дальше агент читает их по имени (file_tool temp, shell_tool {{temp_dir}}, vision_tool). Учитывается attachments.enabled/max_size шаблона; при отключённых вложениях — 400.

Агентский запрос вложения (тул request_attachment) приходит как SSE-событие input_request; виджет показывает подсказку, пользователь прикрепляет файл, тот загружается через /v1/uploads, после чего виджет резолвит запрос:

curl http://127.0.0.1:3000/v1/input-response \
  -H 'Content-Type: application/json' \
  -d '{"request_id": "<id>", "files": [{"name": "photo.jpg", "mime": "image/jpeg", "size": 12345}]}'

Пустой files = пользователь отказался. Неизвестный/просроченный request_id — 404; ожидание по умолчанию 300 сек (поле timeout_secs тула).


8.3 Auth

Эндпоинты 🔒 принимают либо Authorization: Bearer <токен> (для API-клиентов), либо cookie agentos_session (для браузера после web-логина).

Если auth настроена, но ни один credential не разрешается — админ-API отдаёт 401 на каждый запрос (fail-closed). Без токенов и пользователей админ-API открыт (dev-режим).

# API-клиент (bearer)
curl -H 'Authorization: Bearer <token>' http://127.0.0.1:3000/v1/sessions

# Web-логин (браузерный поток)
curl -c cookies.txt -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"<password>"}' \
  http://127.0.0.1:3000/login
curl -b cookies.txt http://127.0.0.1:3000/v1/sessions

8.4 Встраивание виджета

<script src="http://127.0.0.1:3000/widget.js"></script>

Виджет отдаётся с /widget, общается с /v1/chat/completions и закрывает сессии через POST /v1/sessions/:id (sendBeacon). Полный разбор виджета (конфигурация, выбор модели, демо) — в §19.


8.5 Прокси

/proxy и /proxy/content скачивают URL для фронтенда. Ограничения:


8.6 Healthcheck

curl http://127.0.0.1:3000/health

8.7 HTTPS / TLS

Задай AGENT_OS_TLS_CERT и AGENT_OS_TLS_KEY (пути к PEM) — сервер поднимет HTTPS. Иначе — обычный HTTP на AGENT_OS_BIND (по умолчанию 127.0.0.1:3000).


8.8 Входящий webhook и идентичность

Входящий webhook

POST /v1/inbound/:template — внешняя система (CRM, ERP, мониторинг, бэкенд формы, …) запускает один ход агента и синхронно читает ответ — без SSE, без массива messages.

curl -X POST http://127.0.0.1:3000/v1/inbound/ngu-agent \
  -H 'Content-Type: application/json' \
  -d '{"message":"какие общежития у НГУ?","session_id":"crm-123"}'

Запрос:

Поле Обязат. Смысл
message да сообщение пользователя
session_id нет стабильный id для переиспользования контекста; опущен = новая сессия
user_id нет идентичность конечного пользователя (Origin::Webhook); опущен = аноним

Ответ: {"answer": "...", "status": "success", "session_id": "...", "cost_usd": 0.0, "prompt_tokens": n, "completion_tokens": n, "data": null}.

Auth — bearer-токен при заданном inbound.token_env (пусто = открыто, dev).

Токены идентичности конечных пользователей

Когда auth.web_user_secret_env указывает env с HMAC-секретом, виджет получает подписанный токен и шлёт его как X-User-Token вместо самоназванного X-User-Id:

curl -X POST http://127.0.0.1:3000/v1/user-ticket \
  -H 'Content-Type: application/json' -d '{"user_id":"cw-browser-id"}'
# → {"user_id":"cw-browser-id","token":"cw-browser-id.<hmac>"}

Без секрета сервер доверяет X-User-Id напрямую (dev-режим).

Канонические идентичности пользователей

GET /v1/users перечисляет соответствия (origin, external_id) → canonical_id; оператор может слить два канальных id (например web-id и Telegram-id), чтобы они делили память, бюджет и состояние:

curl -X POST http://127.0.0.1:3000/v1/users/link \
  -H 'Authorization: Bearer <token>' \
  -d '{"survivor":"cw-browser-id","merged":"tg:123"}'

Слияние мигрирует scoped state store, долгую память и in-memory бюджетные ведра; дальнейшие сессии обоих каналов резолвятся в survivor.


8.9 Обратная связь (feedback)

Виджет шлёт оценки ответов (like / dislike / cleared) в POST /v1/feedback (публичный), а статистика — в GET /v1/feedback/stats (🔒).

Оценка замыкает цикл качества: хук memory по лайку/дизлайку поднимает/опускает importance фактов, вспомненных в этом ходе (§6.6). Тело запроса включает value, user_text, session.