docs: per-module READMEs (run vs library) + root navigation hub
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:
SubochevAV
2026-09-16 20:44:16 +03:00
parent 5ad972767d
commit 8f616f359f
22 changed files with 1125 additions and 890 deletions
+64 -50
View File
@@ -1,73 +1,87 @@
# :agent-toolsets — `pw.binom.agentik.toolsets`
# `:agent-toolsets` — реестр инструментов агента (KMP, jvm + native)
**Ядро механики toolsets: `ToolsetRegistry`, `ToolsetDispatchPolicy`,
встроенные тулы `enable_toolset` / `disable_toolset`, `SyncLiteTool` базовый
класс.**
KMP, не зависит от `:standalone`, переиспользуем в Android и в любом другом
LiteTool-агенте.
## Что это
## Какую проблему решает
Ядро системы tools для LLM-агента:
В проде у агента может быть **сотня** инструментов (MCP-серверы, кастомные
тулы, встроенные операции). Слать их все в каждый LLM-запрос:
- `Toolset` — интерфейс, объединяющий несколько связанных tools
(`MemoryTools`, `SkillsTools`, `FileSystemTools`).
- `ToolRegistry` — глобальный реестр + фильтр enabled/disabled.
- `ToolDispatcher` — берёт решение LLM (вызов инструмента с аргументами)
→ запускает → возвращает результат.
- **Cooperative cancel** — `interrupt()` корректно отменяет in-flight
вызов, помечая результат `[cancelled by user]`.
- **Concurrency budget** — `backgroundScope = Dispatchers.IO
.limitedParallelism(4)` (см. коммит `86eb063`) — защищает
threadpool от переполнения при fan-out 30+ диалогов.
1. **Раздувает контекст** — описание тула ~50–200 токенов × 100 тулов = 20K токенов
в system prompt без пользы.
2. **Увеличивает latency** — модель тратит время на выбор из длинного списка.
3. **Снижает качество** — модель путается между похожими названиями.
Решает: надёжный механизм tool-calls с прерываниями, без
blocking-pool exhaustion, без утечки. Переиспользуется во всех
IM-фронтендах (CLI, TUI, IRC, web).
Toolsets группируют тулы **по домену** (`filesystem`, `network`, `devops`, …).
Активированы только 2-3 одновременно. `enable_toolset("filesystem")` —
включает целую группу одним обращением; тулы появляются в system prompt +
регистрируются как вызываемые. `disable_toolset(...)` — убирает.
## Где используется
## Архитектура
- `:standalone` подключает несколько `Toolset`-имплементаций
(memory / skills / files / web), фильтрует через
`AGENTIK_TOOLSETS_DEFAULT` env.
## Как подключить
```kotlin
interface Toolset {
val name: String // "filesystem"
val title: String // "File operations"
val enabled: Boolean // текущее состояние
suspend fun enabledTools(context: ToolsetContext): List<LiteTool>
suspend fun systemPromptSection(context: ToolsetContext): String
commonMain.dependencies {
api("pw.binom.agentik:agent-toolsets:0.1.0")
}
class ToolsetRegistry {
fun register(toolset: Toolset)
fun list(): List<Toolset>
suspend fun enable(name: String): Boolean
suspend fun disable(name: String): Boolean
class MyToolset : Toolset {
override val name = "my"
override val description = "Custom user-defined tools"
override val tools = listOf(myTool1, myTool2)
}
class ToolsetDispatchPolicy {
fun buildDispatch(): DispatchPolicy // подаётся в LiteLlm
}
val dispatcher = ToolDispatcher(
toolsets = listOf(MemoryTools(memory), MyToolset()),
enabled = setOf("memory", "my"),
)
```
Встроенные тулы — `EnableToolsetTool` / `DisableToolsetTool` /
`SystemPromptToolsetSection` — дают LLM самой управлять составом инструментов.
База для кастомных тулов — `SyncLiteTool` (обёртка над `LiteTool`,
синхронная `execute(args): String`).
## Версии
## Подключение
`gradle/libs.versions.toml` → `[versions] agentik-agent-toolsets`.
## Как пишется tool
```kotlin
commonMain {
implementation("pw.binom.agentik:agent-toolsets:$version")
// Транзитивно: :storage-core (для ToolsetContext) + :proto
data object EchoTool : Tool {
override val name = "echo"
override val description = "Echoes back the argument"
override val argsSchema = jsonSchema {
property("text", JsonType.STRING) { required = true }
}
override suspend fun invoke(args: JsonObject): ToolResult {
val text = args["text"]?.jsonPrimitive?.content ?: return ToolResult.Error("missing text")
return ToolResult.Text(text)
}
}
```
## Где смотреть версии
## Тесты
- `version` из `gradle.properties` (`version=0.1.0`)
- релизы: `https://git.binom.pw/subochev/agentik/releases`
## Сборка
```bash
./gradlew :agent-toolsets:build
```
./gradlew :agent-toolsets:allTests
```
KMP-таргеты — полный набор. Зависимости — `:storage-core` + `:proto` +
`kotlinx-coroutines` + `kotlinx-serialization`.
Покрывают: invoke happy-path, invalid args, cooperative cancel,
budget exhaustion, registry filter, parallel dispatch.
## Чего здесь НЕТ
- Никакого конкретного LLM. Dispatcher вызывает tools, не LLM.
- Никакого persistent storage. Опирается на контракт `WorkingMemoryStore`
(см. `:storage-core`).
## Текущий статус
Используется продакшеном. Реализует полную спецификацию из
[INTERRUPT-DESIGN.md](../../docs/INTERRUPT-DESIGN.md): tool exchange
log, rolling buffer, partial-state persistence.