25771a0c33
ci / JVM build + tests (push) Failing after 1m57s
PlantUML diagrams for future agent architecture (Android, multi-user chat, sub-agents, A2A): - 01-module-layers.md — целевая модульная структура - 02-agent-composition.md — AgentBuilder DSL + MemoryBackend.exposesTools() - 03-multi-user-chat.md — mention-detection sequence - 04-sub-agents.md — spawnChild + Flow<SubAgentEvent> + A2A - 05-android-stack.md — что меняется на Android vs Standalone Каждый .md включает пред-рендеренный SVG (показывается во всех markdown viewers без PlantUML plugin) + PlantUML source в code block (для редактирования). SVG нужен потому что PlantUML требует Graphviz dot для рендеринга — без него IntelliJ/VSCode выдают ошибку. Регенерация SVG после правки PlantUML-source: docker run --rm -v "$PWD:/work" plantuml/plantuml -tsvg /work/docs/diagrams/*.md
128 lines
4.7 KiB
Markdown
128 lines
4.7 KiB
Markdown
# 02 — Agent Builder: композиция (целевое API)
|
|
|
|
Как `AgentBuilder` собирает `BaseAgent` из компонентов. **Memory backend сам объявляет свои tools** — builder их авто-мержит. BackgroundScheduler подписан на события, не interval-poll.
|
|
|
|

|
|
|
|
PlantUML source (для редактирования; требует Graphviz `dot` для рендеринга):
|
|
|
|
```plantuml
|
|
@startuml agent-composition
|
|
skinparam componentStyle rectangle
|
|
|
|
title Agent Builder — композиция (целевое API)
|
|
|
|
' --- Builder ---
|
|
rectangle "AgentBuilder" as Builder {
|
|
rectangle "llm: LiteLlm (обязательно)" as Llm
|
|
rectangle "storage: StorageBundle (обязательно)" as Storage
|
|
rectangle "memory: MemorySystem (обязательно)" as Mem
|
|
rectangle "soul: SoulProvider (default NoopSoul)" as Soul
|
|
rectangle "tools: List<NamedTool> (авто-сборка из backends)" as Tools
|
|
rectangle "background: BackgroundConfig (default EmptyBg)" as Bg
|
|
rectangle "toolset: List<ToolsetContribution> (default empty)" as Ts
|
|
}
|
|
|
|
' --- Backends with their tool side-effects ---
|
|
rectangle "MemoryMd" as MdMem {
|
|
interface "MemorySystem" as MemSys
|
|
interface "List<NamedTool>" as MdTools
|
|
note right
|
|
MemoryMd.exposesTools() →
|
|
memory_save / memory_read /
|
|
memory_list / memory_delete
|
|
end note
|
|
}
|
|
|
|
rectangle "McpRegistry" as McpReg {
|
|
interface "List<NamedTool>" as McpTools
|
|
note right
|
|
McpRegistry.namedTools →
|
|
server__tool1, server__tool2,
|
|
...
|
|
end note
|
|
}
|
|
|
|
rectangle "BackgroundEvents" as Events {
|
|
interface "MutableSharedFlow<CompactionEvent|ToolCallEvent|LifecycleEvent>" as Flow
|
|
note right
|
|
Эмитится из:
|
|
- CompactionCoordinator
|
|
- ToolDispatcher
|
|
- ConversationLoop.close()
|
|
end note
|
|
}
|
|
|
|
rectangle "BackgroundScheduler" as Sched {
|
|
interface "policy: trigger + debounce" as Policy
|
|
note right
|
|
Подписан на Events.
|
|
НИКАКОГО interval-polling.
|
|
end note
|
|
}
|
|
|
|
' --- Получаемый Agent ---
|
|
rectangle "BaseAgent\n(impl: ConversationLoop)" as Agent {
|
|
rectangle "send / interrupt / events" as API
|
|
rectangle "BackgroundScheduler\nподписка" as Sub
|
|
}
|
|
|
|
' --- Стрелки зависимостей ---
|
|
Builder --> Llm
|
|
Builder --> Storage
|
|
Builder --> Mem
|
|
Builder --> Soul
|
|
Builder --> Tools
|
|
Builder --> Bg
|
|
Builder --> Ts
|
|
|
|
MdMem --> Mem : implements
|
|
MdMem --> MdTools : exposes
|
|
|
|
McpReg --> McpTools : exposes
|
|
|
|
Bg --> Events : subscribes-to
|
|
Bg --> Sched : holds
|
|
|
|
Tools <-- MdTools : auto-merge
|
|
Tools <-- McpTools : auto-merge
|
|
|
|
Builder --> Agent : build()
|
|
Agent --> API
|
|
Agent --> Sub
|
|
|
|
@enduml
|
|
```
|
|
|
|
## Целевой Kotlin DSL
|
|
|
|
```kotlin
|
|
val agent = agentBuilder {
|
|
// Обязательные
|
|
llm(OpenAiLlm.fromEnv()) // или LitertAndroid.onDevice(context)
|
|
storage(SqliteStorage(path)) // или SqliteStorage.android(context)
|
|
memory(MemoryMd(root = "~/memory")) // или MemoryVector(embedding = HttpEmbedding(...))
|
|
|
|
// Опциональные
|
|
soul(FileSoul("~/SOUL.md")) // или HttpSoul(url), NoopSoul()
|
|
background {
|
|
// triggers: OnClosing (reflection+mining), OnCompaction(minTurns=10, mining=true)
|
|
// event-driven, не interval
|
|
}
|
|
tools {
|
|
// memoryMd.exposesTools() + mcpRegistry.namedTools авто-подцепляются
|
|
+FileReadTool(root = "/data")
|
|
}
|
|
toolset {
|
|
+MemoryToolsToolset(memoryMd)
|
|
}
|
|
}.build()
|
|
```
|
|
|
|
## Ключевые решения
|
|
|
|
- **`MemoryBackend.exposesTools()`** — backend декларирует свои tools. Не «подставить любой backend», а «backend сообщает что он умеет». Это убирает coupling «какие tools совместимы с какими backends».
|
|
- **Builder требует только `llm + storage + memory`** как обязательные. Всё остальное — опционально с разумными default'ами (`NoopSoul`, `EmptyBackground`, `empty toolset`).
|
|
- **`BaseAgent`** — реализация `ConversationLoop` через builder. Конструктор принимает все нужные компоненты. **Один и тот же `BaseAgent` в `:standalone`, `:agentik-cli`, `:agentik-android`** — отличается только wiring через builder.
|
|
- **BackgroundScheduler подписан на `BackgroundEvents`** — это даёт event-driven по умолчанию. `OnEvery(n)` interval-режим — опциональный fallback (не default).
|