Files
agentik/NATIVE-COMPATIBILITY.md
subochev cad4d5fc7c AGUI: удалён полностью
Убрана зависимость pw.binom.agui:server из проекта — AGUI больше
не нужен (см. Memory #3675; agentik переходит на свой протокол :proto
и HTTP-фасад :server).

Чистка:
  - standalone/build.gradle.kts:    implementation(libs.agui.server) → удалено
  - gradle/libs.versions.toml:      [versions] agui + agui-api/agui-client/
                                    agui-server entries → удалены
  - settings.gradle.kts:            убран 'AG-UI' из комментария к Nexus-репо
  - proto/build.gradle.kts:         комментарий 'Зеркалит набор AG-UI api' →
                                    'Полный набор KMP-целей'
  - proto/src/.../Agent.kt:         KDoc '(замена AG-UI)' → удалено
  - settings.gradle.kts:            то же
  - docs/ARCHITECTURE.md:           переписан (описывал старую AGUI-centric
                                    архитектуру с AbstractAgent/SessionStore/
                                    AgentEngine — ничего этого в коде уже
                                    нет; теперь отражает текущее состояние:
                                    :proto + :server + :standalone + LiteLlm +
                                    MCP + SqliteStores)
  - NATIVE-COMPATIBILITY.md:        пункт 10 'agui-server KMP-готовность' →
                                    отменён (см. -); убран из 'Жёсткие блокеры'

В коде не осталось ни одного обращения к AGUI. После чистки в репо
больше нет ни одной зависимости от pw.binom.agui.*.

Проверка: ./gradlew :server:assemble (9/9 KMP-целей) +
:standalone:jvmTest 44/44 (ChatAgent 15, LlmConfig 6, McpConfig 8,
McpRegistry 4, Persistence 11) — зелёные.
2026-09-13 19:10:20 +03:00

11 KiB
Raw Permalink Blame History

Совместимость с native (linuxX64) — чеклист

Цель: :standalone собирается и запускается как linuxX64 executable (и потенциально остальные нативные таргеты KMP). Текущее состояние — JVM-only executable на runJvm-таске.

Формат: - N. [ ] — задача; - N. [x] — выполнена; - N. [-] — отменена/не нужна. Решения (что выбрали и почему) — курсивом внизу пункта.


Блок 1. Подготовка (уже сделана или тривиальная)

    1. Замена java.util.UUID на KMP-stdlib (kotlin.uuid.Uuid). Helper Ids.new(prefix) в standalone/src/commonMain/.../persistence/Ids.kt, три call-site (ChatAgent, ChatConversation, SqliteWorkingMemoryStore). Коммит e816d8d.
    1. HTTP-движок: ktor-server-netty → ktor-server-cio. Netty — JVM-only; CIO — KMP (jvm + linuxX64 + ios/...). Каталог-эntry Netty оставлен в libs.versions.toml на случай отката. Коммит e816d8d.

Блок 2. Библиотеки litert-kmp (наши)

    1. litert-api: добавить linuxX64() в kotlin{}. Сейчас только androidTarget() + jvm(). commonMain уже KMP-ready (только kotlinx-coroutines-core). Объём: одна строка в litert-api/build.gradle.kts, один litert-api-linuxx64-артефакт публикуется в Nexus.
    1. litert-openai: добавить linuxX64() в kotlin{}. Та же история. commonMain deps (ktor-client-core, ktor-client-cio, kotlinx-serialization-json) — все KMP с готовыми linuxX64-артефактами. Объём: одна строка + проверить, что Android-only фичи (если есть) изолированы в androidMain (сейчас модуль не имеет androidMain-специфичного кода). Каталог-запись litert-openai-jvm → переименовать в litert-openai (чтобы Linux-таргет подтягивал -linuxx64-вариант автоматически, не нужно ручного when target).
    1. [-] litert-google: linuxX64 — невозможно. Upstream-блокер: Google публикует litertlm-android (AAR с .so) и litertlm-jvm (fat-jar с .so для linux/mac/win JVM), но НЕ нативного litertlm-linuxx64. Без правки upstream LiteRT-LM KMP-враппер для linuxX64 не напишется. Варианты: (a) выкинуть litert-google на linuxX64 (backend=google → отказ); (b) альтернативный движок (llama.cpp через JNI/Kotlin/Native); (c) upstream PR в litertlm. Решение: (a) для v1 linuxX64 — упасть с понятной ошибкой LlmBackend.GOOGLE is not supported on this platform вместо reflection-fallback на JVM .so, который на linuxX64 не сработает бы.

Блок 3. Наш :server модуль

    1. Переписать :server с kotlin("jvm") на kotlin("multiplatform"). Все 9 целей сборки (jvm + macosX64 + macosArm64 + iosX64 + iosArm64 + iosSimulatorArm64 + linuxX64 + linuxArm64 + mingwX64) собираются ./gradlew :server:assemble без ошибок. Блокеров нет: Ktor ktor-server-{core,sse,cio,content-negotiation} и ktor-io (для ByteWriteChannel.writeStringUtf8) есть в KMP-вариантах под все цели; kotlin.time.Instant уже использовался. Единственное изменение по сравнению с JVM-версией: respondTextWriter (JVM-only) → respondBytesWriter + writeStringUtf8 (KMP, тот же ByteWriteChannel API). Источники переехали src/main/kotlin/... → src/commonMain/kotlin/.... :standalone:jvmTest 44/44 зелёные после миграции.

