# 05 — Android Agent Stack Что меняется vs `:standalone`. Цель: `BaseAgent` тот же самый, но platform-impl разные (Storage, LLM, Vector Memory, MCP). ![Android Agent Stack](./05-android-stack.svg) 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)