refactor(storage): split :storage-core into message-store-api + working-memory-api
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:
2026-09-20 15:02:54 +03:00
parent dd7aec8df1
commit 2d9ad526bb
82 changed files with 341 additions and 403 deletions
@@ -14,7 +14,7 @@ import pw.binom.agentik.standalone.agent.ChatConversation
import pw.binom.agentik.llm.tools.LlmReflector
import pw.binom.agentik.llm.tools.SkillMiner
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
/**
@@ -33,7 +33,7 @@ import pw.binom.agentik.skills.SkillStore
*/
internal fun Route.debugRoutes(
agent: Agent,
storage: pw.binom.agentik.storage.StorageBundle,
storage: pw.binom.agentik.storageBundle.StorageBundle,
reflector: LlmReflector?,
skillMiner: SkillMiner?,
skillStore: SkillStore?,
@@ -127,14 +127,14 @@ internal fun Route.debugRoutes(
* (для debug-триггеров reflector/miner; та же логика, что у хуков
* [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 pairs = mutableListOf<ConversationTurn>()
var pendingUser: String? = null
for (row in rows) {
when (val e = row.entry) {
is pw.binom.agentik.storage.WorkingMemoryEntry.User -> pendingUser = e.content.text()
is pw.binom.agentik.storage.WorkingMemoryEntry.Assistant -> {
is pw.binom.agentik.workingMemory.WorkingMemoryEntry.User -> pendingUser = e.content.text()
is pw.binom.agentik.workingMemory.WorkingMemoryEntry.Assistant -> {
val user = pendingUser ?: ""
pendingUser = null
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-контент, без картинок). */
internal fun List<pw.binom.agentik.storage.Content>.text(): String =
filterIsInstance<pw.binom.agentik.storage.Content.Text>().joinToString("\n") { it.body }
internal fun List<pw.binom.agentik.messageStore.Content>.text(): String =
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.
val reflector: pw.binom.agentik.llm.tools.LlmReflector? =
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 {
storage.reflectionStore.listRecent(config.reflection.topK)
} else emptyList()
@@ -12,10 +12,10 @@ import pw.binom.agentik.memory.ConversationTurn
import pw.binom.agentik.memory.MemoryReviewer
import pw.binom.agentik.memory.MemoryStore
import pw.binom.agentik.skills.SkillStore
import pw.binom.agentik.storage.Content
import pw.binom.agentik.storage.ReflectionStore
import pw.binom.agentik.storage.WorkingMemoryEntry
import pw.binom.agentik.storage.WorkingMemoryStore
import pw.binom.agentik.messageStore.Content
import pw.binom.agentik.messageStore.ReflectionStore
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
import pw.binom.agentik.workingMemory.WorkingMemoryStore
import pw.binom.agentik.llm.tools.LlmReflector
import pw.binom.agentik.llm.tools.SkillMiner
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.standalone.agent.memory.MemoryToolsFactory
import pw.binom.agentik.standalone.llm.LlmConfig
import pw.binom.agentik.storage.ConversationRecord
import pw.binom.agentik.storage.Ids
import pw.binom.agentik.storage.Reflection
import pw.binom.agentik.storage.StorageBundle
import pw.binom.agentik.storage.WorkingMemoryEntry
import pw.binom.agentik.storage.events.EventRecord
import pw.binom.agentik.storage.events.EventType
import pw.binom.agentik.messageStore.ConversationRecord
import pw.binom.agentik.messageStore.Ids
import pw.binom.agentik.messageStore.Reflection
import pw.binom.agentik.storageBundle.StorageBundle
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
import pw.binom.agentik.messageStore.events.EventRecord
import pw.binom.agentik.messageStore.events.EventType
import pw.binom.agentik.toolsets.DisableToolsetTool
import pw.binom.agentik.toolsets.EnableToolsetTool
import pw.binom.agentik.toolsets.NamedTool
@@ -68,7 +68,7 @@ import pw.binom.litert.LiteLlm
*/
class ChatAgent(
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 llmConfig: LlmConfig,
private val tools: List<NamedTool> = emptyList(),
@@ -296,7 +296,7 @@ class ChatAgent(
override fun createConversation(temp: Boolean): ProtoConversation {
val now = now()
val id = pw.binom.agentik.storage.Ids.new("conv")
val id = pw.binom.agentik.messageStore.Ids.new("conv")
val rec = ConversationRecord(
id = id,
title = null,
@@ -6,10 +6,10 @@ import pw.binom.agentik.memory.ConversationTurn
import pw.binom.agentik.memory.MemoryReviewer
import pw.binom.agentik.memory.MemoryStore
import pw.binom.agentik.standalone.agent.memory.materializeReviewNote
import pw.binom.agentik.storage.Content
import pw.binom.agentik.storage.WorkingMemoryEntry
import pw.binom.agentik.storage.WorkingMemoryRow
import pw.binom.agentik.storage.WorkingMemoryStore
import pw.binom.agentik.messageStore.Content
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
import pw.binom.agentik.workingMemory.WorkingMemoryRow
import pw.binom.agentik.workingMemory.WorkingMemoryStore
import pw.binom.litert.LiteContentPart
import pw.binom.litert.LiteConversation
import pw.binom.litert.LiteConversationConfig
@@ -3,8 +3,8 @@ package pw.binom.agentik.standalone.agent
import mu.KotlinLogging
import pw.binom.agentik.memory.MemoryPrefetcher
import pw.binom.litert.LiteContentPart
import pw.binom.agentik.storage.MessageContext
import pw.binom.agentik.storage.MessageOrigin
import pw.binom.agentik.messageStore.MessageContext
import pw.binom.agentik.messageStore.MessageOrigin
internal class ContextBuilder(
private val memoryPrefetcher: MemoryPrefetcher?,
@@ -8,10 +8,10 @@ import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import mu.KotlinLogging
import pw.binom.agentik.proto.Event as ProtoEvent
import pw.binom.agentik.storage.Ids
import pw.binom.agentik.storage.events.EventRecord
import pw.binom.agentik.storage.events.EventStore
import pw.binom.agentik.storage.events.EventType
import pw.binom.agentik.messageStore.Ids
import pw.binom.agentik.messageStore.events.EventRecord
import pw.binom.agentik.messageStore.events.EventStore
import pw.binom.agentik.messageStore.events.EventType
private val log = KotlinLogging.logger {}
@@ -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.MessageContext as ProtoMessageContext
import pw.binom.agentik.skills.SkillStore
import pw.binom.agentik.storage.Content
import pw.binom.agentik.storage.ConversationRecord
import pw.binom.agentik.storage.ConversationStore
import pw.binom.agentik.storage.MessageContext
import pw.binom.agentik.storage.MessageOrigin
import pw.binom.agentik.storage.MessageRecord
import pw.binom.agentik.storage.MessageStore
import pw.binom.agentik.storage.ReflectionStore
import pw.binom.agentik.storage.StorageBundle
import pw.binom.agentik.storage.TurnTokens
import pw.binom.agentik.storage.WorkingMemoryEntry
import pw.binom.agentik.storage.WorkingMemoryStore
import pw.binom.agentik.messageStore.Content
import pw.binom.agentik.messageStore.ConversationRecord
import pw.binom.agentik.messageStore.ConversationStore
import pw.binom.agentik.messageStore.MessageContext
import pw.binom.agentik.messageStore.MessageOrigin
import pw.binom.agentik.messageStore.MessageRecord
import pw.binom.agentik.messageStore.MessageStore
import pw.binom.agentik.messageStore.ReflectionStore
import pw.binom.agentik.storageBundle.StorageBundle
import pw.binom.agentik.messageStore.TurnTokens
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
import pw.binom.agentik.workingMemory.WorkingMemoryStore
import pw.binom.agentik.toolsets.ToolsetDispatchPolicy
import pw.binom.litert.LiteContentPart
import pw.binom.litert.LiteConversation
@@ -469,7 +469,7 @@ class ConversationLoop(
private fun now(): Instant =
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 {
val el = JsonElement.serializer()
@@ -1,7 +1,7 @@
package pw.binom.agentik.standalone.agent
import kotlinx.coroutines.CoroutineScope
import pw.binom.agentik.storage.ConversationRecord
import pw.binom.agentik.messageStore.ConversationRecord
import pw.binom.litert.LiteConversation
import java.util.concurrent.atomic.AtomicReference
import pw.binom.agentik.toolsets.NamedTool
@@ -5,9 +5,9 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import mu.KotlinLogging
import pw.binom.agentik.proto.Event as ProtoEvent
import pw.binom.agentik.storage.MessageRecord
import pw.binom.agentik.storage.MessageStore
import pw.binom.agentik.storage.WorkingMemoryEntry
import pw.binom.agentik.messageStore.MessageRecord
import pw.binom.agentik.messageStore.MessageStore
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
import pw.binom.agentik.toolsets.ToolsetDispatchPolicy
import pw.binom.litert.LiteToolCall
import pw.binom.litert.LiteTool
@@ -5,7 +5,7 @@ import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.time.Instant
import pw.binom.agentik.skills.SkillCatalog
import pw.binom.agentik.storage.Reflection
import pw.binom.agentik.messageStore.Reflection
class ChatAgentReflectionTest {
@@ -14,8 +14,8 @@ import pw.binom.agentik.skills.SkillCatalog
import pw.binom.agentik.skills.SkillFile
import pw.binom.agentik.standalone.llm.LlmBackend
import pw.binom.agentik.standalone.llm.LlmConfig
import pw.binom.agentik.storage.MessageRecord
import pw.binom.agentik.storage.WorkingMemoryEntry
import pw.binom.agentik.messageStore.MessageRecord
import pw.binom.agentik.workingMemory.WorkingMemoryEntry
import pw.binom.agentik.storage.sqlite.SqliteStores
import pw.binom.litert.LiteContentPart
import pw.binom.litert.LiteConversation
@@ -41,7 +41,7 @@ import pw.binom.agentik.toolsets.NamedTool
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
@BeforeTest
@@ -56,7 +56,7 @@ class ChatAgentTest {
}
private fun newAgent(
storage: pw.binom.agentik.storage.StorageBundle = this.storage,
storage: pw.binom.agentik.storageBundle.StorageBundle = this.storage,
llm: LiteLlm = this.fakeLlm,
tools: List<NamedTool> = emptyList(),
skills: SkillCatalog = SkillCatalog.EMPTY,
@@ -160,10 +160,10 @@ class ChatAgentTest {
// добавим сообщение, чтобы потом убедиться, что каскад сработал
storage.messageStore.append(
pw.binom.agentik.storage.MessageRecord.UserMessage(
pw.binom.agentik.messageStore.MessageRecord.UserMessage(
id = "m1",
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),
),
)
@@ -190,11 +190,11 @@ class ChatAgentTest {
// user message записан в audit + working memory
val msgs = storage.messageStore.listAll(conv.id)
assertEquals(2, msgs.size)
assertEquals("hi", (msgs[0] as pw.binom.agentik.storage.MessageRecord.UserMessage).content.let {
(it[0] as pw.binom.agentik.storage.Content.Text).body
assertEquals("hi", (msgs[0] as pw.binom.agentik.messageStore.MessageRecord.UserMessage).content.let {
(it[0] as pw.binom.agentik.messageStore.Content.Text).body
})
assertEquals("hello back", (msgs[1] as pw.binom.agentik.storage.MessageRecord.AssistantMessage).content.let {
(it[0] as pw.binom.agentik.storage.Content.Text).body
assertEquals("hello back", (msgs[1] as pw.binom.agentik.messageStore.MessageRecord.AssistantMessage).content.let {
(it[0] as pw.binom.agentik.messageStore.Content.Text).body
})
}
@@ -327,8 +327,8 @@ class ChatAgentTest {
val msgs = storage.messageStore.listAll(conv.id)
assertEquals(2, msgs.size)
assertIs<pw.binom.agentik.storage.MessageRecord.UserMessage>(msgs[0])
val err = assertIs<pw.binom.agentik.storage.MessageRecord.Error>(msgs[1])
assertIs<pw.binom.agentik.messageStore.MessageRecord.UserMessage>(msgs[0])
val err = assertIs<pw.binom.agentik.messageStore.MessageRecord.Error>(msgs[1])
assertEquals("boom from llm", err.message)
// backfill через getMessages (polling/reconnect) тоже видит ошибку
@@ -372,7 +372,7 @@ class ChatAgentTest {
// audit: только user (assistant не успел сгенериться)
val msgs = storage.messageStore.listAll(conv.id)
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 пустой)
val wm = storage.workingMemoryStore.list(conv.id)
@@ -428,7 +428,7 @@ class ChatAgentTest {
// audit: user + toolcall + toolresult (tool выполнился), assistant может быть
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 выполнился нормально")
val toolResultResult = toolResult!!.result!!
assertTrue(toolResultResult.contains("echo"), "tool result содержит реальный ответ тулы: $toolResultResult")
@@ -39,7 +39,7 @@ class ChatAgentToolsetsTest {
private fun newAgent(
toolsets: List<ToolsetContribution> = emptyList(),
): Pair<ChatAgent, pw.binom.agentik.storage.StorageBundle> {
): Pair<ChatAgent, pw.binom.agentik.storageBundle.StorageBundle> {
val storage = SqliteStores.inMemory().asBundle()
val agent = ChatAgent(
id = "test-agent",
@@ -40,7 +40,7 @@ import pw.binom.agentik.llm.tools.SummaryTurn
*/
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
@BeforeTest
@@ -89,7 +89,7 @@ class CompactionTest {
}
val wm = storage.workingMemoryStore.list(conv.id)
// Без 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")
}
@@ -101,7 +101,7 @@ class CompactionTest {
conv.send(listOf(ProtoContent.Text("first")))
val wm = storage.workingMemoryStore.list(conv.id)
// 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")
}
@@ -119,10 +119,10 @@ class CompactionTest {
assertTrue(compactor.calls > 0, "compactor must be called at least once when above threshold")
// В working memory должна появиться Summary.
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")
// 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")
}
@@ -162,8 +162,8 @@ class CompactionTest {
// Должны быть: System + хотя бы один Summary + последние KEEP_RECENT_TURNS ходов.
// KEEP_RECENT_TURNS = 4 → user/assistant последних двух ходов (third + second) могут быть не тронуты.
val userAssistantCount = wm.count {
it.entry is pw.binom.agentik.storage.WorkingMemoryEntry.User ||
it.entry is pw.binom.agentik.storage.WorkingMemoryEntry.Assistant
it.entry is pw.binom.agentik.workingMemory.WorkingMemoryEntry.User ||
it.entry is pw.binom.agentik.workingMemory.WorkingMemoryEntry.Assistant
}
// Минимум 1 ход остаётся (KEEP_RECENT_TURNS).
assertTrue(userAssistantCount >= 1, "at least one recent turn must be preserved")
@@ -1,9 +1,9 @@
package pw.binom.agentik.standalone.agent
import pw.binom.agentik.storage.MessageContext
import pw.binom.agentik.storage.MessageOrigin.EVENT
import pw.binom.agentik.storage.MessageOrigin.SYSTEM
import pw.binom.agentik.storage.MessageOrigin.USER
import pw.binom.agentik.messageStore.MessageContext
import pw.binom.agentik.messageStore.MessageOrigin.EVENT
import pw.binom.agentik.messageStore.MessageOrigin.SYSTEM
import pw.binom.agentik.messageStore.MessageOrigin.USER
import pw.binom.litert.LiteContentPart
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -49,7 +49,7 @@ import kotlin.time.Instant
*/
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 root: Path
@@ -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 pw.binom.agentik.storage.sqlite.SqliteStores
@@ -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.assertEquals
@@ -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.assertEquals