Блок 4. Наш :proto модуль

    1. :proto: убрать kotlinx-datetime api-dep, оставить kotlin.time.Instant. Источник уже был на kotlin.time.Instant (мигрирован ранее), но kotlinx-datetime оставался в gradle как мёртвая api-зависимость. Удалено:
    • api(libs.kotlinx.datetime) из proto/build.gradle.kts
    • implementation(libs.kotlinx.datetime) из standalone/build.gradle.kts
    • [versions] kotlinx-datetime и [libraries] kotlinx-datetime из gradle/libs.versions.toml kotlin.time.Instant доступен во всех KMP-целях без opt-in. ./gradlew :server:assemble + :standalone:jvmTest 44/44 — зелёные.

Блок 5. SQLDelight — нативный драйвер

    1. sqlite-driver (JVM/JDBC) → native-driver для linuxX64. В jvmMain: оставить sqlite-driver (JDBC over java.sql.DriverManager). В linuxX64Main: добавить native-driver — KMP driver поверх cinterop с libsqlite3 (нужен -lsqlite3 linker-флаг или SQLiteBundle из co.touchlab:sqliter для бандлинга). Создать SqliteStores- нейтральный интерфейс хранилищ (он уже есть в commonMain), разделить jvmMain/SqliteStores.kt и linuxX64Main/SqliteStoresNative.kt — оба реализуют один commonMain-интерфейс. Объём: ~150 строк (новый SqliteStoresNative.kt + gradle wiring). Решение по бандлу: использовать SQLiteBundle из co.touchlab:sqliter (KMP-обёртка, тянет свой libsqlite) — без зависимости от системного libsqlite3, бинарь работает на любом linux.
    1. Тесты SQLite переписать на commonTest + expect/actual обёртку. inMemory()-открытие в native-driver использует другой API (нет JDBC :memory:). Объём: один expect fun openInMemory() в commonMain + два actual (JDBC jdbc:sqlite::memory: / native-driver нативный API).

Блок 6. Внешние либы (a2a-server) — наши

    1. AGUI убран из проекта. catalog-entries agui-api/agui-client/agui-server, [versions] agui и implementation(libs.agui.server) в :standalone удалены — AGUI больше не нужен (см. Memory #3675 и переписанный docs/ARCHITECTURE.md). AGUI-фасад был stateless request/response, а agentik переходит на свой stateful протокол :proto / :server.
    1. a2a-server: JVM-only → KMP. Per Memory #3561 — JVM-only (client/server; shared уже KMP). Без native-таргета весь стек A2A недоступен на linuxX64. Объём: переписать на multiplatform, выделить engine-нейтральную маршрутизацию. Альтернатива: на linuxX64 не подключать a2a-server вообще (только :server-фасад). Решение отложено — зависит от того, нужен ли нативный MCP-юзер-кейс вообще подключаться к A2A.

Блок 7. :standalone — добавить native target

    1. standalone/build.gradle.kts: добавить linuxX64() и linuxX64Main/linuxX64Test source-sets. В linuxX64Main: :server (после п.6), litert-openai (после п.4), litert-api (после п.3), ktor-server-cio (engine), ktor-client-cio, kotlin-sdk-client (MCP — KMP, готов), kotlinx-io (KMP, готов). Исключить litert-google (п.5) и a2a-server (п.11) из linuxX64Main.
    1. Main.kt: разделить на commonMain (бизнес-логика: создание ChatAgent, MCP, LlmConfig) + jvmMain/linuxX64Main (выбор engine, embeddedServer). embeddedServer(CIO, …) — один и тот же код на обеих платформах, KMP-нейтрален. Главное отличие — SqliteStores.open() и обработка GOOGLE-бэкенда на linuxX64 (fail-fast).

Блок 8. Тесты и CI

    1. linuxX64Test source-set. Покрыть те же 44 теста на native: должен зелёный прогон через ./gradlew :standalone:linuxX64Test. SQLDelight-тесты на native требуют libsqlite3/SQLiteBundle на машине (CI-linux предоставляет).
    1. Smoke e2e на linuxX64. Запустить ./gradlew :standalone:runLinuxX64 локально, проверить POST /agentik/conversations → 201, цикл с реальным LLM через OpenAI backend; убедиться что LiteRT-LM GOOGLE не подключается (отказ с понятной ошибкой).

Блок 9. Дистрибуция native-бинаря

    1. runLinuxX64-таска через KMP binaries DSL. После добавления linuxX64() KMP генерирует её автоматически — нужно только убедиться что binaries { executable { mainClass.set("pw.binom.agentik.standalone.MainKt") } } работает для linuxX64 (по аналогии с уже настроенным runJvm).
    1. Дистрибутив .tar/.zip/AppImage/Docker. KMP assembleDist для linuxX64 делает tar.gz/zip. Для прод-дистрибуции — Docker-образ (FROM gcr.io/distroless/cc) или AppImage. Объём: ~50 строк Dockerfile + GitHub Action.

Что НЕ блокирует linuxX64 (закрыто или тривиально)

  • kotlinx-coroutines-core — KMP linuxX64 ✓
  • kotlinx-serialization-json — KMP linuxX64 ✓
  • kotlinx-io — KMP linuxX64 (используется в MCP stdio-transport) ✓
  • kotlin-sdk-client (MCP) — KMP full targets ✓
  • ktor-server-core, ktor-server-sse, ktor-server-cio — KMP linuxX64 ✓
  • ktor-client-core, ktor-client-cio — KMP linuxX64 ✓
  • pw.binom.uuid — отсутствует в проекте (используем kotlin.uuid) ✓

Жёсткие блокеры (не обойти без upstream-работы)

  • litertlm-jvm → нужен litertlm-native от Google (см. п.5)
  • a2a-server JVM-only (см. п.11) — нужно переписать или явно не подключать