- README.md в каждом подмодуле: для библиотек — описание проблемы, подключение через maven-central/caffeine, версии в gradle/libs.versions.toml. Для запускаемых модулей — команды запуска + переменные среды с дефолтами. - Корневой README.md переписан как навигационный хаб: что это, где клиенты, где серверы, как собрать, как опубликовать. - build.gradle.kts: per-module POM-description через единую карту в rootProject.extra (порядок важен — нужно ДО apply плагина KMP, поэтому beforeEvaluate в subprojects). - .gitea/workflows/ci.yml (новый): build + jvmTest + shadowJar на PR/push main. - .gitea/workflows/release.yml (обновлён): публикует библиотеки в caffeine Nexus + собирает 3 fatjar'а и крепит их к release как бинарные ассеты.
:storage-core — pw.binom.agentik.storage
Интерфейсы хранилища разговорной истории агента: ConversationStore,
MessageStore, WorkingMemoryStore, ReflectionStore.
Без зависимостей от конкретной БД.
Какую проблему решает
:standalone нужно сохранять диалоги между перезапусками, держать working
memory (сжатую историю, которую видит LLM), reflection-записи. Но привязываться
к конкретной БД (SQLite) в контракте нельзя — для Android подходит другая
история, для тестов — in-memory, для экспериментов с Postgres — третья.
:storage-core отделяет что хранить (контракт) от где хранить
(бэкенды — :storage-sqlite, :storage-inmemory, и в будущем :storage-android).
Агрегатор StorageBundle собирает все 4 стора разом.
Что в контракте
interface ConversationStore : AutoCloseable {
suspend fun upsert(c: Conversation)
suspend fun get(id: String): Conversation?
suspend fun list(offset, limit, orderBy): List<Conversation>
suspend fun delete(id: String): Boolean
fun events(after: Instant): Flow<ConversationStoreEvent>
}
interface MessageStore : AutoCloseable {
suspend fun append(message: Message, conversationId: String, workingMemoryIndex: Int?)
suspend fun listByConversation(conversationId: String, after: Instant?, offset, limit): List<Message>
suspend fun update(message: Message, conversationId: String) // правка + бамп updatedAt
suspend fun deleteByConversation(conversationId: String)
}
interface WorkingMemoryStore : AutoCloseable {
suspend fun append(conversationId: String, entry: WorkingMemoryEntry, index: Int)
suspend fun listByConversation(conversationId: String, after: Instant?): List<WorkingMemoryEntry>
suspend fun compact(conversationId: String, fromIndex: Int, summary: SummaryEntry)
suspend fun reset(conversationId: String)
}
interface ReflectionStore : AutoCloseable {
suspend fun append(conversationId: String, reflection: ReflectionEntry)
suspend fun recent(conversationId: String?, topK: Int): List<ReflectionEntry>
}
WorkingMemoryEntry — sealed interface: User, Assistant, ToolExchange,
Summary. Каждый entry имеет instant (когда попал в working memory) и
index (порядковый номер для восстановления при компакции).
Подключение
commonMain {
implementation("pw.binom.agentik:storage-core:$version")
// + бэкенд:
implementation("pw.binom.agentik:storage-inmemory:$version") // тесты
// или
implementation("pw.binom.agentik:storage-sqlite:$version") // прод
}
Где смотреть версии
versionизgradle.properties(version=0.1.0)- релизы:
https://git.binom.pw/subochev/agentik/releases
Сборка
./gradlew :storage-core:build
KMP-таргеты — полный набор. Зависимости — только kotlinx-coroutines +
kotlinx-serialization.