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:
+75
-41
@@ -1,67 +1,101 @@
|
||||
# :client — `pw.binom.agentik.client`
|
||||
# `:client` — Ktor-клиент к `:server`/`:proto` (KMP, jvm + native)
|
||||
|
||||
**Ktor-клиент, превращающий HTTP-фасад `:server` обратно в `Agent`/`Conversation` из `:proto`.**
|
||||
Подходит для JVM-приложений (CLI, desktop, integration-тесты).
|
||||
## Что это
|
||||
|
||||
## Какую проблему решает
|
||||
Ktor client (`io.ktor.client.HttpClient` + `ContentNegotiation(json) +
|
||||
Sse`), превращающий HTTP/SSE-фасад `:server` в `Agent`/`Conversation`
|
||||
интерфейсы `:proto`:
|
||||
|
||||
После того, как `:server` выставляет агента по HTTP, встаёт задача: дать
|
||||
вызывающей стороне **тот же интерфейс**, что был на сервере — а не отдельный
|
||||
REST-клиент с хендшейкингом SSE, парсингом полей, ручной постраничной подгрузкой.
|
||||
`:client` — обёртка: `AgentikAgent(baseUrl).createConversation()` возвращает
|
||||
`Conversation`, идентичный серверному, а вызовы `send/getMessages/events`
|
||||
прозрачно ездят по HTTP.
|
||||
- `AgentikAgent(id, baseUrl)` — entry-point фабрики.
|
||||
- `AgentClient` — список и lifecycle диалогов.
|
||||
- `ConversationClient` — `send()`, `events()`, `interrupt()`,
|
||||
`getMessages()`, `rename()`, `close()`.
|
||||
- Внутренний парсер SSE → `Flow<Event>`.
|
||||
|
||||
## Использование
|
||||
Решает: пишем нативный Kotlin-клиент, без curl/JS/Python boilerplate,
|
||||
с теми же типами, что и сервер. Один и тот же клиент работает на
|
||||
JVM, iOS, macOS, Linux, Windows.
|
||||
|
||||
## Где используется
|
||||
|
||||
- `:agentik-cli` — REPL.
|
||||
- `:agentik-tui` — Compose-for-Mosaic клиент.
|
||||
- Любой внешний KMP-проект, который хочет встроить агента в свой UI.
|
||||
|
||||
## Как подключить
|
||||
|
||||
```kotlin
|
||||
import pw.binom.agentik.client.AgentikAgent
|
||||
// build.gradle.kts
|
||||
kotlin {
|
||||
sourceSets.commonMain.dependencies {
|
||||
api("pw.binom.agentik:client:0.1.0")
|
||||
}
|
||||
}
|
||||
|
||||
val agent = AgentikAgent(id = "ops-bot", baseUrl = "http://localhost:8080/agentik")
|
||||
val conv = agent.createConversation(temp = false)
|
||||
conv.events(after = Clock.System.now()).collect { ev ->
|
||||
when (ev) {
|
||||
is Event.AppendText -> print(ev.body)
|
||||
is Event.End -> println()
|
||||
// ваш код:
|
||||
val agent = AgentikAgent(id = "agentik", baseUrl = "http://192.168.76.166:8080/agentik")
|
||||
val conv = agent.createConversation(title = "test")
|
||||
conv.send(listOf(Content.Text("hello"))).collect { event ->
|
||||
when (event) {
|
||||
is Event.AppendText -> print(event.body)
|
||||
is Event.End -> println("\n--- end ---")
|
||||
is Event.Error -> error("agent error: ${event.message}")
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
conv.send(listOf(Content.Text("Привет. Сколько будет 2+2?")))
|
||||
// ... события стримятся в collect выше
|
||||
conv.close()
|
||||
```
|
||||
|
||||
Для фоновой подписки (reconnect-safe):
|
||||
## Версии
|
||||
|
||||
`gradle/libs.versions.toml` → `[versions] agentik-client`.
|
||||
|
||||
Поддерживает все KMP-таргеты, что и `:proto`.
|
||||
|
||||
## Примеры API
|
||||
|
||||
```kotlin
|
||||
// Долгая живая подписка на события диалога.
|
||||
conv.events(after = lastSeen).collect { ev ->
|
||||
if (ev is Event.End) lastSeen = ev.date
|
||||
// список диалогов
|
||||
agent.getConversations().collect { println(it.id to it.title) }
|
||||
|
||||
// live-подписка на события отдельного диалога
|
||||
val sub = conversation.events(after = Instant.parse("2026-09-01T00:00:00Z")).collect { }
|
||||
|
||||
// прерывание текущего хода
|
||||
conversation.interrupt()
|
||||
|
||||
// история
|
||||
conversation.getMessages(offset = 0).collect { msg ->
|
||||
when (msg) {
|
||||
is Message.UserMessage -> println("user: ${msg.content}")
|
||||
is Message.AssistantMessage -> println("assistant: ${msg.content}")
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Подключение
|
||||
## Тесты
|
||||
|
||||
```kotlin
|
||||
implementation("pw.binom.agentik:client:$version")
|
||||
// Транзитивно тянет :proto + ktor-client-core/cio/... + kotlinx-serialization.
|
||||
```
|
||||
./gradlew :client:jvmTest
|
||||
```
|
||||
|
||||
## SSE-парсер
|
||||
Покрывают: JSON-парсинг Event'ов, SSE-стрим, recovery после разрыва,
|
||||
401/404.
|
||||
|
||||
Внутри — самописный парсер SSE (режет поток на `data:` строки, буферизует
|
||||
частичные, переживает keep-alive-комментарии). Зависимости — `ktor-client-cio`
|
||||
по умолчанию; если нужен другой engine — подмените через `AgentikAgent(engineFactory = …)`.
|
||||
## Чего здесь НЕТ
|
||||
|
||||
## Где смотреть версии
|
||||
- Никакого LLM-кода. Это просто клиент.
|
||||
- Никакого persistent state. История хранится у сервера, клиент её
|
||||
запрашивает через `getMessages` или подписывается через `events`.
|
||||
|
||||
- `:client` синхронизирован с `:proto`/`server` — `version` из `gradle.properties`
|
||||
- релизы: `https://git.binom.pw/subochev/agentik/releases`
|
||||
## Текущий статус
|
||||
|
||||
## Сборка
|
||||
Используется продакшеном. Бэкендом служит `:server` поверх `:standalone`,
|
||||
но клиент совместим с любым сервером, который держит wire-контракт
|
||||
`:server`.
|
||||
|
||||
```bash
|
||||
./gradlew :client:build
|
||||
```
|
||||
## Известное ограничение
|
||||
|
||||
JVM-only (ktor-client-engine-cio — JVM).
|
||||
SSE event-stream в не-TTY ssh-сессии (без `-tt`) закрывается на
|
||||
default-таймауте Ktor. Используйте либо ssh -tt, либо нативный
|
||||
terminal (TTY). Это upstream-особенность Ktor SSE.
|
||||
|
||||
Reference in New Issue
Block a user