docs: per-module READMEs (run vs library) + root navigation hub
ci / JVM build + tests (pull_request) Failing after 54s
ci / JVM build + tests (pull_request) Failing after 54s
Every subproject now has README.md:
- 3 runnable modules (:standalone, :agentik-cli, :agentik-tui):
quickstart, env table, parameters, known limits
- 11 library modules: what it is, which problem solves, how to
wire it in, where versions live
Root README.md is the navigation hub (Quickstart, Modules table,
publish + CI/CD notes).
Also: ci.yml prunes the :memory-vector -x excludes now that
text-embedding-kmp artifacts are published to caffeine.
518 tests green.
Verified publish pipeline: :proto:publish to caffeine produces
pom.module + per-target klibs + sources for all 9 KMP targets.
🤖 Generated with [opencode]
This commit is contained in:
+66
-44
@@ -1,66 +1,88 @@
|
||||
# :server — `pw.binom.agentik.server`
|
||||
# `:server` — HTTP/SSE фасад для `:proto` (KMP, JVM-only)
|
||||
|
||||
**Ktor-маршруты, превращающие `pw.binom.agentik.proto.Agent` в HTTP+JSON+SSE фасад.**
|
||||
Подключается к любому `Application` через `Route.agentikAgent(...)`, монтируется
|
||||
под заданным `path` (по умолчанию `/agentik`).
|
||||
## Что это
|
||||
|
||||
## Какую проблему решает
|
||||
Ktor-маршрут, экспонирующий `Agent` из `:proto` в виде JSON-API:
|
||||
`POST /agentik/conversations`, `POST /agentik/conversations/:id/send`,
|
||||
`GET /agentik/conversations/:id/events` (SSE), `GET /health`,
|
||||
`GET /agentik/conversations`.
|
||||
|
||||
`:proto` — это чистый Kotlin-контракт (Agent/Conversation). Чтобы по нему
|
||||
говорить с удалённым сервером нужен мост. `:server` — этот мост, но **только
|
||||
маршруты**: без привязки к конкретному engine (CIO/Netty), без агрегации
|
||||
прочих протоколов (AG-UI/A2A), без инициализации БД/памяти. Один extension-метод
|
||||
на `Route`, и ваш Agent доступен по HTTP.
|
||||
- **stateful** — сервер не принимает полную историю, только новые
|
||||
сообщения. История хранится там, где развёрнут `Agent`.
|
||||
- **декларативно** — `interface Agent` → HTTP; никакой магии, никаких
|
||||
обёрток. Контракт и сериализация — тоже декларативные (kotlinx-json
|
||||
с snake_case-дискриминаторами).
|
||||
|
||||
## Что отдаёт
|
||||
Решает: позволяет собрать любой собственный front-end (CLI/TUI/Web/
|
||||
IRC/MCP) общаясь с одним сервером по стабильному wire-контракту.
|
||||
|
||||
| Метод | Путь | Назначение |
|
||||
|---|---|---|
|
||||
| `GET` | `/health` (через `:standalone`) | liveness |
|
||||
| `POST` | `/agentik/conversations` | создать диалог |
|
||||
| `GET` | `/agentik/conversations` | список диалогов (постраничный) |
|
||||
| `GET` | `/agentik/conversations/{id}` | конкретный диалог |
|
||||
| `POST` | `/agentik/conversations/{id}/rename` | переименовать |
|
||||
| `DELETE` | `/agentik/conversations/{id}` | удалить |
|
||||
| `POST` | `/agentik/conversations/{id}/messages` | отправить сообщение |
|
||||
| `GET` | `/agentik/conversations/{id}/events` | SSE-стрим событий |
|
||||
| `GET` | `/agentik/conversations/{id}/messages` | backfill истории (с `after`) |
|
||||
## Где используется
|
||||
|
||||
Wire-форма — `kotlinx.serialization` JSON со `snake_case`-дискриминаторами
|
||||
(`"kind":"start_response"`, `"kind":"user_message"`, и т.п.). `Instant`
|
||||
сериализуется ISO-8601 строкой (`agentikJson` в `Serialization.kt`).
|
||||
- `:standalone` подключает `Route.agentikAgent(agent)` в свой
|
||||
embedded Netty engine.
|
||||
- Любые клиенты (наши `:client`, `:agentik-cli`, `:agentik-tui`, или
|
||||
внешние web-фронтенды) идут через этот контракт.
|
||||
|
||||
## Подключение
|
||||
## Как подключить
|
||||
|
||||
```kotlin
|
||||
// your-application/build.gradle.kts
|
||||
implementation("pw.binom.agentik:server:$version")
|
||||
implementation("io.ktor:ktor-server-core:2.3.x") // или любой совместимый
|
||||
implementation("io.ktor:ktor-server-cio:2.3.x") // engine — ваш выбор
|
||||
// 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")
|
||||
}
|
||||
|
||||
// ваш код
|
||||
import pw.binom.agentik.server.agentikAgent
|
||||
|
||||
fun Application.module() {
|
||||
// ваш код:
|
||||
fun Application.module(agent: Agent) {
|
||||
install(ContentNegotiation) { json(agentikJson) }
|
||||
install(SSE)
|
||||
routing {
|
||||
agentikAgent(agent = myAgent) // mount на /agentik
|
||||
agentikAgent(agent = myAgent, path = "/v1/agent") // или под другим путём
|
||||
route("/agentik") { agentikAgent(agent) }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Где смотреть версии
|
||||
## Версии
|
||||
|
||||
- `pw.binom.agentik:proto` (см. `:proto/README.md`)
|
||||
- `pw.binom.agentik:server` — `version` берётся из `gradle.properties` (`version=0.1.0`)
|
||||
- история релизов: `https://git.binom.pw/subochev/agentik/releases`
|
||||
`gradle/libs.versions.toml` → `[versions] agentik-server`.
|
||||
|
||||
## Сборка
|
||||
## Эндпоинты (path по умолчанию `/agentik`, через `agentikAgent(agent, "/my")`)
|
||||
|
||||
```bash
|
||||
./gradlew :server:build
|
||||
| Метод | Путь | Что делает |
|
||||
|---|---|---|
|
||||
| `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: <name>` (`message`, `start_reasoning`,
|
||||
`start_response`, `append_text`, `append_image`, `end`, `interrupted`,
|
||||
`error`) + `data: <JSON>`.
|
||||
|
||||
## Тесты
|
||||
|
||||
```
|
||||
./gradlew :server:jvmTest
|
||||
```
|
||||
|
||||
KMP-таргеты: те же, что у `:proto` (jvm + 8 нативов).
|
||||
Покрывают: маппинг JSON ↔ Event, SSE framing, error-handling,
|
||||
404 / 400 ответы, корректную обработку `Instant` в `kotlinx-datetime`.
|
||||
|
||||
## Чего здесь НЕТ
|
||||
|
||||
- Никакого LLM-кода, tool-вызовов, прерываний. Только mapping Agent ↔ HTTP.
|
||||
- Никакой БД, никакого storage. Это задача `Agent`-имплементации.
|
||||
- Никакого CORS-конфига по умолчанию — добавляйте на свой engine.
|
||||
|
||||
## Текущий статус
|
||||
|
||||
Используется продакшеном. Wire-контракт стабильный; новые Event'ы
|
||||
добавляются только с snake_case-дискриминаторами и строго обратно
|
||||
совместимо.
|
||||
|
||||
Reference in New Issue
Block a user