reflection: Hermes-style self-reflection (последняя открытая Hermes-фича)
Self-reflection: каждые N пользовательских ходов агент запускает one-shot
LLM-размышление о качестве своих ответов, сохраняет score+weakSpots в SQLite,
подмешивает top-K последних рефлексий в system prompt как "слабые места".
* sqldelight: новая таблица reflection (id, conversation_id?, created_at,
turns_analyzed, score, summary, weak_spots_json) + индексы по created_at и
conversation_id.
* persistence: Reflection data class + ReflectionStore interface +
SqliteReflectionStore (insert/get/listRecent/listForConversation/
deleteOlderThan/count + events Flow). weakSpots хранятся как JSON-массив,
парсятся ручным сканером (без kotlinx-serialization в этом модуле).
* agent: LlmReflector (one-shot LiteLlm через createConversation +
send, structured-output JSON). ReflectionParser (hand-rolled,
толерантный к ```json fences и лидирующему/завершающему тексту;
score принимает int или строку; weakSpots — массив).
* agent: ReflectionPrompts (Russian system+user prompts, аналогично
LlmMemoryReviewer/ReviewPrompts).
* agent: ChatAgent.buildSystemPrompt расширен параметром reflections —
добавляется секция `## Self-reflection: твои слабые места за последнее время`
после memory и перед soul-prepend.
* agent: ChatConversation.scheduleReflection — каждые reflectionInterval
пользовательских ходов (счётчик через workingMemory.list) запускает
reflector на Dispatchers.IO, результат сохраняет в reflectionStore
с conversationId. Не блокирует turn.
* AgentikConfig: новые поля reflectionInterval (env AGENTIK_REFLECTION_INTERVAL,
default 10, clamped 0..1000) и reflectionTopK (env AGENTIK_REFLECTION_TOP_K,
default 3, clamped 0..20).
* Main.kt: если reflectionInterval > 0 — создаём LlmReflector(llm); загружаем
top-K из SQLite в system prompt.
* Ids.reflection() — генератор id "refl-<uuid>".
* Tests: ReflectionParserTest (7: clean JSON, fences, лидирующий текст,
score-as-string, отсутствие score, невалидный JSON, escape-последовательности),
ReflectionStoreTest (7: round-trip, listRecent с лимитом, фильтр по
conversation_id, deleteOlderThan, count, encode/decode строк), и
ChatAgentReflectionTest (3: секция скрыта при пустых, присутствует с
score+spots, порядок soul→memory→reflection).
* README: новые env-переменные, раздел "Self-reflection", startup output.
Smoke test подтверждает: reflection секция появляется в system prompt когда
в SQLite есть записи (listRecent возвращает непустой список). При
reflectionInterval=0 reflector не создаётся, scheduleReflection — no-op.
Tests: 305 total green (+17: 7+7+3). Fatjar собирается, logback-вывод
работает (logging: см. предыдущий коммит f5a551b).
This commit is contained in:
+2
-5
@@ -35,7 +35,7 @@ class SiglipEmbeddingProviderTest {
|
||||
|
||||
@Test
|
||||
fun `missing model file fails with clear error`() {
|
||||
val tmpDir = createTempDir(prefix = "no-model-")
|
||||
val tmpDir = kotlin.io.path.createTempDirectory(prefix = "no-model-").toFile()
|
||||
val nonExistent = File(tmpDir, "does-not-exist.onnx")
|
||||
assertFailsWith<Exception> {
|
||||
SiglipEmbeddingProvider(
|
||||
@@ -46,9 +46,6 @@ class SiglipEmbeddingProviderTest {
|
||||
}
|
||||
|
||||
private inline fun assume(condition: Boolean, message: () -> String) {
|
||||
if (!condition) {
|
||||
println("SKIPPED: ${message()}")
|
||||
return
|
||||
}
|
||||
org.junit.Assume.assumeTrue(message(), condition)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user