Files
agentik/standalone/build.gradle.kts
T
subochev 2d9ad526bb
ci / JVM build + tests (push) Failing after 2m5s
refactor(storage): split :storage-core into message-store-api + working-memory-api
Разделяет монолитный :storage-core на 3 модуля с чёткими границами:

  :message-store-api   — MessageStore, ReflectionStore, EventStore, ConversationStore +
                          Content, Payload, MessageContext, Ids, MessageEvent
                          (audit log + event stream)
  :working-memory-api  — WorkingMemoryStore + WorkingMemoryEntry
                          (runtime context с compaction)
  :storage-bundle      — StorageBundle агрегатор, зависит от обоих
                          (только для server-side runtime)

Пакеты:
  pw.binom.agentik.storage.*  → УДАЛЕНО
  pw.binom.agentik.messageStore.*        — append-only API
  pw.binom.agentik.messageStore.events.* — EventStore + EventRecord
  pw.binom.agentik.workingMemory.*      — WM API
  pw.binom.agentik.storageBundle.*       — aggregator

Зачем:
  - Тонкий клиент может подтянуть ТОЛЬКО :message-store-api (~15KB, нет
    compaction-логики, нет MessageStore+WorkingMemoryStore cross-deps).
  - Android-agent в будущем подключит :message-store-api для audit log,
    серверный runtime — :storage-bundle со всем.
  - Компиляционные границы защищают от случайной зависимости от WM
    в read-only клиентах (раньше один :storage-core не давал такой
    гарантии).

Миграция:
  - Имплементации (:storage-inmemory, :storage-sqlite, :storage-ksqlite)
    обновили package + добавили deps на оба API модуля + :storage-bundle.
  - Тесты из :storage-core (PersistenceTest, SqliteStoresMigrationTest,
    TokenStatsTest) переехали в :standalone, получили testImplementation
    на оба API модуля и импорты новых типов.
  - 52 файла в :standalone, :agent-toolsets, :llm-tools, :server, :client,
    :agentik-cli обновили FQN.
  - :storage-core удалён.

Совместимость схем не меняется — все 5 impl'ов (3 backend × 5 store) хранят
данные в тех же таблицах, миграция между Sqlite и Ksqlite возможна через SQL dump.

Тесты:
  standalone         178 ✅
  agent-toolsets      36 ✅
  storage-inmemory    47 ✅
  storage-sqlite      17 ✅  (включая переехавшие persistence/* + tokenStats)
  storage-ksqlite     36 ✅
  ---
  Total: 314 tests, 0 failures
2026-09-20 15:02:54 +03:00

166 lines
7.6 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@file:OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.artifacts.ConfigurationContainer
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"
kotlin {
jvmToolchain(21)
jvm {
binaries {
executable {
mainClass.set("pw.binom.agentik.standalone.MainKt")
}
}
}
sourceSets {
commonMain.dependencies {
api(project(":storage-bundle"))
implementation(project(":proto"))
implementation(project(":server"))
// Commons
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
// litert-kmp: контракт (commonMain)
api(libs.litert.api)
// litert-openai: JVM-реализация
implementation(libs.litert.openai)
}
jvmMain.dependencies {
// Парсер и загрузчик скилов (YAML frontmatter + markdown body).
implementation(project(":skills"))
// Долговременная память (Hermes-style MD-бэкенд) + хранилище истории.
implementation(project(":memory-api"))
implementation(project(":memory-md"))
if (!skipVectorMemory) {
implementation(project(":memory-vector"))
}
implementation(project(":message-store-api"))
implementation(project(":working-memory-api"))
implementation(project(":storage-sqlite"))
implementation(project(":agent-toolsets"))
// Generic LLM-side tools (LlmReflector, SkillMiner, LlmMemoryReviewer,
// ContextCompactor, парсеры/промпты). Вынесены из :standalone.
implementation(project(":llm-tools"))
// Generic MCP-bridge (McpConfig, McpRegistry, McpLiteToolAdapter).
// Вынесен из :standalone — generic мост между MCP-SDK и LiteTool.
implementation(project(":mcp-bridge"))
// 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)
implementation(libs.ktor.serialization.kotlinx.json)
// Логирование: 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.kotlin.test)
}
jvmTest.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>("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 org.gradle.api.artifacts.ConfigurationContainer
} catch (_: ClassCastException) {
// KGP-generated dependency accessor; обходим через raw project.
@Suppress("UNCHECKED_CAST")
(project as org.gradle.api.Project).configurations as org.gradle.api.artifacts.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
}