Phase 5: :memory-vector (JVector + SQLite + LLM-эмбеддинги), memory-abstraction, compaction, MessageContext
- :memory-api — общий контракт MemoryStore/Prefetcher/Reviewer/Tools/MemorySystem
- :memory-md (KMP, kotlinx-io) — Hermes-style §-файлы, keyword overlap
- :memory-vector (JVM-only) — JVector ANN + SQLite + HttpEmbeddingClient
- :standalone — AGENTIK_MEMORY_BACKEND={md,vector,off}, выбор в Main.kt
- :standalone — compaction рабочего контекста (LiteLlmContextCompactor + reviewPreCompaction)
- :proto — MessageContext (origin: user/system/event) на send и в Message
- :server — backward-compat dual-format для POST /messages
- README — env-vars, vector-бэкенд docs
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package pw.binom.agentik.server
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import pw.binom.agentik.proto.Content
|
||||
import pw.binom.agentik.proto.Conversation
|
||||
import pw.binom.agentik.proto.MessageContext
|
||||
import kotlin.time.Instant
|
||||
|
||||
/**
|
||||
@@ -32,3 +34,19 @@ internal data class RequestCreateConversation(val temp: Boolean)
|
||||
|
||||
@Serializable
|
||||
internal data class RequestRename(val title: String)
|
||||
|
||||
/**
|
||||
* Тело `POST /conversations/{id}/messages`.
|
||||
*
|
||||
* Поддерживает два формата для backward-compat:
|
||||
* - **новый**: `{"content": [...], "context": {...}}` — с контекстом инициации;
|
||||
* - **старый**: голый JSON-массив `[...]` контента — context=null (обычный user).
|
||||
*
|
||||
* Маршрутизация формата делается в обработчике через try-{catch}-fallback на
|
||||
* `List<Content>` десериализацию.
|
||||
*/
|
||||
@Serializable
|
||||
internal data class RequestSendMessage(
|
||||
val content: List<Content>,
|
||||
val context: MessageContext? = null,
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.server.application.ApplicationCall
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.request.receive
|
||||
import io.ktor.server.request.receiveText
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.response.respondBytesWriter
|
||||
import io.ktor.server.response.respondText
|
||||
@@ -78,8 +79,17 @@ internal fun Route.agentikRoutes(agent: Agent) {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
return@post
|
||||
}
|
||||
val content = call.receive<List<Content>>()
|
||||
c.send(content)
|
||||
// Backward-compat: принимаем либо голый массив Content (старые клиенты),
|
||||
// либо объект {content, context}. Парсим как RequestSendMessage первой —
|
||||
// она устойчива к пустому/null context, и только если тип payload'а не
|
||||
// объект — fallback на List<Content>.
|
||||
val raw = call.receiveText()
|
||||
val parsed = parseSendRequest(raw)
|
||||
if (parsed == null) {
|
||||
call.respond(HttpStatusCode.BadRequest, "Invalid send payload (expected array of Content or {content, context?})")
|
||||
return@post
|
||||
}
|
||||
c.send(parsed.content, parsed.context)
|
||||
call.respond(HttpStatusCode.Accepted)
|
||||
}
|
||||
|
||||
@@ -159,3 +169,28 @@ private suspend fun <T> ApplicationCall.streamJsonSse(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Парсит тело `POST /conversations/{id}/messages` в двух форматах:
|
||||
* 1) новый объект `{content: [...], context?: {...}}`;
|
||||
* 2) старый голый массив `[...]` (context = null).
|
||||
*
|
||||
* Возвращает null при невалидном JSON в обоих форматах.
|
||||
*/
|
||||
private fun parseSendRequest(raw: String): RequestSendMessage? {
|
||||
val trimmed = raw.trimStart()
|
||||
if (trimmed.startsWith("[")) {
|
||||
// старый формат
|
||||
return runCatching {
|
||||
val list = agentikJson.decodeFromString(
|
||||
kotlinx.serialization.builtins.ListSerializer(Content.serializer()),
|
||||
raw,
|
||||
)
|
||||
RequestSendMessage(content = list, context = null)
|
||||
}.getOrNull()
|
||||
}
|
||||
// новый формат (или что-то иное — пробуем распарсить объект)
|
||||
return runCatching {
|
||||
agentikJson.decodeFromString(RequestSendMessage.serializer(), raw)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user