docs(diagrams): agent architecture overview with pre-rendered SVG
ci / JVM build + tests (push) Failing after 1m57s
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
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
# 05 — Android Agent Stack
|
||||
|
||||
Что меняется vs `:standalone`. Цель: `BaseAgent` тот же самый, но platform-impl разные (Storage, LLM, Vector Memory, MCP).
|
||||
|
||||

|
||||
|
||||
PlantUML source (для редактирования; требует Graphviz `dot` для рендеринга):
|
||||
|
||||
```plantuml
|
||||
@startuml android-agent-stack
|
||||
skinparam componentStyle rectangle
|
||||
|
||||
title Android Agent Stack — что меняется vs Standalone
|
||||
|
||||
' --- Android side ---
|
||||
package "Android Application" {
|
||||
[MainActivity\n(Compose)] as Activity
|
||||
[AndroidAgentRunner\n(workmanager / service)] as Runner
|
||||
[AndroidAgentBuilder] as AndroidBuilder
|
||||
}
|
||||
|
||||
package "Android-specific impls" {
|
||||
[StorageSqliteAndroid\n(Room/sqlite)] as StorageA
|
||||
[MemoryVectorAndroid\n(ONNX runtime + ANN)] as MemVecA
|
||||
[LitertAndroid\n(NNAPI delegate)] as LitertA
|
||||
[SoulFileAndroid\n(context.filesDir)] as SoulA
|
||||
[McpRegistry\nstdio: ProcessBuilder] as McpA
|
||||
}
|
||||
|
||||
' --- Shared (KMP) ---
|
||||
package "Agent Runtime (shared)" {
|
||||
[AgentCore\nBaseAgent] as AgentCore
|
||||
[AgentBuilder] as Builder
|
||||
}
|
||||
|
||||
package "Domain (shared)" {
|
||||
[LlmTools\ncommonMain] as LlmT
|
||||
[BackgroundEvents\ncommonMain] as Ev
|
||||
[McpBridge\njvmMain] as McpB
|
||||
[Skills\ncommonMain] as Skills
|
||||
}
|
||||
|
||||
package "Memory (shared impl)" {
|
||||
[MemoryMd\n(commonMain)] as MemMd
|
||||
[MemoryApi\ninterfaces] as MemApi
|
||||
}
|
||||
|
||||
' --- Зависимости ---
|
||||
Activity --> Runner
|
||||
Runner --> AndroidBuilder
|
||||
AndroidBuilder --> AgentCore
|
||||
|
||||
AndroidBuilder --> StorageA
|
||||
AndroidBuilder --> MemVecA
|
||||
AndroidBuilder --> LitertA
|
||||
AndroidBuilder --> SoulA
|
||||
AndroidBuilder --> McpA
|
||||
|
||||
AgentCore --> LlmT
|
||||
AgentCore --> Ev
|
||||
AgentCore --> McpB
|
||||
AgentCore --> Skills
|
||||
AgentCore --> MemMd
|
||||
|
||||
' --- Главные отличия от Standalone ---
|
||||
note right of LitertA
|
||||
On-device inference.
|
||||
LiteRT с NNAPI delegate →
|
||||
работает на CPU/GPU/NPU
|
||||
прямо на устройстве, без сети.
|
||||
|
||||
vs Standalone: HTTP-only
|
||||
(OpenAI-compatible).
|
||||
end note
|
||||
|
||||
note right of StorageA
|
||||
android.database.sqlite
|
||||
через Room или сырой API.
|
||||
|
||||
vs Standalone: JDBC +
|
||||
Sqlite-JDBC driver
|
||||
(только JVM).
|
||||
end note
|
||||
|
||||
note right of MemVecA
|
||||
JVector JVM-only. На Android
|
||||
нужна альтернатива —
|
||||
ONNX Runtime + какой-нибудь
|
||||
ANN (Annoy/HNSW).
|
||||
|
||||
Или пока без vector memory,
|
||||
только MemoryMd.
|
||||
end note
|
||||
|
||||
note right of McpA
|
||||
MCP через ProcessBuilder
|
||||
на Android работает, но
|
||||
subprocess lifecycle
|
||||
сложнее (foreground service
|
||||
нужен для долгого subprocess).
|
||||
end note
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
## Что общего с `:standalone`
|
||||
|
||||
**`BaseAgent`, `BackgroundScheduler`, `LlmTools`, `McpBridge`, `Skills`, `MemoryMd` — всё KMP (commonMain).** Android-agent = `:standalone` с другим wiring'ом. Не нужно переписывать agent logic.
|
||||
|
||||
## Что другое
|
||||
|
||||
| Компонент | `:standalone` (JVM) | `:agentik-android` (Android) | Сложность |
|
||||
|---|---|---|---|
|
||||
| Storage | `:storage-sqlite` (JDBC + Sqlite-JDBC) | `:storage-sqlite-android` (Room или raw) | Низкая — тот же `StorageBundle` interface |
|
||||
| LLM | `:litert-openai` (HTTP), `:litert-google` (LiteRT JVM) | `:litert-android` (LiteRT Android, NNAPI delegate) | Средняя — нужен новый модуль |
|
||||
| Vector memory | `:memory-vector` (JVector) | `:memory-vector-android` (ONNX Runtime + HNSW/Annoy) | Высокая — JVector JVM-only, нужна альтернатива |
|
||||
| SOUL provider | `FileSoulProvider` (path) | `SoulFileAndroid` (`context.filesDir`) | Низкая |
|
||||
| MCP | `McpRegistry` (ProcessBuilder, stdio subprocess) | Тот же `McpRegistry`, но subprocess в foreground service | Средняя — нужен Android service |
|
||||
| Embedding | `HttpEmbeddingClient` (HTTP) | Тот же ИЛИ on-device (ONNX) | Средняя |
|
||||
|
||||
## Минимальный Android agent (v1)
|
||||
|
||||
Если не нужны все фичи сразу — минимум:
|
||||
|
||||
```kotlin
|
||||
val agent = androidAgentBuilder(context) {
|
||||
llm(LitertAndroid.onDevice(context, modelPath = "/data/local/tmp/model.litertlm"))
|
||||
storage(SqliteStorage.android(context, "agent.db"))
|
||||
memory(MemoryMd.root(context.filesDir.resolve("memory")))
|
||||
soul(FileSoul(context.filesDir.resolve("SOUL.md")))
|
||||
background {
|
||||
// OnClosing + OnCompaction работают так же как на JVM
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Без MCP, без vector memory (только MemoryMd на файлах), только on-device LLM. Достаточно для off-line агента.
|
||||
|
||||
## Foreground service для MCP
|
||||
|
||||
Если нужны MCP-серверы (например, локальный file-system MCP) — subprocess нужен foreground service чтобы Android не убил его при выключении экрана. Это добавляет сложности:
|
||||
|
||||
```kotlin
|
||||
class McpForegroundService : Service() {
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
val proc = ProcessBuilder(command, args).start()
|
||||
// ... route stdio to McpLiteToolAdapter ...
|
||||
return START_STICKY
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Пока можно без этого (только если MCP нужен на Android).
|
||||
|
||||
## Текущее состояние vs целевое
|
||||
|
||||
✅ KMP-ready:
|
||||
- `:llm-tools` (commonMain, платформо-агностик)
|
||||
- `:mcp-bridge` (jvmMain — Android-вариант через `:mcp-bridge-android`)
|
||||
- `:skills` (commonMain)
|
||||
- `:memory-md` (commonMain)
|
||||
- `:proto` (commonMain)
|
||||
|
||||
⏳ Не существует:
|
||||
- `:storage-sqlite-android`
|
||||
- `:memory-vector-android`
|
||||
- `:litert-android`
|
||||
- `:agentik-android` (само приложение)
|
||||
- `:agent-core` (выделить BaseAgent + builder)
|
||||
- `:background-events` (выделить events + scheduler)
|
||||
Reference in New Issue
Block a user