@file:OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class) import org.gradle.api.artifacts.ConfigurationContainer import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.shadow) } // CI-флаг: при -PskipVectorMemory=true :memory-vector не подключается как // зависимость — нужно для CI runner'а (text-embedding-kmp ещё не опубликован // в caffeine). Подробнее см. memory-vector/build.gradle.kts. val skipVectorMemory: Boolean = (project.findProperty("skipVectorMemory") == "true") || System.getenv("SKIP_VECTOR_MEMORY") == "1" // :standalone — единственный entry-point проекта, JVM-only по факту (один // `jvm()` target). Чтобы не таскать лишние sourceSet'ы, ВСЁ живёт в // commonMain + commonTest — даже зависимости, которые формально JVM-only // (ktor-server-cio, litert-openai, storage-ksqlite, ...). KMP-плагин тут // только ради бесшовного потребления KMP-зависимостей (`:proto`, `:server`, // `:journal-api`, ...); компилируется всё ровно в одну JVM-таргет. kotlin { jvmToolchain(21) jvm { binaries { executable { mainClass.set("pw.binom.agentik.standalone.MainKt") } } } sourceSets { commonMain.dependencies { // Протокол + KMP storage API implementation(project(":proto")) implementation(project(":server")) implementation(project(":journal-api")) implementation(project(":outbox-api")) implementation(project(":context-api")) implementation(project(":reflection-api")) // Commons implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.serialization.json) // Парсер и загрузчик скилов (YAML frontmatter + markdown body). implementation(project(":skills")) // Долговременная память (Hermes-style MD-бэкенд) + хранилище истории. implementation(project(":memory-api")) implementation(project(":memory-md")) if (!skipVectorMemory) { implementation(project(":memory-vector")) } // SQLite-бэкенд (ksqlite JNI) — JVM-only по факту. implementation(project(":storage-ksqlite")) // Bounded-tail live event stream + per-event TTL. implementation(project(":outbox-inmemory")) // LLM-toolsets + generic LLM-side tools (LlmReflector, SkillMiner, // LlmMemoryReviewer, ContextCompactor, парсеры/промпты). implementation(project(":agent-toolsets")) implementation(project(":llm-tools")) // Generic MCP-bridge (McpConfig, McpRegistry, McpLiteToolAdapter). implementation(project(":mcp-bridge")) // litert-kmp: контракт (commonMain) api(libs.litert.api) // litert-openai: JVM-реализация implementation(libs.litert.openai) // litert-google: встроенный LiteRT-LM движок, нужен только на runtime runtimeOnly(libs.litert.google) // Ktor server (для :server facade + a2aServer) // Используем CIO вместо Netty — он KMP (jvm + linuxX64/ios/...), нам нужен // для будущей native-сборки; на JVM работает идентично для нашего сценария. implementation(libs.ktor.server.core) implementation(libs.ktor.server.sse) implementation(libs.ktor.server.cio) implementation(libs.ktor.server.content.negotiation) implementation(libs.ktor.serialization.kotlinx.json) // Транспортные фасады (A2A остаётся заготовкой; на v1 не подключается в Main.kt — // см. docs/ARCHITECTURE.md §3). implementation(libs.a2a.server) // MCP (Model Context Protocol) клиент — подключение внешних/внутренних MCP-серверов implementation(libs.mcp.sdk.client) implementation(libs.ktor.client.core) implementation(libs.ktor.client.cio) implementation(libs.ktor.client.content.negotiation) // Логирование: kotlin-logging (тонкая обёртка slf4j-api) + logback-classic // (binding для JVM; без него slf4j-api NOP-логирует и не падает). implementation(libs.kotlin.logging) implementation(libs.logback.classic) } commonTest.dependencies { implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.serialization.json) implementation(libs.kotlin.test) // Ktor test engine для smoke-тестов HTTP implementation(libs.ktor.server.test.host) } } } // --- Fatjar (uberjar) --- // // :standalone — KMP jvm-only бэкенд. Стандартный KMP `jvmJar` содержит только // наши классы и требует подтянуть все зависимости на runtime через classpath. // Для дистрибутива нужен self-contained `*-all.jar`, который содержит и наш // код, и runtime classpath. Делается это Shadow-плагином: // // 1. shadowJar расширяет `jvmJar` (через from(tasks.named("jvmJar"))) // 2. Добавляет все артефакты из jvmRuntimeClasspath как `zipTree` // 3. Корректно сливает META-INF/services (через ServiceFileTransformer) // 4. Прописывает Main-Class в манифесте // // Результат: `build/libs/standalone-*-all.jar` запускается как // java -jar standalone-0.1.0-all.jar // // KMP-сборка под ios/lin/macos не затрагивается — задача живёт только в jvm. // Shadow 8.x не авторегистрирует shadowJar в KMP-проектах (нет стандартного `jar`), // поэтому регистрируем явно через tasks.register. // // В Gradle 9 KGP подменяет `configurations` на сгенерированный dependency-accessor // (он возвращает List), поэтому используем прямой доступ к Project API. val shadowJarTask = tasks.register("shadowJar") { archiveBaseName.set("standalone") archiveClassifier.set("all") description = "Self-contained fatjar with all runtime dependencies bundled." group = "build" from(tasks.named("jvmJar")) // javaClass-каст через Any? чтобы вытащить реальный ConfigurationContainer // из любого типа, который сейчас прикидывается `configurations`. val cc = try { @Suppress("UNCHECKED_CAST") configurations as ConfigurationContainer } catch (_: ClassCastException) { // KGP-generated dependency accessor; обходим через raw project. @Suppress("UNCHECKED_CAST") (project as org.gradle.api.Project).configurations as ConfigurationContainer } from(cc.getByName("jvmRuntimeClasspath")) mergeServiceFiles() duplicatesStrategy = DuplicatesStrategy.EXCLUDE manifest { attributes["Main-Class"] = "pw.binom.agentik.standalone.MainKt" attributes["Implementation-Title"] = "agentik-standalone" attributes["Implementation-Version"] = project.version.toString() } includeEmptyDirs = false }