Files
agentik/docs/diagrams/05-android-stack.md
T
subochev 25771a0c33
ci / JVM build + tests (push) Failing after 1m57s
docs(diagrams): agent architecture overview with pre-rendered SVG
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
2026-09-18 20:02:41 +03:00

5.9 KiB
Raw Blame History

05 — Android Agent Stack

Что меняется vs :standalone. Цель: BaseAgent тот же самый, но platform-impl разные (Storage, LLM, Vector Memory, MCP).

Android Agent Stack

PlantUML source (для редактирования; требует Graphviz dot для рендеринга):

@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)

Если не нужны все фичи сразу — минимум:

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 не убил его при выключении экрана. Это добавляет сложности:

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)