🤖 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

Публичный API

Endpoint Описание
GET /health healthcheck
GET /v1/models доступные модели
GET /v1/templates шаблоны агентов (welcome, tools)
POST /v1/chat/completions чат с агентом (SSE, собственный формат)
POST /v1/continuations следующая страница лениво-пагинированной таблицы
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 инспекция долгой памяти скоупа

🔒 = требует 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-режим (общий агент шаблона)
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"
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.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.