refactor(storage): split :storage-core into message-store-api + working-memory-api
ci / JVM build + tests (push) Failing after 2m5s
ci / JVM build + tests (push) Failing after 2m5s
Разделяет монолитный :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
This commit is contained in:
@@ -21,8 +21,8 @@ kotlin {
|
|||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
// :storage-core — для StorageBundle в ToolsetContext (commit 5+)
|
api(project(":storage-bundle"))
|
||||||
api(project(":storage-core"))
|
// :storage-bundle transitively подтягивает :message-store-api и :working-memory-api.
|
||||||
|
|
||||||
// litert-kmp: LiteTool интерфейс (sync describe/invoke)
|
// litert-kmp: LiteTool интерфейс (sync describe/invoke)
|
||||||
api(libs.litert.api)
|
api(libs.litert.api)
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ internal class AgentClient(
|
|||||||
/**
|
/**
|
||||||
* Запись event'а, которую возвращает /events/replay endpoint.
|
* Запись event'а, которую возвращает /events/replay endpoint.
|
||||||
*
|
*
|
||||||
* Это **мини-зеркало** `pw.binom.agentik.storage.events.EventRecord` — клиент
|
* Это **мини-зеркало** `pw.binom.agentik.messageStore.events.EventRecord` — клиент
|
||||||
* не зависит от `:storage-core`, поэтому определяет свою модель (wire-only).
|
* не зависит от `:storage-core`, поэтому определяет свою модель (wire-only).
|
||||||
*
|
*
|
||||||
* Формат полностью совместим с сервером — `agentikJson.encodeToString(...)` там
|
* Формат полностью совместим с сервером — `agentikJson.encodeToString(...)` там
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
api(project(":memory-api"))
|
api(project(":memory-api"))
|
||||||
api(project(":storage-core"))
|
api(project(":message-store-api"))
|
||||||
|
api(project(":working-memory-api"))
|
||||||
api(project(":skills"))
|
api(project(":skills"))
|
||||||
api(libs.litert.api)
|
api(libs.litert.api)
|
||||||
implementation(libs.kotlinx.coroutines.core)
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import pw.binom.agentik.memory.MemoryStore
|
|||||||
import pw.binom.agentik.memory.MemoryStoreEvent
|
import pw.binom.agentik.memory.MemoryStoreEvent
|
||||||
import pw.binom.agentik.memory.NewMemoryNote
|
import pw.binom.agentik.memory.NewMemoryNote
|
||||||
import pw.binom.agentik.memory.ReviewedTurn
|
import pw.binom.agentik.memory.ReviewedTurn
|
||||||
import pw.binom.agentik.storage.Ids
|
import pw.binom.agentik.messageStore.Ids
|
||||||
import pw.binom.litert.LiteLlm
|
import pw.binom.litert.LiteLlm
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import kotlinx.coroutines.withContext
|
|||||||
import pw.binom.agentik.memory.ConversationTurn
|
import pw.binom.agentik.memory.ConversationTurn
|
||||||
import pw.binom.litert.LiteConversationConfig
|
import pw.binom.litert.LiteConversationConfig
|
||||||
import pw.binom.litert.LiteLlm
|
import pw.binom.litert.LiteLlm
|
||||||
import pw.binom.agentik.storage.Ids
|
import pw.binom.agentik.messageStore.Ids
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlin.multiplatform)
|
||||||
|
alias(libs.plugins.kotlin.serialization)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public API для append-only storage агента (audit log, replay-after-disconnect,
|
||||||
|
// conversation metadata). Этот модуль НЕ содержит working memory — он для
|
||||||
|
// тонких клиентов, которые хотят только события/сообщения без тяжёлой
|
||||||
|
// runtime-логики.
|
||||||
|
//
|
||||||
|
// Зависимости:
|
||||||
|
// - kotlinx.coroutines / serialization (KMP).
|
||||||
|
// - БЕЗ :storage-core — мы его полностью выпиливаем, интерфейсы переезжают сюда.
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(21)
|
||||||
|
|
||||||
|
jvm()
|
||||||
|
linuxX64()
|
||||||
|
mingwX64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
commonMain.dependencies {
|
||||||
|
api(libs.kotlinx.coroutines.core)
|
||||||
|
api(libs.kotlinx.serialization.core)
|
||||||
|
api(libs.kotlinx.serialization.json)
|
||||||
|
}
|
||||||
|
commonTest.dependencies {
|
||||||
|
implementation(kotlin("test"))
|
||||||
|
implementation(libs.kotlinx.coroutines.test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlin.uuid.Uuid
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.messageStore
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage.events
|
package pw.binom.agentik.messageStore.events
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
@@ -23,7 +23,8 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
implementation(project(":proto"))
|
implementation(project(":proto"))
|
||||||
implementation(project(":storage-core"))
|
implementation(project(":message-store-api"))
|
||||||
|
implementation(project(":working-memory-api"))
|
||||||
|
|
||||||
// Ktor (без engine — engine подключает потребитель, см. :standalone).
|
// Ktor (без engine — engine подключает потребитель, см. :standalone).
|
||||||
implementation(libs.ktor.server.core)
|
implementation(libs.ktor.server.core)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
|
|||||||
import io.ktor.server.routing.Route
|
import io.ktor.server.routing.Route
|
||||||
import io.ktor.server.routing.route
|
import io.ktor.server.routing.route
|
||||||
import pw.binom.agentik.proto.Agent
|
import pw.binom.agentik.proto.Agent
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Встраивает HTTP/SSE-фасад протокола agentik в твой Ktor-роутинг.
|
* Встраивает HTTP/SSE-фасад протокола agentik в твой Ktor-роутинг.
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import pw.binom.agentik.proto.AllEvent
|
|||||||
import pw.binom.agentik.proto.Conversation
|
import pw.binom.agentik.proto.Conversation
|
||||||
import pw.binom.agentik.proto.Content
|
import pw.binom.agentik.proto.Content
|
||||||
import pw.binom.agentik.proto.Event
|
import pw.binom.agentik.proto.Event
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
internal fun Route.agentikRoutes(agent: Agent, eventStore: EventStore? = null) {
|
internal fun Route.agentikRoutes(agent: Agent, eventStore: EventStore? = null) {
|
||||||
|
|||||||
+5
-3
@@ -63,12 +63,14 @@ include(":memory-vector")
|
|||||||
// Интерфейсы хранилища и разговорной истории: MessageStore / WorkingMemoryStore /
|
// Интерфейсы хранилища и разговорной истории: MessageStore / WorkingMemoryStore /
|
||||||
// ConversationStore / ReflectionStore + StorageBundle агрегатор. Реализации —
|
// ConversationStore / ReflectionStore + StorageBundle агрегатор. Реализации —
|
||||||
// в :storage-inmemory / :storage-sqlite / :storage-android (последний deferred).
|
// в :storage-inmemory / :storage-sqlite / :storage-android (последний deferred).
|
||||||
include(":storage-core")
|
// In-memory реализация store'ов из :message-store-api и :working-memory-api. KMP,
|
||||||
// In-memory реализация всех 4 store'ов из :storage-core. KMP, без платформенных
|
|
||||||
// IO-зависимостей. Используется в тестах (быстрый setup, без JDBC) и будет
|
// IO-зависимостей. Используется в тестах (быстрый setup, без JDBC) и будет
|
||||||
// использоваться в Android-сборке (JVector/SQLite не подходят для ART out-of-box).
|
// использоваться в Android-сборке (JVector/SQLite не подходят для ART out-of-box).
|
||||||
|
include(":message-store-api")
|
||||||
|
include(":working-memory-api")
|
||||||
|
include(":storage-bundle")
|
||||||
include(":storage-inmemory")
|
include(":storage-inmemory")
|
||||||
// SQLDelight-реализация всех 4 store'ов из :storage-core. JVM-only (SQLDelight
|
// SQLDelight-реализация store'ов из :message-store-api и :working-memory-api. JVM-only
|
||||||
// native драйверов для KMP вне JVM пока не публикует). Содержит 4 .sq-файла +
|
// native драйверов для KMP вне JVM пока не публикует). Содержит 4 .sq-файла +
|
||||||
// 5 классов: SqliteStores, SqliteConversationStore, SqliteMessageStore,
|
// 5 классов: SqliteStores, SqliteConversationStore, SqliteMessageStore,
|
||||||
// SqliteWorkingMemoryStore, SqliteReflectionStore. Бэкенд для прод-запуска
|
// SqliteWorkingMemoryStore, SqliteReflectionStore. Бэкенд для прод-запуска
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ kotlin {
|
|||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
|
api(project(":storage-bundle"))
|
||||||
implementation(project(":proto"))
|
implementation(project(":proto"))
|
||||||
implementation(project(":server"))
|
implementation(project(":server"))
|
||||||
|
|
||||||
@@ -56,7 +57,8 @@ kotlin {
|
|||||||
if (!skipVectorMemory) {
|
if (!skipVectorMemory) {
|
||||||
implementation(project(":memory-vector"))
|
implementation(project(":memory-vector"))
|
||||||
}
|
}
|
||||||
implementation(project(":storage-core"))
|
implementation(project(":message-store-api"))
|
||||||
|
implementation(project(":working-memory-api"))
|
||||||
implementation(project(":storage-sqlite"))
|
implementation(project(":storage-sqlite"))
|
||||||
implementation(project(":agent-toolsets"))
|
implementation(project(":agent-toolsets"))
|
||||||
// Generic LLM-side tools (LlmReflector, SkillMiner, LlmMemoryReviewer,
|
// Generic LLM-side tools (LlmReflector, SkillMiner, LlmMemoryReviewer,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import pw.binom.agentik.standalone.agent.ChatConversation
|
|||||||
import pw.binom.agentik.llm.tools.LlmReflector
|
import pw.binom.agentik.llm.tools.LlmReflector
|
||||||
import pw.binom.agentik.llm.tools.SkillMiner
|
import pw.binom.agentik.llm.tools.SkillMiner
|
||||||
import pw.binom.agentik.standalone.agent.memory.Curator
|
import pw.binom.agentik.standalone.agent.memory.Curator
|
||||||
import pw.binom.agentik.storage.StorageBundle
|
import pw.binom.agentik.storageBundle.StorageBundle
|
||||||
import pw.binom.agentik.skills.SkillStore
|
import pw.binom.agentik.skills.SkillStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,7 +33,7 @@ import pw.binom.agentik.skills.SkillStore
|
|||||||
*/
|
*/
|
||||||
internal fun Route.debugRoutes(
|
internal fun Route.debugRoutes(
|
||||||
agent: Agent,
|
agent: Agent,
|
||||||
storage: pw.binom.agentik.storage.StorageBundle,
|
storage: pw.binom.agentik.storageBundle.StorageBundle,
|
||||||
reflector: LlmReflector?,
|
reflector: LlmReflector?,
|
||||||
skillMiner: SkillMiner?,
|
skillMiner: SkillMiner?,
|
||||||
skillStore: SkillStore?,
|
skillStore: SkillStore?,
|
||||||
@@ -127,14 +127,14 @@ internal fun Route.debugRoutes(
|
|||||||
* (для debug-триггеров reflector/miner; та же логика, что у хуков
|
* (для debug-триггеров reflector/miner; та же логика, что у хуков
|
||||||
* [ChatConversation]).
|
* [ChatConversation]).
|
||||||
*/
|
*/
|
||||||
internal suspend fun recentTurns(storage: pw.binom.agentik.storage.StorageBundle, conversationId: String, maxTurns: Int): List<ConversationTurn> {
|
internal suspend fun recentTurns(storage: pw.binom.agentik.storageBundle.StorageBundle, conversationId: String, maxTurns: Int): List<ConversationTurn> {
|
||||||
val rows = storage.workingMemoryStore.list(conversationId)
|
val rows = storage.workingMemoryStore.list(conversationId)
|
||||||
val pairs = mutableListOf<ConversationTurn>()
|
val pairs = mutableListOf<ConversationTurn>()
|
||||||
var pendingUser: String? = null
|
var pendingUser: String? = null
|
||||||
for (row in rows) {
|
for (row in rows) {
|
||||||
when (val e = row.entry) {
|
when (val e = row.entry) {
|
||||||
is pw.binom.agentik.storage.WorkingMemoryEntry.User -> pendingUser = e.content.text()
|
is pw.binom.agentik.workingMemory.WorkingMemoryEntry.User -> pendingUser = e.content.text()
|
||||||
is pw.binom.agentik.storage.WorkingMemoryEntry.Assistant -> {
|
is pw.binom.agentik.workingMemory.WorkingMemoryEntry.Assistant -> {
|
||||||
val user = pendingUser ?: ""
|
val user = pendingUser ?: ""
|
||||||
pendingUser = null
|
pendingUser = null
|
||||||
pairs += ConversationTurn(userMessage = user, assistantMessage = e.content.text())
|
pairs += ConversationTurn(userMessage = user, assistantMessage = e.content.text())
|
||||||
@@ -146,5 +146,5 @@ internal suspend fun recentTurns(storage: pw.binom.agentik.storage.StorageBundle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Текстовое содержимое записей working memory (Text-контент, без картинок). */
|
/** Текстовое содержимое записей working memory (Text-контент, без картинок). */
|
||||||
internal fun List<pw.binom.agentik.storage.Content>.text(): String =
|
internal fun List<pw.binom.agentik.messageStore.Content>.text(): String =
|
||||||
filterIsInstance<pw.binom.agentik.storage.Content.Text>().joinToString("\n") { it.body }
|
filterIsInstance<pw.binom.agentik.messageStore.Content.Text>().joinToString("\n") { it.body }
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ private fun runServer() {
|
|||||||
// и interval > 0. Загружаем top-K последних рефлексий из SQLite в system prompt.
|
// и interval > 0. Загружаем top-K последних рефлексий из SQLite в system prompt.
|
||||||
val reflector: pw.binom.agentik.llm.tools.LlmReflector? =
|
val reflector: pw.binom.agentik.llm.tools.LlmReflector? =
|
||||||
if (config.reflection.interval > 0) LlmReflector(llm = llm) else null
|
if (config.reflection.interval > 0) LlmReflector(llm = llm) else null
|
||||||
val recentReflections: List<pw.binom.agentik.storage.Reflection> =
|
val recentReflections: List<pw.binom.agentik.messageStore.Reflection> =
|
||||||
if (config.reflection.topK > 0) kotlinx.coroutines.runBlocking {
|
if (config.reflection.topK > 0) kotlinx.coroutines.runBlocking {
|
||||||
storage.reflectionStore.listRecent(config.reflection.topK)
|
storage.reflectionStore.listRecent(config.reflection.topK)
|
||||||
} else emptyList()
|
} else emptyList()
|
||||||
|
|||||||
+4
-4
@@ -12,10 +12,10 @@ import pw.binom.agentik.memory.ConversationTurn
|
|||||||
import pw.binom.agentik.memory.MemoryReviewer
|
import pw.binom.agentik.memory.MemoryReviewer
|
||||||
import pw.binom.agentik.memory.MemoryStore
|
import pw.binom.agentik.memory.MemoryStore
|
||||||
import pw.binom.agentik.skills.SkillStore
|
import pw.binom.agentik.skills.SkillStore
|
||||||
import pw.binom.agentik.storage.Content
|
import pw.binom.agentik.messageStore.Content
|
||||||
import pw.binom.agentik.storage.ReflectionStore
|
import pw.binom.agentik.messageStore.ReflectionStore
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.storage.WorkingMemoryStore
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
import pw.binom.agentik.llm.tools.LlmReflector
|
import pw.binom.agentik.llm.tools.LlmReflector
|
||||||
import pw.binom.agentik.llm.tools.SkillMiner
|
import pw.binom.agentik.llm.tools.SkillMiner
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ import pw.binom.agentik.skills.SkillCatalog
|
|||||||
import pw.binom.agentik.skills.renderSystemPromptSection
|
import pw.binom.agentik.skills.renderSystemPromptSection
|
||||||
import pw.binom.agentik.standalone.agent.memory.MemoryToolsFactory
|
import pw.binom.agentik.standalone.agent.memory.MemoryToolsFactory
|
||||||
import pw.binom.agentik.standalone.llm.LlmConfig
|
import pw.binom.agentik.standalone.llm.LlmConfig
|
||||||
import pw.binom.agentik.storage.ConversationRecord
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
import pw.binom.agentik.storage.Ids
|
import pw.binom.agentik.messageStore.Ids
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
import pw.binom.agentik.storage.StorageBundle
|
import pw.binom.agentik.storageBundle.StorageBundle
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.storage.events.EventRecord
|
import pw.binom.agentik.messageStore.events.EventRecord
|
||||||
import pw.binom.agentik.storage.events.EventType
|
import pw.binom.agentik.messageStore.events.EventType
|
||||||
import pw.binom.agentik.toolsets.DisableToolsetTool
|
import pw.binom.agentik.toolsets.DisableToolsetTool
|
||||||
import pw.binom.agentik.toolsets.EnableToolsetTool
|
import pw.binom.agentik.toolsets.EnableToolsetTool
|
||||||
import pw.binom.agentik.toolsets.NamedTool
|
import pw.binom.agentik.toolsets.NamedTool
|
||||||
@@ -68,7 +68,7 @@ import pw.binom.litert.LiteLlm
|
|||||||
*/
|
*/
|
||||||
class ChatAgent(
|
class ChatAgent(
|
||||||
override val id: String,
|
override val id: String,
|
||||||
private val storage: pw.binom.agentik.storage.StorageBundle,
|
private val storage: pw.binom.agentik.storageBundle.StorageBundle,
|
||||||
private val llm: LiteLlm,
|
private val llm: LiteLlm,
|
||||||
private val llmConfig: LlmConfig,
|
private val llmConfig: LlmConfig,
|
||||||
private val tools: List<NamedTool> = emptyList(),
|
private val tools: List<NamedTool> = emptyList(),
|
||||||
@@ -296,7 +296,7 @@ class ChatAgent(
|
|||||||
|
|
||||||
override fun createConversation(temp: Boolean): ProtoConversation {
|
override fun createConversation(temp: Boolean): ProtoConversation {
|
||||||
val now = now()
|
val now = now()
|
||||||
val id = pw.binom.agentik.storage.Ids.new("conv")
|
val id = pw.binom.agentik.messageStore.Ids.new("conv")
|
||||||
val rec = ConversationRecord(
|
val rec = ConversationRecord(
|
||||||
id = id,
|
id = id,
|
||||||
title = null,
|
title = null,
|
||||||
|
|||||||
+4
-4
@@ -6,10 +6,10 @@ import pw.binom.agentik.memory.ConversationTurn
|
|||||||
import pw.binom.agentik.memory.MemoryReviewer
|
import pw.binom.agentik.memory.MemoryReviewer
|
||||||
import pw.binom.agentik.memory.MemoryStore
|
import pw.binom.agentik.memory.MemoryStore
|
||||||
import pw.binom.agentik.standalone.agent.memory.materializeReviewNote
|
import pw.binom.agentik.standalone.agent.memory.materializeReviewNote
|
||||||
import pw.binom.agentik.storage.Content
|
import pw.binom.agentik.messageStore.Content
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.storage.WorkingMemoryRow
|
import pw.binom.agentik.workingMemory.WorkingMemoryRow
|
||||||
import pw.binom.agentik.storage.WorkingMemoryStore
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
import pw.binom.litert.LiteContentPart
|
import pw.binom.litert.LiteContentPart
|
||||||
import pw.binom.litert.LiteConversation
|
import pw.binom.litert.LiteConversation
|
||||||
import pw.binom.litert.LiteConversationConfig
|
import pw.binom.litert.LiteConversationConfig
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package pw.binom.agentik.standalone.agent
|
|||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import pw.binom.agentik.memory.MemoryPrefetcher
|
import pw.binom.agentik.memory.MemoryPrefetcher
|
||||||
import pw.binom.litert.LiteContentPart
|
import pw.binom.litert.LiteContentPart
|
||||||
import pw.binom.agentik.storage.MessageContext
|
import pw.binom.agentik.messageStore.MessageContext
|
||||||
import pw.binom.agentik.storage.MessageOrigin
|
import pw.binom.agentik.messageStore.MessageOrigin
|
||||||
|
|
||||||
internal class ContextBuilder(
|
internal class ContextBuilder(
|
||||||
private val memoryPrefetcher: MemoryPrefetcher?,
|
private val memoryPrefetcher: MemoryPrefetcher?,
|
||||||
|
|||||||
+4
-4
@@ -8,10 +8,10 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import pw.binom.agentik.proto.Event as ProtoEvent
|
import pw.binom.agentik.proto.Event as ProtoEvent
|
||||||
import pw.binom.agentik.storage.Ids
|
import pw.binom.agentik.messageStore.Ids
|
||||||
import pw.binom.agentik.storage.events.EventRecord
|
import pw.binom.agentik.messageStore.events.EventRecord
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
import pw.binom.agentik.storage.events.EventType
|
import pw.binom.agentik.messageStore.events.EventType
|
||||||
|
|
||||||
private val log = KotlinLogging.logger {}
|
private val log = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -28,18 +28,18 @@ import pw.binom.agentik.proto.Event as ProtoEvent
|
|||||||
import pw.binom.agentik.proto.Message as ProtoMessage
|
import pw.binom.agentik.proto.Message as ProtoMessage
|
||||||
import pw.binom.agentik.proto.MessageContext as ProtoMessageContext
|
import pw.binom.agentik.proto.MessageContext as ProtoMessageContext
|
||||||
import pw.binom.agentik.skills.SkillStore
|
import pw.binom.agentik.skills.SkillStore
|
||||||
import pw.binom.agentik.storage.Content
|
import pw.binom.agentik.messageStore.Content
|
||||||
import pw.binom.agentik.storage.ConversationRecord
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
import pw.binom.agentik.storage.ConversationStore
|
import pw.binom.agentik.messageStore.ConversationStore
|
||||||
import pw.binom.agentik.storage.MessageContext
|
import pw.binom.agentik.messageStore.MessageContext
|
||||||
import pw.binom.agentik.storage.MessageOrigin
|
import pw.binom.agentik.messageStore.MessageOrigin
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.MessageStore
|
import pw.binom.agentik.messageStore.MessageStore
|
||||||
import pw.binom.agentik.storage.ReflectionStore
|
import pw.binom.agentik.messageStore.ReflectionStore
|
||||||
import pw.binom.agentik.storage.StorageBundle
|
import pw.binom.agentik.storageBundle.StorageBundle
|
||||||
import pw.binom.agentik.storage.TurnTokens
|
import pw.binom.agentik.messageStore.TurnTokens
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.storage.WorkingMemoryStore
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
import pw.binom.agentik.toolsets.ToolsetDispatchPolicy
|
import pw.binom.agentik.toolsets.ToolsetDispatchPolicy
|
||||||
import pw.binom.litert.LiteContentPart
|
import pw.binom.litert.LiteContentPart
|
||||||
import pw.binom.litert.LiteConversation
|
import pw.binom.litert.LiteConversation
|
||||||
@@ -469,7 +469,7 @@ class ConversationLoop(
|
|||||||
private fun now(): Instant =
|
private fun now(): Instant =
|
||||||
Instant.fromEpochMilliseconds(System.currentTimeMillis())
|
Instant.fromEpochMilliseconds(System.currentTimeMillis())
|
||||||
|
|
||||||
private fun newId(prefix: String): String = pw.binom.agentik.storage.Ids.new(prefix)
|
private fun newId(prefix: String): String = pw.binom.agentik.messageStore.Ids.new(prefix)
|
||||||
|
|
||||||
private fun encodeArgsJson(arguments: Map<String, Any?>): String {
|
private fun encodeArgsJson(arguments: Map<String, Any?>): String {
|
||||||
val el = JsonElement.serializer()
|
val el = JsonElement.serializer()
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package pw.binom.agentik.standalone.agent
|
package pw.binom.agentik.standalone.agent
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import pw.binom.agentik.storage.ConversationRecord
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
import pw.binom.litert.LiteConversation
|
import pw.binom.litert.LiteConversation
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import pw.binom.agentik.toolsets.NamedTool
|
import pw.binom.agentik.toolsets.NamedTool
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import pw.binom.agentik.proto.Event as ProtoEvent
|
import pw.binom.agentik.proto.Event as ProtoEvent
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.MessageStore
|
import pw.binom.agentik.messageStore.MessageStore
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.toolsets.ToolsetDispatchPolicy
|
import pw.binom.agentik.toolsets.ToolsetDispatchPolicy
|
||||||
import pw.binom.litert.LiteToolCall
|
import pw.binom.litert.LiteToolCall
|
||||||
import pw.binom.litert.LiteTool
|
import pw.binom.litert.LiteTool
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import kotlin.test.assertFalse
|
|||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
import pw.binom.agentik.skills.SkillCatalog
|
import pw.binom.agentik.skills.SkillCatalog
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
|
|
||||||
class ChatAgentReflectionTest {
|
class ChatAgentReflectionTest {
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import pw.binom.agentik.skills.SkillCatalog
|
|||||||
import pw.binom.agentik.skills.SkillFile
|
import pw.binom.agentik.skills.SkillFile
|
||||||
import pw.binom.agentik.standalone.llm.LlmBackend
|
import pw.binom.agentik.standalone.llm.LlmBackend
|
||||||
import pw.binom.agentik.standalone.llm.LlmConfig
|
import pw.binom.agentik.standalone.llm.LlmConfig
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.storage.sqlite.SqliteStores
|
import pw.binom.agentik.storage.sqlite.SqliteStores
|
||||||
import pw.binom.litert.LiteContentPart
|
import pw.binom.litert.LiteContentPart
|
||||||
import pw.binom.litert.LiteConversation
|
import pw.binom.litert.LiteConversation
|
||||||
@@ -41,7 +41,7 @@ import pw.binom.agentik.toolsets.NamedTool
|
|||||||
|
|
||||||
class ChatAgentTest {
|
class ChatAgentTest {
|
||||||
|
|
||||||
private lateinit var storage: pw.binom.agentik.storage.StorageBundle
|
private lateinit var storage: pw.binom.agentik.storageBundle.StorageBundle
|
||||||
private lateinit var fakeLlm: FakeLiteLlm
|
private lateinit var fakeLlm: FakeLiteLlm
|
||||||
|
|
||||||
@BeforeTest
|
@BeforeTest
|
||||||
@@ -56,7 +56,7 @@ class ChatAgentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun newAgent(
|
private fun newAgent(
|
||||||
storage: pw.binom.agentik.storage.StorageBundle = this.storage,
|
storage: pw.binom.agentik.storageBundle.StorageBundle = this.storage,
|
||||||
llm: LiteLlm = this.fakeLlm,
|
llm: LiteLlm = this.fakeLlm,
|
||||||
tools: List<NamedTool> = emptyList(),
|
tools: List<NamedTool> = emptyList(),
|
||||||
skills: SkillCatalog = SkillCatalog.EMPTY,
|
skills: SkillCatalog = SkillCatalog.EMPTY,
|
||||||
@@ -160,10 +160,10 @@ class ChatAgentTest {
|
|||||||
|
|
||||||
// добавим сообщение, чтобы потом убедиться, что каскад сработал
|
// добавим сообщение, чтобы потом убедиться, что каскад сработал
|
||||||
storage.messageStore.append(
|
storage.messageStore.append(
|
||||||
pw.binom.agentik.storage.MessageRecord.UserMessage(
|
pw.binom.agentik.messageStore.MessageRecord.UserMessage(
|
||||||
id = "m1",
|
id = "m1",
|
||||||
conversationId = id,
|
conversationId = id,
|
||||||
content = listOf(pw.binom.agentik.storage.Content.Text("hi")),
|
content = listOf(pw.binom.agentik.messageStore.Content.Text("hi")),
|
||||||
createdAt = Instant.fromEpochMilliseconds(1_700_000_000_000),
|
createdAt = Instant.fromEpochMilliseconds(1_700_000_000_000),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -190,11 +190,11 @@ class ChatAgentTest {
|
|||||||
// user message записан в audit + working memory
|
// user message записан в audit + working memory
|
||||||
val msgs = storage.messageStore.listAll(conv.id)
|
val msgs = storage.messageStore.listAll(conv.id)
|
||||||
assertEquals(2, msgs.size)
|
assertEquals(2, msgs.size)
|
||||||
assertEquals("hi", (msgs[0] as pw.binom.agentik.storage.MessageRecord.UserMessage).content.let {
|
assertEquals("hi", (msgs[0] as pw.binom.agentik.messageStore.MessageRecord.UserMessage).content.let {
|
||||||
(it[0] as pw.binom.agentik.storage.Content.Text).body
|
(it[0] as pw.binom.agentik.messageStore.Content.Text).body
|
||||||
})
|
})
|
||||||
assertEquals("hello back", (msgs[1] as pw.binom.agentik.storage.MessageRecord.AssistantMessage).content.let {
|
assertEquals("hello back", (msgs[1] as pw.binom.agentik.messageStore.MessageRecord.AssistantMessage).content.let {
|
||||||
(it[0] as pw.binom.agentik.storage.Content.Text).body
|
(it[0] as pw.binom.agentik.messageStore.Content.Text).body
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,8 +327,8 @@ class ChatAgentTest {
|
|||||||
|
|
||||||
val msgs = storage.messageStore.listAll(conv.id)
|
val msgs = storage.messageStore.listAll(conv.id)
|
||||||
assertEquals(2, msgs.size)
|
assertEquals(2, msgs.size)
|
||||||
assertIs<pw.binom.agentik.storage.MessageRecord.UserMessage>(msgs[0])
|
assertIs<pw.binom.agentik.messageStore.MessageRecord.UserMessage>(msgs[0])
|
||||||
val err = assertIs<pw.binom.agentik.storage.MessageRecord.Error>(msgs[1])
|
val err = assertIs<pw.binom.agentik.messageStore.MessageRecord.Error>(msgs[1])
|
||||||
assertEquals("boom from llm", err.message)
|
assertEquals("boom from llm", err.message)
|
||||||
|
|
||||||
// backfill через getMessages (polling/reconnect) тоже видит ошибку
|
// backfill через getMessages (polling/reconnect) тоже видит ошибку
|
||||||
@@ -372,7 +372,7 @@ class ChatAgentTest {
|
|||||||
// audit: только user (assistant не успел сгенериться)
|
// audit: только user (assistant не успел сгенериться)
|
||||||
val msgs = storage.messageStore.listAll(conv.id)
|
val msgs = storage.messageStore.listAll(conv.id)
|
||||||
assertEquals(1, msgs.size)
|
assertEquals(1, msgs.size)
|
||||||
assertIs<pw.binom.agentik.storage.MessageRecord.UserMessage>(msgs[0])
|
assertIs<pw.binom.agentik.messageStore.MessageRecord.UserMessage>(msgs[0])
|
||||||
|
|
||||||
// working memory: только user (assistant skipped because пустой)
|
// working memory: только user (assistant skipped because пустой)
|
||||||
val wm = storage.workingMemoryStore.list(conv.id)
|
val wm = storage.workingMemoryStore.list(conv.id)
|
||||||
@@ -428,7 +428,7 @@ class ChatAgentTest {
|
|||||||
|
|
||||||
// audit: user + toolcall + toolresult (tool выполнился), assistant может быть
|
// audit: user + toolcall + toolresult (tool выполнился), assistant может быть
|
||||||
val msgs = storage.messageStore.listAll(conv.id)
|
val msgs = storage.messageStore.listAll(conv.id)
|
||||||
val toolResult = msgs.filterIsInstance<pw.binom.agentik.storage.MessageRecord.ToolResult>().firstOrNull()
|
val toolResult = msgs.filterIsInstance<pw.binom.agentik.messageStore.MessageRecord.ToolResult>().firstOrNull()
|
||||||
assertNotNull(toolResult, "tool result должен быть в audit — tool выполнился нормально")
|
assertNotNull(toolResult, "tool result должен быть в audit — tool выполнился нормально")
|
||||||
val toolResultResult = toolResult!!.result!!
|
val toolResultResult = toolResult!!.result!!
|
||||||
assertTrue(toolResultResult.contains("echo"), "tool result содержит реальный ответ тулы: $toolResultResult")
|
assertTrue(toolResultResult.contains("echo"), "tool result содержит реальный ответ тулы: $toolResultResult")
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ class ChatAgentToolsetsTest {
|
|||||||
|
|
||||||
private fun newAgent(
|
private fun newAgent(
|
||||||
toolsets: List<ToolsetContribution> = emptyList(),
|
toolsets: List<ToolsetContribution> = emptyList(),
|
||||||
): Pair<ChatAgent, pw.binom.agentik.storage.StorageBundle> {
|
): Pair<ChatAgent, pw.binom.agentik.storageBundle.StorageBundle> {
|
||||||
val storage = SqliteStores.inMemory().asBundle()
|
val storage = SqliteStores.inMemory().asBundle()
|
||||||
val agent = ChatAgent(
|
val agent = ChatAgent(
|
||||||
id = "test-agent",
|
id = "test-agent",
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import pw.binom.agentik.llm.tools.SummaryTurn
|
|||||||
*/
|
*/
|
||||||
class CompactionTest {
|
class CompactionTest {
|
||||||
|
|
||||||
private lateinit var storage: pw.binom.agentik.storage.StorageBundle
|
private lateinit var storage: pw.binom.agentik.storageBundle.StorageBundle
|
||||||
private lateinit var fakeLlm: FakeLiteLlm
|
private lateinit var fakeLlm: FakeLiteLlm
|
||||||
|
|
||||||
@BeforeTest
|
@BeforeTest
|
||||||
@@ -89,7 +89,7 @@ class CompactionTest {
|
|||||||
}
|
}
|
||||||
val wm = storage.workingMemoryStore.list(conv.id)
|
val wm = storage.workingMemoryStore.list(conv.id)
|
||||||
// Без compaction все ходы остаются в памяти (System + 10 user/assistant = 21 строк).
|
// Без compaction все ходы остаются в памяти (System + 10 user/assistant = 21 строк).
|
||||||
val summaries = wm.filter { it.entry is pw.binom.agentik.storage.WorkingMemoryEntry.Summary }
|
val summaries = wm.filter { it.entry is pw.binom.agentik.workingMemory.WorkingMemoryEntry.Summary }
|
||||||
assertEquals(0, summaries.size, "compaction must not run without contextWindow")
|
assertEquals(0, summaries.size, "compaction must not run without contextWindow")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ class CompactionTest {
|
|||||||
conv.send(listOf(ProtoContent.Text("first")))
|
conv.send(listOf(ProtoContent.Text("first")))
|
||||||
val wm = storage.workingMemoryStore.list(conv.id)
|
val wm = storage.workingMemoryStore.list(conv.id)
|
||||||
// System + User + Assistant = 3. Без compactor — никаких Summary.
|
// System + User + Assistant = 3. Без compactor — никаких Summary.
|
||||||
val summaries = wm.filter { it.entry is pw.binom.agentik.storage.WorkingMemoryEntry.Summary }
|
val summaries = wm.filter { it.entry is pw.binom.agentik.workingMemory.WorkingMemoryEntry.Summary }
|
||||||
assertEquals(0, summaries.size, "no compaction runs without compactor")
|
assertEquals(0, summaries.size, "no compaction runs without compactor")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,10 +119,10 @@ class CompactionTest {
|
|||||||
assertTrue(compactor.calls > 0, "compactor must be called at least once when above threshold")
|
assertTrue(compactor.calls > 0, "compactor must be called at least once when above threshold")
|
||||||
// В working memory должна появиться Summary.
|
// В working memory должна появиться Summary.
|
||||||
val wm = storage.workingMemoryStore.list(conv.id)
|
val wm = storage.workingMemoryStore.list(conv.id)
|
||||||
val summaries = wm.filter { it.entry is pw.binom.agentik.storage.WorkingMemoryEntry.Summary }
|
val summaries = wm.filter { it.entry is pw.binom.agentik.workingMemory.WorkingMemoryEntry.Summary }
|
||||||
assertTrue(summaries.isNotEmpty(), "at least one Summary entry should be present after compaction")
|
assertTrue(summaries.isNotEmpty(), "at least one Summary entry should be present after compaction")
|
||||||
// Summary-текст — то, что вернул наш compactor.
|
// Summary-текст — то, что вернул наш compactor.
|
||||||
val summaryText = (summaries.first().entry as pw.binom.agentik.storage.WorkingMemoryEntry.Summary).text
|
val summaryText = (summaries.first().entry as pw.binom.agentik.workingMemory.WorkingMemoryEntry.Summary).text
|
||||||
assertTrue(summaryText.startsWith("**Goal**"), "summary text should come from compactor: $summaryText")
|
assertTrue(summaryText.startsWith("**Goal**"), "summary text should come from compactor: $summaryText")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,8 +162,8 @@ class CompactionTest {
|
|||||||
// Должны быть: System + хотя бы один Summary + последние KEEP_RECENT_TURNS ходов.
|
// Должны быть: System + хотя бы один Summary + последние KEEP_RECENT_TURNS ходов.
|
||||||
// KEEP_RECENT_TURNS = 4 → user/assistant последних двух ходов (third + second) могут быть не тронуты.
|
// KEEP_RECENT_TURNS = 4 → user/assistant последних двух ходов (third + second) могут быть не тронуты.
|
||||||
val userAssistantCount = wm.count {
|
val userAssistantCount = wm.count {
|
||||||
it.entry is pw.binom.agentik.storage.WorkingMemoryEntry.User ||
|
it.entry is pw.binom.agentik.workingMemory.WorkingMemoryEntry.User ||
|
||||||
it.entry is pw.binom.agentik.storage.WorkingMemoryEntry.Assistant
|
it.entry is pw.binom.agentik.workingMemory.WorkingMemoryEntry.Assistant
|
||||||
}
|
}
|
||||||
// Минимум 1 ход остаётся (KEEP_RECENT_TURNS).
|
// Минимум 1 ход остаётся (KEEP_RECENT_TURNS).
|
||||||
assertTrue(userAssistantCount >= 1, "at least one recent turn must be preserved")
|
assertTrue(userAssistantCount >= 1, "at least one recent turn must be preserved")
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
package pw.binom.agentik.standalone.agent
|
package pw.binom.agentik.standalone.agent
|
||||||
|
|
||||||
import pw.binom.agentik.storage.MessageContext
|
import pw.binom.agentik.messageStore.MessageContext
|
||||||
import pw.binom.agentik.storage.MessageOrigin.EVENT
|
import pw.binom.agentik.messageStore.MessageOrigin.EVENT
|
||||||
import pw.binom.agentik.storage.MessageOrigin.SYSTEM
|
import pw.binom.agentik.messageStore.MessageOrigin.SYSTEM
|
||||||
import pw.binom.agentik.storage.MessageOrigin.USER
|
import pw.binom.agentik.messageStore.MessageOrigin.USER
|
||||||
import pw.binom.litert.LiteContentPart
|
import pw.binom.litert.LiteContentPart
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import kotlin.time.Instant
|
|||||||
*/
|
*/
|
||||||
class MemoryWiringTest {
|
class MemoryWiringTest {
|
||||||
|
|
||||||
private lateinit var storage: pw.binom.agentik.storage.StorageBundle
|
private lateinit var storage: pw.binom.agentik.storageBundle.StorageBundle
|
||||||
private lateinit var fakeLlm: FakeLiteLlm
|
private lateinit var fakeLlm: FakeLiteLlm
|
||||||
private lateinit var root: Path
|
private lateinit var root: Path
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -1,4 +1,10 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.standalone.persistence
|
||||||
|
import pw.binom.agentik.messageStore.MessageContext
|
||||||
|
import pw.binom.agentik.messageStore.MessageOrigin
|
||||||
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
|
import pw.binom.agentik.messageStore.Content
|
||||||
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import pw.binom.agentik.storage.sqlite.SqliteStores
|
import pw.binom.agentik.storage.sqlite.SqliteStores
|
||||||
+6
-1
@@ -1,4 +1,9 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.standalone.persistence
|
||||||
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
|
import pw.binom.agentik.messageStore.Content
|
||||||
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
+11
-1
@@ -1,4 +1,14 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.standalone.persistence
|
||||||
|
import pw.binom.agentik.messageStore.TurnTokens
|
||||||
|
import pw.binom.agentik.messageStore.MessageBodyPayload
|
||||||
|
import pw.binom.agentik.messageStore.encodeBodyPayload
|
||||||
|
import pw.binom.agentik.messageStore.decodeBodyPayload
|
||||||
|
import pw.binom.agentik.messageStore.MessageContext
|
||||||
|
import pw.binom.agentik.messageStore.MessageOrigin
|
||||||
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
|
import pw.binom.agentik.messageStore.Content
|
||||||
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlin.multiplatform)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Агрегатор всех 5 storage-интерфейсов (MessageStore + ReflectionStore +
|
||||||
|
// EventStore + ConversationStore + WorkingMemoryStore). Зависит от обоих API
|
||||||
|
// модулей. Нужен только server-side рантайму (`:standalone`, `:agentik-cli`,
|
||||||
|
// `:agent-toolsets`, будущий `:android-agent` core). Тонкие клиенты этот модуль
|
||||||
|
// НЕ подтягивают — они работают с одним только `:message-store-api`.
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(21)
|
||||||
|
|
||||||
|
jvm()
|
||||||
|
linuxX64()
|
||||||
|
mingwX64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
commonMain.dependencies {
|
||||||
|
api(project(":message-store-api"))
|
||||||
|
api(project(":working-memory-api"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package pw.binom.agentik.storageBundle
|
||||||
|
|
||||||
|
import pw.binom.agentik.messageStore.ConversationStore
|
||||||
|
import pw.binom.agentik.messageStore.MessageStore
|
||||||
|
import pw.binom.agentik.messageStore.ReflectionStore
|
||||||
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Агрегатор всех storage-интерфейсов для полного агент-рантайма.
|
||||||
|
*
|
||||||
|
* Зависит от **обоих** API модулей — `:message-store-api` и `:working-memory-api`.
|
||||||
|
* Тонкие клиенты, которым нужен только audit log, могут не подтягивать этот модуль
|
||||||
|
* и работать с [MessageStore] / [ReflectionStore] / [EventStore] / [ConversationStore]
|
||||||
|
* напрямую.
|
||||||
|
*
|
||||||
|
* **Реализации агрегата**:
|
||||||
|
* - [SqliteStorageBundle] — JVM-only, SQLDelight + SQLite. В `:storage-sqlite`.
|
||||||
|
* - [InMemoryStorageBundle] — KMP, Map-based. В `:storage-inmemory`.
|
||||||
|
*
|
||||||
|
* `SkillStore` НЕ входит — он в `:skills` (контент-файлы навыков), принимается
|
||||||
|
* отдельно в `ChatAgent`.
|
||||||
|
*
|
||||||
|
* AutoCloseable: один `close()` закрывает все store'ы; в реализациях без
|
||||||
|
* ресурсов (in-memory) — no-op.
|
||||||
|
*/
|
||||||
|
data class StorageBundle(
|
||||||
|
val conversationStore: ConversationStore,
|
||||||
|
val messageStore: MessageStore,
|
||||||
|
val workingMemoryStore: WorkingMemoryStore,
|
||||||
|
val reflectionStore: ReflectionStore,
|
||||||
|
val eventStore: EventStore? = null,
|
||||||
|
) : AutoCloseable {
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
conversationStore.close()
|
||||||
|
messageStore.close()
|
||||||
|
workingMemoryStore.close()
|
||||||
|
reflectionStore.close()
|
||||||
|
eventStore?.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
# `:storage-core` — контракт хранилища (KMP, jvm + native)
|
|
||||||
|
|
||||||
## Что это
|
|
||||||
|
|
||||||
Интерфейсы persistence-уровня для `:standalone`:
|
|
||||||
|
|
||||||
- `MessageStore` — append-only история сообщений по диалогу.
|
|
||||||
- `WorkingMemoryStore` — rolling buffer текущего хода (`AssistantMessage`,
|
|
||||||
`ToolExchange`, `UserMessage`, system-prompt) для fast-recovery
|
|
||||||
при reconnect/relance.
|
|
||||||
- `ConversationStore` — метаданные диалогов (id, title, model,
|
|
||||||
timestamps).
|
|
||||||
- `ReflectionStore` — LLM-reflections (свободная форма заметок
|
|
||||||
хранителя).
|
|
||||||
|
|
||||||
Решает: позволяет запустить агента на Android-in-memory, на
|
|
||||||
desktop-SQLite, или на production-SQLite, не переписывая логику.
|
|
||||||
Контракт минимален и async-friendly.
|
|
||||||
|
|
||||||
## Где используется
|
|
||||||
|
|
||||||
- `:storage-inmemory` — для тестов и Android.
|
|
||||||
- `:storage-sqlite` — прод (Desktop / server / однодесктопный
|
|
||||||
Android-development).
|
|
||||||
|
|
||||||
## Как подключить
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
kotlin {
|
|
||||||
sourceSets.commonMain.dependencies {
|
|
||||||
api("pw.binom.agentik:storage-core:0.1.0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Версии
|
|
||||||
|
|
||||||
`gradle/libs.versions.toml` → `[versions] agentik-storage-core`.
|
|
||||||
|
|
||||||
## Что в API
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
interface MessageStore {
|
|
||||||
suspend fun append(conversationId: String, message: Message): Unit
|
|
||||||
suspend fun after(conversationId: String, instant: Instant, limit: Int = 100): List<Message>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WorkingMemoryStore {
|
|
||||||
suspend fun save(conv: String, entry: WorkingMemoryEntry): Unit
|
|
||||||
fun load(conv: String): Flow<WorkingMemoryEntry> // cold flow
|
|
||||||
suspend fun clear(conv: String): Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface WorkingMemoryEntry {
|
|
||||||
val id: String
|
|
||||||
val date: Instant
|
|
||||||
class UserMessage(...) : WorkingMemoryEntry
|
|
||||||
class AssistantMessage(...) : WorkingMemoryEntry
|
|
||||||
class ToolExchange(val toolName: String, val toolArgsJson: String, val resultText: String, val wasCancelled: Boolean) : WorkingMemoryEntry
|
|
||||||
class SystemPrompt(...) : WorkingMemoryEntry
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Тесты
|
|
||||||
|
|
||||||
Контрактные тесты (общие для всех имплементаций) — в `:storage-sqlite`
|
|
||||||
и `:storage-inmemory`.
|
|
||||||
|
|
||||||
## Чего здесь НЕТ
|
|
||||||
|
|
||||||
- Никакого HTTP / SSE.
|
|
||||||
- Никакой конкретной БД. Backend'ы в `:storage-*`.
|
|
||||||
|
|
||||||
## Текущий статус
|
|
||||||
|
|
||||||
Используется продакшеном. Контракт зафиксирован после
|
|
||||||
interrupt-имплементации (см. [INTERRUPT-DESIGN.md](../../docs/INTERRUPT-DESIGN.md)).
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package pw.binom.agentik.storage
|
|
||||||
|
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Агрегатор всех storage-интерфейсов, нужных агенту для работы с историей диалога.
|
|
||||||
*
|
|
||||||
* Реализации:
|
|
||||||
* - [SqliteStorageBundle] — JVM-only, основная. SQLDelight + SQLite.
|
|
||||||
* - [InMemoryStorageBundle] — Map-based, для тестов.
|
|
||||||
* - `:storage-android` — Android-специфичная (deferred, Android-сборка в планах).
|
|
||||||
*
|
|
||||||
* `SkillStore` НЕ входит сюда — он живёт в модуле `:skills` (другая ответственность:
|
|
||||||
* не сообщения/рефлексии, а контент-файлы навыков) и принимается отдельно в `ChatAgent`.
|
|
||||||
*
|
|
||||||
* [EventStore] входит начиная с commit "event-store" — для replay после
|
|
||||||
* disconnect (см. `/events/replay` endpoint в `:server`).
|
|
||||||
*
|
|
||||||
* AutoCloseable: один `close()` закрывает все store'ы. В реализациях,
|
|
||||||
* которые не владеют ресурсами (in-memory), close — no-op.
|
|
||||||
*/
|
|
||||||
data class StorageBundle(
|
|
||||||
val conversationStore: ConversationStore,
|
|
||||||
val messageStore: MessageStore,
|
|
||||||
val workingMemoryStore: WorkingMemoryStore,
|
|
||||||
val reflectionStore: ReflectionStore,
|
|
||||||
val eventStore: EventStore? = null,
|
|
||||||
) : AutoCloseable {
|
|
||||||
override fun close() {
|
|
||||||
conversationStore.close()
|
|
||||||
messageStore.close()
|
|
||||||
workingMemoryStore.close()
|
|
||||||
reflectionStore.close()
|
|
||||||
eventStore?.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package pw.binom.agentik.storage
|
|
||||||
|
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
|
||||||
import kotlinx.serialization.json.buildJsonObject
|
|
||||||
import kotlin.test.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertNull
|
|
||||||
import kotlin.test.assertTrue
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Тесты payload-формата: контекст инициации хода персистится через
|
|
||||||
* `payload_json` SQLite, старый plain-array формат читается без потерь.
|
|
||||||
*/
|
|
||||||
class PayloadTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `user context roundtrips through MessageBodyPayload`() {
|
|
||||||
val ctx = MessageContext(
|
|
||||||
origin = MessageOrigin.USER,
|
|
||||||
description = "irc PRIVMSG",
|
|
||||||
sourceId = "irc:agentik",
|
|
||||||
)
|
|
||||||
val encoded = encodeBodyPayload(listOf(Content.Text("hi")), ctx)
|
|
||||||
// новый формат: wrapper-объект с полем context
|
|
||||||
assertTrue(encoded.startsWith("{"), "expected wrapped object, got: $encoded")
|
|
||||||
assertTrue(encoded.contains("\"context\""), "expected context field, got: $encoded")
|
|
||||||
|
|
||||||
val decoded = decodeBodyPayload(encoded)
|
|
||||||
assertEquals(listOf(Content.Text("hi")), decoded.content)
|
|
||||||
assertEquals(ctx, decoded.context)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `event context roundtrips with metadata`() {
|
|
||||||
val ctx = MessageContext(
|
|
||||||
origin = MessageOrigin.EVENT,
|
|
||||||
description = "scheduled cron morning-briefing",
|
|
||||||
sourceId = "cron-42",
|
|
||||||
metadata = buildJsonObject {
|
|
||||||
put("scheduledAt", JsonPrimitive("2026-09-14T08:00:00Z"))
|
|
||||||
put("rule", JsonPrimitive("0 8 * * *"))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
val encoded = encodeBodyPayload(listOf(Content.Text("wake up")), ctx)
|
|
||||||
val decoded = decodeBodyPayload(encoded)
|
|
||||||
assertEquals(MessageOrigin.EVENT, decoded.context?.origin)
|
|
||||||
assertEquals("scheduled cron morning-briefing", decoded.context?.description)
|
|
||||||
assertEquals("cron-42", decoded.context?.sourceId)
|
|
||||||
assertEquals("0 8 * * *", (decoded.context?.metadata?.let { (it as kotlinx.serialization.json.JsonObject)["rule"] } as? JsonPrimitive)?.content)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `null context produces wrapper without context field`() {
|
|
||||||
val encoded = encodeBodyPayload(listOf(Content.Text("hello")))
|
|
||||||
assertTrue(encoded.contains("\"content\""), "expected content field, got: $encoded")
|
|
||||||
val decoded = decodeBodyPayload(encoded)
|
|
||||||
assertEquals(listOf(Content.Text("hello")), decoded.content)
|
|
||||||
assertNull(decoded.context)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `legacy plain-array payload still decodes backward compat`() {
|
|
||||||
val legacy = "[" +
|
|
||||||
"""{"type":"text","body":"old message"}""" +
|
|
||||||
"]"
|
|
||||||
val decoded = decodeBodyPayload(legacy)
|
|
||||||
assertEquals(listOf(Content.Text("old message")), decoded.content)
|
|
||||||
assertNull(decoded.context)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `system context with description only roundtrips`() {
|
|
||||||
val ctx = MessageContext(origin = MessageOrigin.SYSTEM, description = "agent startup greeting")
|
|
||||||
val encoded = encodeBodyPayload(listOf(Content.Text("boot")), ctx)
|
|
||||||
val decoded = decodeBodyPayload(encoded)
|
|
||||||
assertEquals(MessageOrigin.SYSTEM, decoded.context?.origin)
|
|
||||||
assertEquals("agent startup greeting", decoded.context?.description)
|
|
||||||
assertNull(decoded.context?.sourceId)
|
|
||||||
assertNull(decoded.context?.metadata)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,9 @@ kotlin {
|
|||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
api(project(":storage-core"))
|
api(project(":message-store-api"))
|
||||||
|
api(project(":storage-bundle"))
|
||||||
|
api(project(":working-memory-api"))
|
||||||
}
|
}
|
||||||
commonTest.dependencies {
|
commonTest.dependencies {
|
||||||
implementation(kotlin("test"))
|
implementation(kotlin("test"))
|
||||||
|
|||||||
+2
-2
@@ -3,8 +3,8 @@ package pw.binom.agentik.storage.inmemory
|
|||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
import pw.binom.agentik.storage.ConversationRecord
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
import pw.binom.agentik.storage.ConversationStore
|
import pw.binom.agentik.messageStore.ConversationStore
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.inmemory
|
package pw.binom.agentik.storage.inmemory
|
||||||
|
|
||||||
import pw.binom.agentik.storage.events.EventRecord
|
import pw.binom.agentik.messageStore.events.EventRecord
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
import pw.binom.agentik.storage.events.EventType
|
import pw.binom.agentik.messageStore.events.EventType
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
|||||||
+4
-4
@@ -5,10 +5,10 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import pw.binom.agentik.storage.MessageEvent
|
import pw.binom.agentik.messageStore.MessageEvent
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.MessageStore
|
import pw.binom.agentik.messageStore.MessageStore
|
||||||
import pw.binom.agentik.storage.TokenStats
|
import pw.binom.agentik.messageStore.TokenStats
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+3
-3
@@ -5,9 +5,9 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
import pw.binom.agentik.storage.ReflectionEvent
|
import pw.binom.agentik.messageStore.ReflectionEvent
|
||||||
import pw.binom.agentik.storage.ReflectionStore
|
import pw.binom.agentik.messageStore.ReflectionStore
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package pw.binom.agentik.storage.inmemory
|
package pw.binom.agentik.storage.inmemory
|
||||||
|
|
||||||
import pw.binom.agentik.storage.StorageBundle
|
import pw.binom.agentik.storageBundle.StorageBundle
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+4
-4
@@ -2,10 +2,10 @@ package pw.binom.agentik.storage.inmemory
|
|||||||
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import pw.binom.agentik.storage.Ids
|
import pw.binom.agentik.messageStore.Ids
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.storage.WorkingMemoryRow
|
import pw.binom.agentik.workingMemory.WorkingMemoryRow
|
||||||
import pw.binom.agentik.storage.WorkingMemoryStore
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package pw.binom.agentik.storage.inmemory
|
package pw.binom.agentik.storage.inmemory
|
||||||
|
|
||||||
import pw.binom.agentik.storage.ConversationRecord
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
|
|||||||
+2
-2
@@ -2,8 +2,8 @@ package pw.binom.agentik.storage.inmemory
|
|||||||
|
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import pw.binom.agentik.storage.events.EventRecord
|
import pw.binom.agentik.messageStore.events.EventRecord
|
||||||
import pw.binom.agentik.storage.events.EventType
|
import pw.binom.agentik.messageStore.events.EventType
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
|||||||
+5
-5
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.inmemory
|
package pw.binom.agentik.storage.inmemory
|
||||||
|
|
||||||
import pw.binom.agentik.storage.Content
|
import pw.binom.agentik.messageStore.Content
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.TurnTokens
|
import pw.binom.agentik.messageStore.TurnTokens
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
@@ -113,8 +113,8 @@ class InMemoryMessageStoreTest {
|
|||||||
yield() // даём коллектору подписаться ДО append — иначе SharedFlow без replay потеряет эвент
|
yield() // даём коллектору подписаться ДО append — иначе SharedFlow без replay потеряет эвент
|
||||||
store.append(MessageRecord.UserMessage("u1", "c1", listOf(Content.Text("hi")), t0))
|
store.append(MessageRecord.UserMessage("u1", "c1", listOf(Content.Text("hi")), t0))
|
||||||
val ev = deferred.await()
|
val ev = deferred.await()
|
||||||
assertTrue(ev is pw.binom.agentik.storage.MessageEvent.Appended)
|
assertTrue(ev is pw.binom.agentik.messageStore.MessageEvent.Appended)
|
||||||
val appended = ev as pw.binom.agentik.storage.MessageEvent.Appended
|
val appended = ev as pw.binom.agentik.messageStore.MessageEvent.Appended
|
||||||
assertEquals("c1", appended.conversationId)
|
assertEquals("c1", appended.conversationId)
|
||||||
assertEquals("u1", appended.record.id)
|
assertEquals("u1", appended.record.id)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package pw.binom.agentik.storage.inmemory
|
package pw.binom.agentik.storage.inmemory
|
||||||
|
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
import pw.binom.agentik.storage.ReflectionEvent
|
import pw.binom.agentik.messageStore.ReflectionEvent
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package pw.binom.agentik.storage.inmemory
|
package pw.binom.agentik.storage.inmemory
|
||||||
|
|
||||||
import pw.binom.agentik.storage.Content
|
import pw.binom.agentik.messageStore.Content
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ kotlin {
|
|||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
api(project(":storage-core"))
|
api(project(":message-store-api"))
|
||||||
|
api(project(":storage-bundle"))
|
||||||
|
api(project(":working-memory-api"))
|
||||||
|
|
||||||
// ksqlite ещё не опубликован в Maven Central — только в локальном
|
// ksqlite ещё не опубликован в Maven Central — только в локальном
|
||||||
// caffeine-репо. Версия пока 0.1.0-SNAPSHOT (CI fallback из README).
|
// caffeine-репо. Версия пока 0.1.0-SNAPSHOT (CI fallback из README).
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
import pw.binom.agentik.storage.ConversationRecord
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
import pw.binom.agentik.storage.ConversationStore
|
import pw.binom.agentik.messageStore.ConversationStore
|
||||||
import pw.binom.db.ksqlite.SQLiteConnection
|
import pw.binom.db.ksqlite.SQLiteConnection
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import pw.binom.agentik.storage.events.EventRecord
|
import pw.binom.agentik.messageStore.events.EventRecord
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
import pw.binom.agentik.storage.events.EventType
|
import pw.binom.agentik.messageStore.events.EventType
|
||||||
import pw.binom.db.ksqlite.SQLiteConnection
|
import pw.binom.db.ksqlite.SQLiteConnection
|
||||||
import pw.binom.db.ksqlite.SQLitePreparedStatement
|
import pw.binom.db.ksqlite.SQLitePreparedStatement
|
||||||
import pw.binom.db.ksqlite.SQLiteResultSet
|
import pw.binom.db.ksqlite.SQLiteResultSet
|
||||||
|
|||||||
+5
-5
@@ -1,11 +1,11 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.MessageStore
|
import pw.binom.agentik.messageStore.MessageStore
|
||||||
import pw.binom.agentik.storage.TokenStats
|
import pw.binom.agentik.messageStore.TokenStats
|
||||||
import pw.binom.agentik.storage.decodeBodyPayload
|
import pw.binom.agentik.messageStore.decodeBodyPayload
|
||||||
import pw.binom.agentik.storage.encodeBodyPayload
|
import pw.binom.agentik.messageStore.encodeBodyPayload
|
||||||
import pw.binom.db.ksqlite.SQLiteConnection
|
import pw.binom.db.ksqlite.SQLiteConnection
|
||||||
import pw.binom.db.ksqlite.SQLiteResultSet
|
import pw.binom.db.ksqlite.SQLiteResultSet
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
import pw.binom.agentik.storage.ReflectionEvent
|
import pw.binom.agentik.messageStore.ReflectionEvent
|
||||||
import pw.binom.agentik.storage.ReflectionStore
|
import pw.binom.agentik.messageStore.ReflectionStore
|
||||||
import pw.binom.db.ksqlite.SQLiteConnection
|
import pw.binom.db.ksqlite.SQLiteConnection
|
||||||
import pw.binom.db.ksqlite.SQLiteResultSet
|
import pw.binom.db.ksqlite.SQLiteResultSet
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|||||||
+6
-6
@@ -1,11 +1,11 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import pw.binom.agentik.storage.ConversationStore
|
import pw.binom.agentik.messageStore.ConversationStore
|
||||||
import pw.binom.agentik.storage.MessageStore
|
import pw.binom.agentik.messageStore.MessageStore
|
||||||
import pw.binom.agentik.storage.ReflectionStore
|
import pw.binom.agentik.messageStore.ReflectionStore
|
||||||
import pw.binom.agentik.storage.StorageBundle
|
import pw.binom.agentik.storageBundle.StorageBundle
|
||||||
import pw.binom.agentik.storage.WorkingMemoryStore
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
import pw.binom.db.ksqlite.SQLiteConnection
|
import pw.binom.db.ksqlite.SQLiteConnection
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+4
-4
@@ -1,10 +1,10 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.storage.WorkingMemoryRow
|
import pw.binom.agentik.workingMemory.WorkingMemoryRow
|
||||||
import pw.binom.agentik.storage.WorkingMemoryStore
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
import pw.binom.agentik.storage.Ids
|
import pw.binom.agentik.messageStore.Ids
|
||||||
import pw.binom.db.ksqlite.SQLiteConnection
|
import pw.binom.db.ksqlite.SQLiteConnection
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.decodeBodyPayload
|
import pw.binom.agentik.messageStore.decodeBodyPayload
|
||||||
import pw.binom.agentik.storage.encodeBodyPayload
|
import pw.binom.agentik.messageStore.encodeBodyPayload
|
||||||
import pw.binom.db.ksqlite.SQLiteResultSet
|
import pw.binom.db.ksqlite.SQLiteResultSet
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import pw.binom.agentik.storage.ConversationRecord
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
import kotlin.test.AfterTest
|
import kotlin.test.AfterTest
|
||||||
import kotlin.test.BeforeTest
|
import kotlin.test.BeforeTest
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import pw.binom.agentik.storage.events.EventRecord
|
import pw.binom.agentik.messageStore.events.EventRecord
|
||||||
import pw.binom.agentik.storage.events.EventType
|
import pw.binom.agentik.messageStore.events.EventType
|
||||||
import kotlin.test.AfterTest
|
import kotlin.test.AfterTest
|
||||||
import kotlin.test.BeforeTest
|
import kotlin.test.BeforeTest
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import pw.binom.agentik.storage.Content
|
import pw.binom.agentik.messageStore.Content
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.TurnTokens
|
import pw.binom.agentik.messageStore.TurnTokens
|
||||||
import kotlin.test.AfterTest
|
import kotlin.test.AfterTest
|
||||||
import kotlin.test.BeforeTest
|
import kotlin.test.BeforeTest
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@@ -20,7 +20,7 @@ class KsqliteMessageStoreTest {
|
|||||||
stores = KsqliteStores.inMemory("msg-${kotlin.random.Random.nextLong()}")
|
stores = KsqliteStores.inMemory("msg-${kotlin.random.Random.nextLong()}")
|
||||||
kotlinx.coroutines.runBlocking {
|
kotlinx.coroutines.runBlocking {
|
||||||
stores.conversations.upsert(
|
stores.conversations.upsert(
|
||||||
pw.binom.agentik.storage.ConversationRecord(
|
pw.binom.agentik.messageStore.ConversationRecord(
|
||||||
"conv1", null, false,
|
"conv1", null, false,
|
||||||
Instant.parse("2026-09-15T10:00:00Z"),
|
Instant.parse("2026-09-15T10:00:00Z"),
|
||||||
Instant.parse("2026-09-15T10:00:00Z"),
|
Instant.parse("2026-09-15T10:00:00Z"),
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
import kotlin.test.AfterTest
|
import kotlin.test.AfterTest
|
||||||
import kotlin.test.BeforeTest
|
import kotlin.test.BeforeTest
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.ksqlite
|
package pw.binom.agentik.storage.ksqlite
|
||||||
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import pw.binom.agentik.storage.Content
|
import pw.binom.agentik.messageStore.Content
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import kotlin.test.AfterTest
|
import kotlin.test.AfterTest
|
||||||
import kotlin.test.BeforeTest
|
import kotlin.test.BeforeTest
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ kotlin {
|
|||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
api(project(":storage-core"))
|
api(project(":message-store-api"))
|
||||||
|
api(project(":storage-bundle"))
|
||||||
|
api(project(":working-memory-api"))
|
||||||
api(libs.sqldelight.runtime)
|
api(libs.sqldelight.runtime)
|
||||||
api(libs.sqldelight.coroutines)
|
api(libs.sqldelight.coroutines)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.sqlite
|
package pw.binom.agentik.storage.sqlite
|
||||||
|
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
import pw.binom.agentik.storage.ConversationRecord
|
import pw.binom.agentik.messageStore.ConversationRecord
|
||||||
import pw.binom.agentik.storage.ConversationStore
|
import pw.binom.agentik.messageStore.ConversationStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SQLite-реализация [ConversationStore].
|
* SQLite-реализация [ConversationStore].
|
||||||
|
|||||||
+3
-3
@@ -2,9 +2,9 @@ package pw.binom.agentik.storage.sqlite
|
|||||||
|
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import pw.binom.agentik.storage.events.EventRecord
|
import pw.binom.agentik.messageStore.events.EventRecord
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
import pw.binom.agentik.storage.events.EventType
|
import pw.binom.agentik.messageStore.events.EventType
|
||||||
import pw.binom.agentik.storage.sqlite.Agent_event as DbAgentEvent
|
import pw.binom.agentik.storage.sqlite.Agent_event as DbAgentEvent
|
||||||
|
|
||||||
private val log = KotlinLogging.logger {}
|
private val log = KotlinLogging.logger {}
|
||||||
|
|||||||
+5
-5
@@ -1,11 +1,11 @@
|
|||||||
package pw.binom.agentik.storage.sqlite
|
package pw.binom.agentik.storage.sqlite
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import pw.binom.agentik.storage.MessageRecord
|
import pw.binom.agentik.messageStore.MessageRecord
|
||||||
import pw.binom.agentik.storage.MessageStore
|
import pw.binom.agentik.messageStore.MessageStore
|
||||||
import pw.binom.agentik.storage.TokenStats
|
import pw.binom.agentik.messageStore.TokenStats
|
||||||
import pw.binom.agentik.storage.decodeBodyPayload
|
import pw.binom.agentik.messageStore.decodeBodyPayload
|
||||||
import pw.binom.agentik.storage.encodeBodyPayload
|
import pw.binom.agentik.messageStore.encodeBodyPayload
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+3
-3
@@ -6,9 +6,9 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
import pw.binom.agentik.storage.ReflectionEvent
|
import pw.binom.agentik.messageStore.ReflectionEvent
|
||||||
import pw.binom.agentik.storage.ReflectionStore
|
import pw.binom.agentik.messageStore.ReflectionStore
|
||||||
import pw.binom.agentik.storage.sqlite.AgentikDatabase
|
import pw.binom.agentik.storage.sqlite.AgentikDatabase
|
||||||
import pw.binom.agentik.storage.sqlite.Reflection as DbReflection
|
import pw.binom.agentik.storage.sqlite.Reflection as DbReflection
|
||||||
import pw.binom.agentik.storage.sqlite.ReflectionQueries
|
import pw.binom.agentik.storage.sqlite.ReflectionQueries
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ package pw.binom.agentik.storage.sqlite
|
|||||||
import app.cash.sqldelight.db.QueryResult
|
import app.cash.sqldelight.db.QueryResult
|
||||||
import app.cash.sqldelight.db.SqlDriver
|
import app.cash.sqldelight.db.SqlDriver
|
||||||
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
|
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
|
||||||
import pw.binom.agentik.storage.ConversationStore
|
import pw.binom.agentik.messageStore.ConversationStore
|
||||||
import pw.binom.agentik.storage.MessageStore
|
import pw.binom.agentik.messageStore.MessageStore
|
||||||
import pw.binom.agentik.storage.ReflectionStore
|
import pw.binom.agentik.messageStore.ReflectionStore
|
||||||
import pw.binom.agentik.storage.StorageBundle
|
import pw.binom.agentik.storageBundle.StorageBundle
|
||||||
import pw.binom.agentik.storage.events.EventStore
|
import pw.binom.agentik.messageStore.events.EventStore
|
||||||
import pw.binom.agentik.storage.sqlite.SqliteReflectionStore
|
import pw.binom.agentik.storage.sqlite.SqliteReflectionStore
|
||||||
import pw.binom.agentik.storage.WorkingMemoryStore
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Корневой объект SQLite-слоя: держит [SqlDriver] и пять store'ов (включая
|
* Корневой объект SQLite-слоя: держит [SqlDriver] и пять store'ов (включая
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
package pw.binom.agentik.storage.sqlite
|
package pw.binom.agentik.storage.sqlite
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import pw.binom.agentik.storage.WorkingMemoryEntry
|
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
|
||||||
import pw.binom.agentik.storage.WorkingMemoryRow
|
import pw.binom.agentik.workingMemory.WorkingMemoryRow
|
||||||
import pw.binom.agentik.storage.WorkingMemoryStore
|
import pw.binom.agentik.workingMemory.WorkingMemoryStore
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,4 +90,4 @@ private fun Working_memory.toRow(): WorkingMemoryRow {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newId(): String = pw.binom.agentik.storage.Ids.new("wm")
|
private fun newId(): String = pw.binom.agentik.messageStore.Ids.new("wm")
|
||||||
|
|||||||
+2
-2
@@ -5,8 +5,8 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
import pw.binom.agentik.storage.Reflection
|
import pw.binom.agentik.messageStore.Reflection
|
||||||
import pw.binom.agentik.storage.ReflectionEvent
|
import pw.binom.agentik.messageStore.ReflectionEvent
|
||||||
|
|
||||||
class ReflectionStoreTest {
|
class ReflectionStoreTest {
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package pw.binom.agentik.storage.sqlite
|
package pw.binom.agentik.storage.sqlite
|
||||||
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import pw.binom.agentik.storage.events.EventRecord
|
import pw.binom.agentik.messageStore.events.EventRecord
|
||||||
import pw.binom.agentik.storage.events.EventType
|
import pw.binom.agentik.messageStore.events.EventType
|
||||||
import kotlin.test.AfterTest
|
import kotlin.test.AfterTest
|
||||||
import kotlin.test.BeforeTest
|
import kotlin.test.BeforeTest
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|||||||
@@ -3,24 +3,22 @@ plugins {
|
|||||||
alias(libs.plugins.kotlin.serialization)
|
alias(libs.plugins.kotlin.serialization)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Public API для mutable working-memory — runtime context агента (compaction,
|
||||||
|
// order_idx, summary entries). Зависит от :message-store-api для Ids (wm- префикс).
|
||||||
|
//
|
||||||
|
// НЕ нужен тонким клиентам — только серверному рантайму (`:standalone`, `:agentik-cli`,
|
||||||
|
// будущий `:android-agent` core).
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvmToolchain(21)
|
jvmToolchain(21)
|
||||||
|
|
||||||
// Зеркалит набор :proto / :server / :memory-api — KMP-модуль с интерфейсами
|
|
||||||
// хранилища и разговорной истории, без платформенного IO. Конкретные
|
|
||||||
// реализации (sqlite, in-memory, android) живут в отдельных модулях.
|
|
||||||
jvm()
|
jvm()
|
||||||
macosX64()
|
|
||||||
macosArm64()
|
|
||||||
iosX64()
|
|
||||||
iosArm64()
|
|
||||||
iosSimulatorArm64()
|
|
||||||
linuxX64()
|
linuxX64()
|
||||||
linuxArm64()
|
|
||||||
mingwX64()
|
mingwX64()
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
|
api(project(":message-store-api"))
|
||||||
api(libs.kotlinx.coroutines.core)
|
api(libs.kotlinx.coroutines.core)
|
||||||
api(libs.kotlinx.serialization.core)
|
api(libs.kotlinx.serialization.core)
|
||||||
api(libs.kotlinx.serialization.json)
|
api(libs.kotlinx.serialization.json)
|
||||||
+3
-1
@@ -1,7 +1,9 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.workingMemory
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import pw.binom.agentik.messageStore.Content
|
||||||
|
import pw.binom.agentik.messageStore.MessageContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Запись в working memory диалога: ровно то, что агент сейчас видит в
|
* Запись в working memory диалога: ровно то, что агент сейчас видит в
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package pw.binom.agentik.storage
|
package pw.binom.agentik.workingMemory
|
||||||
|
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
Reference in New Issue
Block a user