# `:server` — HTTP/SSE фасад для `:proto` (KMP, JVM-only) ## Что это Ktor-маршрут, экспонирующий `Agent` из `:proto` в виде JSON-API: `POST /agentik/conversations`, `POST /agentik/conversations/:id/send`, `GET /agentik/conversations/:id/events` (SSE), `GET /health`, `GET /agentik/conversations`. - **stateful** — сервер не принимает полную историю, только новые сообщения. История хранится там, где развёрнут `Agent`. - **декларативно** — `interface Agent` → HTTP; никакой магии, никаких обёрток. Контракт и сериализация — тоже декларативные (kotlinx-json с snake_case-дискриминаторами). Решает: позволяет собрать любой собственный front-end (CLI/TUI/Web/ IRC/MCP) общаясь с одним сервером по стабильному wire-контракту. ## Где используется - `:standalone` подключает `Route.agentikAgent(agent)` в свой embedded Netty engine. - Любые клиенты (наши `:client`, `:agentik-cli`, `:agentik-tui`, или внешние web-фронтенды) идут через этот контракт. ## Как подключить ```kotlin // build.gradle.kts (KMP JVM target) plugins { id("pw.binom.agentik.server-conventions") version "0.1.0" } dependencies { api("pw.binom.agentik:server:0.1.0") api("pw.binom.agentik:proto:0.1.0") } // ваш код: fun Application.module(agent: Agent) { install(ContentNegotiation) { json(agentikJson) } install(SSE) routing { route("/agentik") { agentikAgent(agent) } } } ``` ## Версии `gradle/libs.versions.toml` → `[versions] agentik-server`. ## Эндпоинты (path по умолчанию `/agentik`, через `agentikAgent(agent, "/my")`) | Метод | Путь | Что делает | |---|---|---| | `POST` | `/conversations` | Создать диалог (body: `{title?}`) | | `GET` | `/conversations` | Список диалогов (по `?offset=&limit=`) | | `GET` | `/conversations/:id` | Снимок диалога + count | | `GET` | `/conversations/:id/messages` | История сообщений (по `?after=`) | | `POST` | `/conversations/:id/rename` | Переименовать (body: `{title}`) | | `DELETE` | `/conversations/:id` | Удалить | | `POST` | `/conversations/:id/send` | Send-флоу (body: `{content:[…]}` → SSE) | | `GET` | `/conversations/:id/events` | Live подписка (SSE) | | `POST` | `/conversations/:id/interrupt` | Прервать текущий `send()` | `Content-Type: text/event-stream` всегда для SSE, ноль-лишних заголовков. Сообщения: `event: ` (`message`, `start_reasoning`, `start_response`, `append_text`, `append_image`, `end`, `interrupted`, `error`) + `data: `. ## Тесты ``` ./gradlew :server:jvmTest ``` Покрывают: маппинг JSON ↔ Event, SSE framing, error-handling, 404 / 400 ответы, корректную обработку `Instant` в `kotlinx-datetime`. ## Чего здесь НЕТ - Никакого LLM-кода, tool-вызовов, прерываний. Только mapping Agent ↔ HTTP. - Никакой БД, никакого storage. Это задача `Agent`-имплементации. - Никакого CORS-конфига по умолчанию — добавляйте на свой engine. ## Текущий статус Используется продакшеном. Wire-контракт стабильный; новые Event'ы добавляются только с snake_case-дискриминаторами и строго обратно совместимо.