960cd60120
- только jvm-таргет; composite includeBuild("../agentik")
- mavenLocal() первым в репозиториях: локальные публикации перекрывают Nexus
- Compose 1.7.3 + Kotlin 2.4.20, compose.desktop.currentOs
- вендоренный markdown (ru.otpbank.ai:markdown), mic-api/asr-vosk/vad
- gradle wrapper, gradle.properties, .gitignore (локальный тулинг)
129 lines
6.8 KiB
Kotlin
129 lines
6.8 KiB
Kotlin
// `binaries {}` — экспериментальный API KGP, `compose.uiTest` — экспериментальная
|
||
// библиотека Compose (компилятор требует явного opt-in в скрипте).
|
||
@file:OptIn(
|
||
org.jetbrains.compose.ExperimentalComposeLibrary::class,
|
||
org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class,
|
||
)
|
||
|
||
plugins {
|
||
alias(libs.plugins.kotlin.multiplatform)
|
||
alias(libs.plugins.kotlin.serialization)
|
||
// UI — Compose Multiplatform. `kotlin-compose` — компиляторный плагин
|
||
// (@Composable), `compose` — рантайм/DSL (`compose.material3`, ...).
|
||
alias(libs.plugins.kotlin.compose)
|
||
alias(libs.plugins.compose)
|
||
// `application` plugin (он тянет `java`) **несовместим** с
|
||
// `kotlin("multiplatform")` — проверка `checkKotlinGradlePluginConfigurationErrors`
|
||
// падает на старте. В KMP executable настраивается через
|
||
// `kotlin { jvm { binaries { executable { ... } } } }` ниже — он создаёт
|
||
// `run` / `installDist` / jar с mainClass автоматически.
|
||
}
|
||
|
||
group = "pw.binom.agentik.desktop"
|
||
version = "0.1.0-SNAPSHOT"
|
||
|
||
kotlin {
|
||
// KMP-проект с **одной** целью — JVM. Структура каталогов
|
||
// `src/jvmMain/kotlin/...` (а не `src/main/kotlin/...`), чтобы при
|
||
// расширении целями (iOS / Native) не пришлось переименовывать.
|
||
// Toolchain 21 = как у agentik (`:client` / `:journal-ksqlite` тоже
|
||
// jvmToolchain(21)) — иначе Gradle тащит второй JDK через foojay.
|
||
jvmToolchain(21)
|
||
jvm {
|
||
binaries {
|
||
executable {
|
||
mainClass.set("pw.binom.agentik.desktop.MainKt")
|
||
// `jvmJar` создаётся автоматически; `run` запускает main.
|
||
}
|
||
}
|
||
}
|
||
|
||
sourceSets {
|
||
jvmMain.dependencies {
|
||
// --- Agentik (композитная сборка, см. settings.gradle.kts) ---
|
||
// `AgentikAgent` / `wrapWithLocalConversationCache` /
|
||
// `ReconnectingOutbox` — всё что нужно для клиента уже здесь.
|
||
implementation(libs.agentik.client)
|
||
// Контракты `MessageRecord` / `ConversationRecord` /
|
||
// `MutableJournalStore` / `MutableConversationStore`.
|
||
implementation(libs.agentik.journal.api)
|
||
// SQLite-реализации обоих store'ов из `:journal-ksqlite`.
|
||
implementation(libs.agentik.journal.ksqlite)
|
||
// `Event` / `AgentEvent` / `CommonEvent` / `OutboxStore` (live-поток).
|
||
implementation(libs.agentik.outbox.api)
|
||
// `Agent` / `Conversation` / `AgentInfo` / `Content` — proto-контракты.
|
||
implementation(libs.agentik.proto)
|
||
|
||
// --- Ktor client engine (передаётся в AgentikAgent как engineFactory) ---
|
||
implementation(libs.ktor.client.cio)
|
||
|
||
// --- Низкоуровневая БД (`SQLiteConnection` / prepared statements) ---
|
||
implementation(libs.ksqlite)
|
||
|
||
// --- Kotlinx ---
|
||
implementation(libs.kotlinx.coroutines.core)
|
||
implementation(libs.kotlinx.serialization.json)
|
||
|
||
// --- UI: Compose Multiplatform (markdown-рендер + экраны) ---
|
||
implementation(compose.foundation)
|
||
implementation(compose.ui)
|
||
implementation(compose.material3)
|
||
implementation(compose.materialIconsExtended)
|
||
// Оконный рантайм Compose Desktop (Window/application) + skiko
|
||
// для текущей ОС. Без него `compose.ui.window.application` не резолвится.
|
||
implementation(compose.desktop.currentOs)
|
||
|
||
// --- Markdown: парсер (ru.otpbank.ai:markdown, обёртка над
|
||
// org.intellij.markdown) + вендоренный рендер сегментов. ---
|
||
implementation(libs.markdown)
|
||
|
||
// --- Голос: микрофон → VAD → распознавание (см. MIC-ASR-SEARCH.md).
|
||
// JVM-реализация микрофона — `javax.sound.sampled`. ---
|
||
implementation(libs.mic.api)
|
||
implementation(libs.asr.api)
|
||
implementation(libs.asr.vosk)
|
||
implementation(libs.vad)
|
||
|
||
// --- Логирование ---
|
||
implementation(libs.kotlin.logging)
|
||
implementation(libs.logback.classic)
|
||
}
|
||
|
||
jvmTest.dependencies {
|
||
implementation(libs.kotlin.test)
|
||
implementation(libs.kotlinx.coroutines.test)
|
||
implementation(libs.junit.jupiter)
|
||
// Оффскрин-рендер Compose: прогоняем реальную тему/компоненты
|
||
// в ImageComposeScene и проверяем палитру по пикселям.
|
||
implementation(compose.uiTest)
|
||
// E2E: поднимаем настоящий `:server` (HTTP/SSE) поверх
|
||
// in-memory-агента и гоняем десктопный стек по живому протоколу.
|
||
implementation(libs.agentik.server)
|
||
implementation(libs.agentik.journal.inmemory)
|
||
implementation(libs.agentik.outbox.inmemory)
|
||
implementation(libs.ktor.server.cio)
|
||
}
|
||
}
|
||
}
|
||
|
||
// `application` плагин в KMP конфликтует с `kotlin("multiplatform")`,
|
||
// executable объявлен выше в `kotlin { jvm { binaries { executable { ... } } } }`
|
||
// — он автоматически создаёт `run` / `installDist` и jvmJar.
|
||
|
||
tasks.withType<Test>().configureEach {
|
||
useJUnitPlatform()
|
||
// Один JVM на тест-класс. Причина не в изоляции данных, а в нативных
|
||
// библиотеках: skiko (Compose) и C++-стек распознавания (Vosk/Kaldi, ONNX)
|
||
// конфликтуют по порядку загрузки — тот, кто грузится ПОСЛЕ skiko, падает
|
||
// с SIGSEGV. Классы, которым нужен нативный ASR, обязаны прогревать его
|
||
// первым делом (VoiceNative / RealSpeechIT), а skiko-классы — не мешать им.
|
||
// forkEvery = 1 гарантирует, что порядок классов не важен.
|
||
forkEvery = 1
|
||
// Изолируем данные приложения от реального $HOME разработчика:
|
||
// AppPaths читает AGENTIK_DESKTOP_HOME, тесты пишут в build/.
|
||
environment(
|
||
"AGENTIK_DESKTOP_HOME",
|
||
layout.buildDirectory.dir("test-agentik-home").get().asFile.absolutePath,
|
||
)
|
||
}
|