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:
@@ -0,0 +1,330 @@
|
||||
# Memory — дизайн (draft)
|
||||
|
||||
> Обсуждение долговременной памяти агента. Начат 2026-09-13.
|
||||
> Цель — выбрать модель хранения и поиска **до** написания кода.
|
||||
>
|
||||
> **Update 2026-09-14:** пивот хранения. Поднимаем не один monolithic
|
||||
> backend, а **абстракцию** (`MemoryStore`/`MemoryPrefetcher`/`MemoryReviewer`/
|
||||
> `MemoryTools` в `:memory-api`) и подменяемые реализации. v1 идёт на
|
||||
> Hermes-style **§-файлах** в `~/.agentik/memory/{USER,WORLD,PREFERENCES}.md`
|
||||
> (модуль `:memory-md`). SQLite+vector sidecar из §3 ниже переезжает в
|
||||
> следующий бэкенд (`:memory-vector`, фаза 2+) — обоснование там же,
|
||||
> отличий в API не будет. §3.1 («почему не файлы») остаётся аргументом
|
||||
> *против единого источника истины вне основной БД*, но под абстракцией
|
||||
> это уже не та проблема: факты в MD живут отдельно, а всё остальное
|
||||
> state диалогов по-прежнему в `agentik.db`.
|
||||
|
||||
## 1. Требования
|
||||
|
||||
Что память должна делать в agentik:
|
||||
|
||||
1. **Хранить факты** между сессиями: о пользователе (USER), о мире/проектах (WORLD), о предпочтениях (PREFERENCE).
|
||||
2. **Быстро находить релевантное** перед каждым ходом (prefetch, top-K).
|
||||
3. **Быть перезаписываемой** — пользователь и сам агент могут удалять/править/архивировать.
|
||||
4. **Переживать рестарты** — данные не теряются.
|
||||
5. **Работать на native таргетах** (`:server` уже KMP, `:standalone` linuxX64 в плане).
|
||||
6. **Single-binary** — никаких внешних сервисов типа Qdrant.
|
||||
|
||||
Чего **не** обязательно в v1:
|
||||
- миллионы заметок;
|
||||
- мультипользовательские tenant'ы;
|
||||
- sub-ms ANN на >100K векторов.
|
||||
|
||||
## 2. Варианты хранения
|
||||
|
||||
### A. Текстовые файлы (Hermes-style)
|
||||
- `~/.hermes/memories/MEMORY.md` и `USER.md`, разделитель записей `§`.
|
||||
- Поиск: substring / FTS5 / LLM-ранжирование.
|
||||
- **+** человекочитаемо, легко бэкапить (`cp`), редактировать руками.
|
||||
- **−** не семантический: «как мы деплоим» не найдёт «systemctl + k3s».
|
||||
- **−** параллельно с SQLite (у нас всё остальное в `agentik.db`) — два места правды.
|
||||
|
||||
### B. SQLite + FTS5
|
||||
- Всё в `agentik.db`: `memory_note` + `memory_note_fts` (виртуальная FTS5-таблица).
|
||||
- Поиск: FTS5 BM25 + trigram (для русского).
|
||||
- **+** один процесс, знакомый API, никаких новых зависимостей.
|
||||
- **−** keyword-only: «k8s» не матчится с «kubernetes», «Go» не находится в «статически типизированном языке с горутинами».
|
||||
|
||||
### C. SQLite (canonical) + векторный sidecar
|
||||
- Канонический store: `memory_note(id, category, content, created_at, last_used_at, use_count, conversation_id?, source, embedding_model, embedding_dim)` — обычные столбцы.
|
||||
- Векторный индекс: либо BLOB-столбец с packed Float32Array + brute-force cosine, либо отдельная embedded-БД (sqlite-vss, LanceDB).
|
||||
- **+** семантический поиск «по смыслу»; canonical store остаётся SQL-инспектируемым (можно `grep`, `sqlite3 agentik.db "SELECT …"`).
|
||||
- **+** гибридный ranking: similarity × recency × use_count.
|
||||
- **−** зависимость на embedding-модель.
|
||||
|
||||
### D. Чисто векторная БД (Qdrant / Milvus / Weaviate / Chroma)
|
||||
- **+** production-grade ANN.
|
||||
- **−** отдельный процесс, **ломает single-binary философию agentik**.
|
||||
|
||||
## 3. Рекомендация — гибрид **C**
|
||||
|
||||
**Канонический store — SQLite (как у нас всё остальное). Векторный индекс — sidecar.**
|
||||
|
||||
### 3.1 Почему не A (только файлы)
|
||||
|
||||
- В agentik **всё** состояние уже в SQLite: разговоры, working memory, summary, ошибки. Раздваивать на файлы = доп. синхронизация при каждом save/delete + новая категория бэкапов.
|
||||
- Файлы не масштабируются на >100 заметок без индекса: `grep -F` это O(N) по байтам.
|
||||
- Семантический поиск всё равно хочется — придётся добавлять векторы позже, тогда MD превращается в sidecar с теми же проблемами синхронизации, но без преимуществ.
|
||||
|
||||
### 3.2 Почему не B (только FTS5)
|
||||
|
||||
- Keyword-поиск быстро упирается в перефразирование: пользователь пишет «на чём билдим?», заметка говорит «building with Gradle 9.4.1» — без морфологии и/или эмбеддингов не находится.
|
||||
- Мультиязычность (русские заметки, английские запросы) — FTS5 с trigram работает, но семантика всё равно точнее.
|
||||
- Цена эмбеддингов на нашем масштабе ($0.004 на 1000 заметок единоразово + копейки на save) практически нулевая.
|
||||
|
||||
### 3.3 Почему не sqlite-vss / LanceDB embedded
|
||||
|
||||
- **sqlite-vss** — расширение SQLite, надо пересобирать под каждый native таргет (linuxX64, iosArm64, iosSimulatorArm64, mingwX64). Блокирует наш linuxX64-чек (NATIVE-COMPATIBILITY.md).
|
||||
- **LanceDB Java SDK** — есть (Apache 2.0), но JVM-only (JNI к нативной `.so`); на ios/iosSimulator без отдельного билда не работает.
|
||||
- На нашем масштабе (<10K заметок на агента) **brute-force cosine по BLOB-столбцу** — правильный порядок сложности:
|
||||
- 1 эмбеддинг = 1536 floats × 4 байта ≈ 6 KB (OpenAI small) или 384 × 4 ≈ 1.5 KB (MiniLM).
|
||||
- 10K × 6 KB = 60 MB в RAM. Дешево.
|
||||
- Поиск: 10K cosine-similarity = ~0.5 ms на JVM, <0.1 ms нативно. Не нужен HNSW.
|
||||
|
||||
Если когда-нибудь выйдем за 50K заметок — переедем на sqlite-vss или LanceDB без поломки API: `MemoryStore.search(query, k)` остаётся прежним.
|
||||
|
||||
### 3.4 Схема канонического store (предложение)
|
||||
|
||||
```sql
|
||||
CREATE TABLE memory_note (
|
||||
id TEXT PRIMARY KEY, -- "mem-<uuid>"
|
||||
category TEXT NOT NULL, -- 'user' | 'world' | 'preference'
|
||||
content TEXT NOT NULL, -- полный текст заметки
|
||||
conversation_id TEXT, -- NULL = global, иначе привязана к диалогу
|
||||
source TEXT NOT NULL, -- 'agent_save' | 'user_explicit' | 'auto_review'
|
||||
created_at INTEGER NOT NULL, -- epoch ms
|
||||
last_used_at INTEGER NOT NULL, -- когда последний раз матчилась в prefetch
|
||||
use_count INTEGER NOT NULL DEFAULT 0, -- сколько раз выдавалась в prefetch
|
||||
embedding_model TEXT NOT NULL, -- 'openai/text-embedding-3-small' (для миграций)
|
||||
embedding_dim INTEGER NOT NULL,
|
||||
embedding BLOB NOT NULL -- packed Float32Array, little-endian
|
||||
);
|
||||
|
||||
CREATE INDEX memory_note_category_idx ON memory_note(category);
|
||||
CREATE INDEX memory_note_last_used_idx ON memory_note(last_used_at DESC);
|
||||
CREATE INDEX memory_note_conversation_idx ON memory_note(conversation_id);
|
||||
```
|
||||
|
||||
Размер: на 10K заметок ≈ 60 MB (OpenAI small) или 15 MB (MiniLM). Дешевле, чем `agentik.db`-кеш.
|
||||
|
||||
## 4. Embedding: где считать
|
||||
|
||||
| Вариант | + | − |
|
||||
|---|---|---|
|
||||
| **Удалённо через litellm** (`text-embedding-3-small`, 1536-dim, $0.02/1M tokens) | 0 локальных деплов, высокое качество, мультиязычный | +1 HTTP на save/query; нужен ключ OpenAI |
|
||||
| **Локально через ONNX Runtime** (`all-MiniLM-L6-v2`, 384-dim, $0) | оффлайн, native-совместимо, без задержек | +25 MB к бинарю; хуже качество; инициализация ~500 ms |
|
||||
| **Через GOOGLE backend** (Gemini embedding) | уже работающее API | привязывает embedding к backend; GOOGLE может не иметь OpenAI embedding-API |
|
||||
| **Гибрид** (по умолчанию OpenAI, fallback на локальный если ключа нет) | resilience | +сложность |
|
||||
|
||||
**Рекомендация:** на v1 — **отдельный embedding-конфиг**, дефолт OpenAI через litellm, фоллбэк на локальный MiniLM через ONNX (если выйдет 0.3+ java SDK и мы соберём native-билды под все таргеты — отложим в v2).
|
||||
|
||||
### Стоимость на реальном использовании
|
||||
|
||||
- text-embedding-3-small, 1000 заметок × 200 токенов = 200K токенов = **$0.004** единоразово.
|
||||
- `memory_save` ≈ $0.00001 (200 токенов на индексацию).
|
||||
- `prefetch` (1 query embedding) ≈ $0.000003.
|
||||
- 100 заметок/месяц, 50 ходов/день = <$0.01/месяц. Ничтожно.
|
||||
|
||||
## 5. Жизненный цикл заметки
|
||||
|
||||
```
|
||||
review-loop (post-turn)
|
||||
│
|
||||
▼
|
||||
memory_save(category, content) ──► write to memory_note
|
||||
│ │
|
||||
│ ├──► embedding = embed(content)
|
||||
│ ├──► use_count = 0
|
||||
│ └──► last_used_at = created_at
|
||||
│
|
||||
▼
|
||||
prefetch(user_message, topK=10) ──► vector top-K + recency rerank
|
||||
│ │
|
||||
│ ▼
|
||||
│ bump use_count, last_used_at
|
||||
│ │
|
||||
│ ▼
|
||||
│ inject into user message prefix:
|
||||
│ "[Контекст — то, что я помню]
|
||||
│ - факт 1
|
||||
│ - факт 2
|
||||
│ [/Контекст]"
|
||||
│
|
||||
▼
|
||||
(eventually)
|
||||
│
|
||||
manual memory_delete(id) ◄── пользовательская команда
|
||||
│
|
||||
curator: last_used_at < 90 days ago ──► status = 'archived' (не видна в prefetch)
|
||||
```
|
||||
|
||||
`status` в схеме нет — архивация = `use_count == 0 AND last_used_at < archive_threshold`. Чисто по таймстампам, без LLM. Curator (Фаза 4) делает это в фоне раз в сутки.
|
||||
|
||||
## 6. Review-loop (как у Hermes, адаптированный)
|
||||
|
||||
Не fork-agent. **Один-shot LLM-вызов** на `LiteLlm.sendStreamContents` с урезанным туловым whitelist'ом (`memory_save`, `memory_search`, `memory_list`, `skill_save`). Тот же backend, что у основного агента.
|
||||
|
||||
Триггер: **каждые N ходов** (default 10, настраивается `AGENTIK_MEMORY_NUDGE_INTERVAL`).
|
||||
Условие: только после **успешно** завершённого хода (не прерванного, не упавшего).
|
||||
|
||||
Промпт (рус/англ по языку разговора):
|
||||
|
||||
```
|
||||
Ты — фоновый аналитик. Посмотри на последний разговор и реши, есть ли
|
||||
что запомнить в долговременную память агента. Сохраняй только если:
|
||||
1. Пользователь рассказал о себе: persona, привычки, предпочтения.
|
||||
2. Пользователь рассказал о проекте/окружении: стек, инструменты, сроки.
|
||||
3. Пользователь выразил ожидания к тому, как агент должен работать.
|
||||
|
||||
Если ничего нет — просто ответь "nothing to save" и не вызывай тулы.
|
||||
Если есть — вызови memory_save(category, content) для каждого факта.
|
||||
```
|
||||
|
||||
`category`: одна из `user` / `world` / `preference`. Агент решает сам.
|
||||
|
||||
## 7. Открытые вопросы (нужны решения)
|
||||
|
||||
| # | Вопрос | Предложение |
|
||||
|---|---|---|
|
||||
| 1 | **Переносимость embeddings между моделями.** Поменяем модель → переиндексировать всё? | Хранить `embedding_model` в строке; на старте проверять, что у всех строк он одинаковый; иначе фоновый reindex. Дёшево ($0.004 на 1000 заметок). |
|
||||
| 2 | **Мультиязычность.** Русские заметки + английские запросы. | text-embedding-3-small мультиязычен (тестировал на рус+англ — ок); MiniLM — частично. На v1 OpenAI хватает. |
|
||||
| 3 | **TTL заметок.** Hermes без TTL. У нас возможны устаревшие факты. | Curator (Фаза 4): `use_count == 0 AND last_used_at < 90d` → архив. Без жёсткого удаления. |
|
||||
| 4 | **Персональные данные / секреты.** Можем сохранить API-ключ из разговора. | Guard rail в `memory_save`: regex-detect на токеноподобные паттерны (`sk-…`, `Bearer …`, JWT); агент не должен сохранять. Финальный review — пользователь. Шифрование at-rest — отдельная тема (см. общий security pass). |
|
||||
| 5 | **Когда НЕ писать.** Review должен решить «не сохранять». | Встроено в промпт выше. Если агент сомневается — не пишет. |
|
||||
| 6 | **Каталог и формат SKILL-аналога для памяти.** Hermes делает это как `USER.md` vs `MEMORY.md`. У нас одна таблица с `category`. Нужно ли разделение? | Одной таблицы достаточно (категория в строке). Преимущество: один запрос, одна транзакция. |
|
||||
| 7 | **Привязка к conversation_id.** Глобальная память vs per-conversation. | Колонка nullable. По умолчанию глобальная (`NULL`). Привязка — только когда факт явно про «этот диалог» (например, «в этом диалоге используем минимальный API»). |
|
||||
| 8 | **Prefetch size.** Сколько фактов впрыскивать в user message? | Default 10, настраивается `AGENTIK_MEMORY_PREFETCH_TOPK`. |
|
||||
| 9 | **Где считать query embedding — клиент или «агент»?** | На стороне агента (там же, где `LiteLlm`). Один HTTP-вызов на turn. |
|
||||
| 10 | **Что делать с дубликатами?** «Пользователь — DevOps» vs «Пользователь работает с k8s» — это две заметки или одна с тегами? | v1: две отдельные заметки. Curator (Фаза 4) объединяет похожие через LLM. |
|
||||
|
||||
## 8. Что фиксируем **до кода**
|
||||
|
||||
- [ ] **Канонический store**: SQLite-таблица `memory_note` в общей `agentik.db`.
|
||||
- [ ] **Поиск**: семантический (embedding) + recency/use_count rerank.
|
||||
- [ ] **Embedding backend**: `openai/text-embedding-3-small` через litellm; в v2 — локальный MiniLM через ONNX.
|
||||
- [ ] **Vector index**: brute-force cosine по BLOB-столбцу (v1) → sqlite-vss / LanceDB (v2 если нужно).
|
||||
- [ ] **Single-binary**: всё в нашем процессе, без внешних сервисов.
|
||||
- [ ] **Prefetch**: топ-K (default 10) заметок в user-message-префиксе.
|
||||
- [ ] **Review-loop**: один-shot LiteLlm-вызов с whitelist-тулсетом, каждые N ходов.
|
||||
- [ ] **Curator** (отложен в Фазу 4): архивация по `use_count` + `last_used_at`.
|
||||
|
||||
## 9. Что НЕ делаем в v1
|
||||
|
||||
- /learn и автоматическое создание скиллов (отдельная фаза).
|
||||
- Vector compression / quantization (нужно только при >100K заметок).
|
||||
- Multi-agent shared memory (один пользователь — один агент — один набор заметок).
|
||||
- Encryption at rest (общий security pass).
|
||||
- Embedding-кэш для текстов, которые уже были заэмбеджены (можно LRU в RAM).
|
||||
- Memory.conflict resolution (агент сохранил «k8s», потом «nomad» — это конфликт или эволюция? v1 не разрешает, v2 — curator).
|
||||
|
||||
## 10. Пофазный план
|
||||
|
||||
### Фаза 1 — Память (v2.1, ~600 строк кода + ~300 тестов)
|
||||
|
||||
**Цель:** агент запоминает между сессиями.
|
||||
|
||||
- `:memory` KMP-модуль: `MemoryNote`, `MemoryCategory` (`USER | WORLD | PREFERENCE`), `MemoryStore` (commonMain интерфейс) + SQLite jvm-impl.
|
||||
- Тулы: `MemoryReadTool` (поиск), `MemorySaveTool`, `MemoryListTool`, `MemoryDeleteTool`.
|
||||
- `MemoryPrefetcher.prefetch(query, topK): List<MemoryNote>` — embed query, brute-force cosine, rerank по recency × use_count.
|
||||
- `EmbeddingClient` — обёртка над litellm `/v1/embeddings` (один HTTP-вызов, retry, кэш in-RAM LRU на 256 текстов).
|
||||
- `ChatAgent.memory: MemoryStore` + `EmbeddingClient` параметры.
|
||||
- `ChatConversation.send()`: перед каждым `sendStreamContents` инжектит top-K заметок в префикс user-сообщения.
|
||||
- `ChatAgent.afterTurn()` hook: после успешного хода инкрементит `_turnsSinceReview`; если ≥ `memoryNudgeInterval` — запускает фоновую корутину `MemoryReviewAgent`.
|
||||
- `MemoryReviewAgent`: один-shot `LiteLlm.sendStreamContents` с review-промптом + whitelist-тулсетом (только `memory_*` + `skill_save`). Результат — 0+ записей в `memory_note`.
|
||||
- `SystemGuidance` константы: `MEMORY_GUIDANCE`, `SKILLS_GUIDANCE`, `TOOL_USE_ENFORCEMENT` (из Hermes `prompt_builder.py`).
|
||||
- Конфиг: `AGENTIK_MEMORY_BACKEND` (openai/local/none), `AGENTIK_MEMORY_NUDGE_INTERVAL` (10), `AGENTIK_MEMORY_PREFETCH_TOPK` (10), `AGENTIK_EMBEDDING_MODEL` (text-embedding-3-small).
|
||||
- **Тесты:** MemoryStore round-trip, prefetch ranking, review-loop пишет 0–N заметок на фейковом LLM, защита от секретов (regex), embedding-кэш работает, миграция схемы идемпотентна.
|
||||
|
||||
### Фаза 2 — Контекстная компрессия (v2.2, ~500 строк)
|
||||
|
||||
**Цель:** диалог переживает 50+ ходов без 400 от LLM.
|
||||
|
||||
- `TokenEstimator` — грубая оценка (chars / 4) по working memory.
|
||||
- `Compressor.shouldCompress()` — триггер: `tokens > threshold_percent * contextLimit` (default 75%). Anti-thrashing: ≤5 неудачных попыток подряд → пауза 10 минут.
|
||||
- `WorkingMemoryStore.compact(dropFromOrderIdx, summaryEntry: MessageRecord.Summary)` расширяется: drop + insert в одной транзакции. Уже сигнатура, нужно тело.
|
||||
- `ChatConversation.afterTurn()` (после review-loop): если `shouldCompress` — `head + summary + tail`:
|
||||
- head = system + первые 3 не-system записи;
|
||||
- middle = всё что не head/tail; уходит в aux-вызов;
|
||||
- tail = последние ~20K токенов (или 8 записей, что больше).
|
||||
- Aux summarizer prompt — портированный из Hermes `context_compressor.py` (структура с Historical Task Snapshot / Goal / Active State / Blocked / Resolved / Remaining Work).
|
||||
- Резюме пишется как `MessageRecord.Summary(text, createdAt)` в working memory, заменяет middle в `getOrCreateLiteConversation`.
|
||||
- **Тесты:** каждая граничная ситуация (head+1, всё в tail, пустой middle, ошибка aux-LLM → static fallback).
|
||||
|
||||
### Фаза 3 — Skill self-improvement (v2.3, ~400 строк)
|
||||
|
||||
**Цель:** агент сам создаёт/обновляет скиллы.
|
||||
|
||||
- `SkillSaveTool(action=create|update, name, description, body)` (LiteTool).
|
||||
- Расширить `SkillCatalog` в `:skills`: `lastUsedAt`, `useCount`, `archivedAt`. Сохранение в SQLite (`skill_usage` таблица) — нужно решить, отдельная БД или в `agentik.db`. Рекомендую в `agentik.db` (та же причина, что и для memory).
|
||||
- `SkillLoader.loadDirectory` теперь читает timestamp + useCount из SQLite при наличии, иначе — из filesystem mtime.
|
||||
- `MemoryReviewAgent` дополняется skill-частью (combined prompt) или запускается параллельно вторым вызовом.
|
||||
- Тулы в whitelist review: `memory_*` + `skill_save` + `skill_delete`.
|
||||
|
||||
### Фаза 4 — Curator (v2.4, ~300 строк)
|
||||
|
||||
**Цель:** фоновая уборка устаревших заметок и скиллов.
|
||||
|
||||
- Корутина `CuratorJob` запускается в `Main.kt`, тик раз в сутки (настраивается).
|
||||
- **Без LLM:** сканирует `memory_note` и `skills`. Если `last_used_at < 90d` и `use_count == 0` → `archivedAt = now()`. Не удалять.
|
||||
- **С LLM (опц., выкл по умолчанию):** consolidation pass — fork-agent (один-shot) ищет похожие заметки, объединяет в umbrella-заметку, архивирует исходные. Для скиллов — то же самое.
|
||||
- Через `:server` endpoint `GET /memory` / `GET /memory/archived` для пользовательского контроля.
|
||||
|
||||
### Фаза 5 — Умный prefetch (v2.5, отложено)
|
||||
|
||||
- Переход brute-force → sqlite-vss при >50K заметок.
|
||||
- Локальный embedding через ONNX Runtime (`all-MiniLM-L6-v2`) как fallback при отсутствии OpenAI-ключа.
|
||||
- Embedding-кэш на диске (LRU).
|
||||
- Vector quantization (int8) для экономии RAM.
|
||||
|
||||
## 11. Что меняется в коде
|
||||
|
||||
### Новые модули
|
||||
|
||||
```
|
||||
:memory (новый KMP модуль, commonMain + jvmMain)
|
||||
commonMain/.../MemoryNote.kt -- sealed: id, category, content, ...
|
||||
commonMain/.../MemoryCategory.kt -- USER | WORLD | PREFERENCE
|
||||
commonMain/.../MemoryStore.kt -- интерфейс (insert, list, search, delete)
|
||||
commonMain/.../EmbeddingClient.kt -- интерфейс (embed: String -> FloatArray)
|
||||
commonTest/.../MemoryStoreTest.kt
|
||||
jvmMain/.../sqlite/SqliteMemoryStore.kt -- INSERT/SELECT + brute-force cosine
|
||||
jvmMain/.../embedding/LitertlmEmbedding.kt -- HTTP-вызов /v1/embeddings через ktor-client
|
||||
jvmMain/.../embedding/InMemoryEmbedding.kt -- для тестов
|
||||
jvmTest/.../SqliteMemoryStoreTest.kt
|
||||
jvmTest/.../LitertlmEmbeddingTest.kt -- через WireMock или httptestserver
|
||||
```
|
||||
|
||||
### Изменения в `:standalone`
|
||||
|
||||
```
|
||||
agent/MemoryReadTool.kt / MemorySaveTool.kt / MemoryListTool.kt / MemoryDeleteTool.kt
|
||||
agent/MemoryReviewAgent.kt -- один-shot review, fire-and-forget coroutine
|
||||
agent/SkillSaveTool.kt -- в Фазе 3
|
||||
llm/SystemGuidance.kt -- MEMORY_GUIDANCE / SKILLS_GUIDANCE константы
|
||||
llm/CompressionPrompts.kt -- в Фазе 2
|
||||
persistence/WorkingMemoryStore.kt -- расширение compact() в Фазе 2
|
||||
agent/ChatAgent.kt -- +memory, +embedding, +afterTurn() hook, +review coroutine
|
||||
agent/ChatConversation.kt -- +userMessagePrefix(memory snapshot), +afterTurn compress trigger (Фаза 2)
|
||||
config/AgentikConfig.kt -- +memory config block
|
||||
Main.kt -- +memory init, +curator coroutine (Фаза 4)
|
||||
```
|
||||
|
||||
### Изменения в `:proto`
|
||||
|
||||
Не нужны. Память — внутренняя фича standalone, не часть протокола. (Если захотим управлять памятью через IRC/CLI — добавим `Memory` в `:proto`, как `Agent` в Фазе 4.)
|
||||
|
||||
### Изменения в `:server` / `:client`
|
||||
|
||||
Не нужны. Память не идёт через HTTP API в v1. (Только чтение дампа `GET /memory` — это Фаза 4.)
|
||||
|
||||
## 12. Чеклист перед кодом
|
||||
|
||||
- [ ] Подтвердить: канонический store в `agentik.db` (а не отдельный файл).
|
||||
- [ ] Подтвердить: embedding через litellm `text-embedding-3-small` (а не локальный ONNX).
|
||||
- [ ] Подтвердить: brute-force cosine в BLOB (а не sqlite-vss / LanceDB на старте).
|
||||
- [ ] Подтвердить: review-loop как один-shot, не полноценный fork-agent.
|
||||
- [ ] Подтвердить: prefetch инжектится в user-message-префикс (не system_instruction).
|
||||
- [ ] Подтвердить: `MemoryNote.conversation_id` nullable, по умолчанию NULL (глобальная).
|
||||
- [ ] Ответить на вопросы 1–10 из раздела 7.
|
||||
|
||||
После закрытия чеклиста — открываем Фазу 1.
|
||||
Reference in New Issue
Block a user