docs: per-module READMEs (run vs library) + root navigation hub
ci / JVM build + tests (pull_request) Failing after 54s

Every subproject now has README.md:
- 3 runnable modules (:standalone, :agentik-cli, :agentik-tui):
  quickstart, env table, parameters, known limits
- 11 library modules: what it is, which problem solves, how to
  wire it in, where versions live

Root README.md is the navigation hub (Quickstart, Modules table,
publish + CI/CD notes).

Also: ci.yml prunes the :memory-vector -x excludes now that
text-embedding-kmp artifacts are published to caffeine.

518 tests green.

Verified publish pipeline: :proto:publish to caffeine produces
pom.module + per-target klibs + sources for all 9 KMP targets.

🤖 Generated with [opencode]
This commit is contained in:
SubochevAV
2026-09-16 20:44:16 +03:00
parent 5ad972767d
commit 8f616f359f
22 changed files with 1125 additions and 890 deletions
+57 -51
View File
@@ -1,72 +1,78 @@
# :memory-vector — `pw.binom.agentik.memory.vector`
# `:memory-vector` — ANN/JVector/SQLite память с эмбеддингами (JVM-only)
**Реализация долговременной памяти поверх JVector (ANN-индекс) + SQLite (метаданные) + эмбеддингов.**
JVM-only (JVector не публикует KMP-таргеты; на Android ART работает через Java 11
scalar fallback).
## Что это
## Какую проблему решает
Реализация `MemoryStore` поверх SQLite + [JVector](https://github.com/jbellis/jvector)
+ LLM-эмбеддинги:
`:memory-md` хорош для малых объёмов и дев-окружения, но при тысячах заметок
keyword-overlap поиск не справляется. Vector-бэкенд считает **эмбеддинги**
заметок, складывает в JVector ANN-индекс, ищет по cosine similarity.
`recency-re-rank` подмешивает свежесть, чтобы новые факты не тонули в старых.
- **Хранение метаданных** — SQLite (notes, timestamps, источник).
- **ANN-индекс** — JVector (тот же класс HNSW, что используется в
Cassandra DataStax).
- **Эмбеддинги** — два backendа:
- **HTTP** — POST на любой OpenAI-совместимый `/v1/embeddings`
(vLLM, LiteLLM, text-embedding-ada-002, и т.д.).
- **SigLIP2** — локальная модель через [text-embedding-kmp](https://git.binom.pw/subochev/text-embedding-kmp)
(ONNX Runtime, без сети).
## Архитектура
Решает: семантический поиск по памяти. "Где я рассказывал про
CI/CD" находит нужный эпизод, даже если формулировка другая. При
этом offline-capable через SigLIP.
```
┌───────────────────────┐
user-query ─►│ EmbeddingProvider │ (HTTP /v1/embeddings или SIGLIP2 on-device)
└─────────┬─────────────┘
▼
┌───────────────────────┐
│ MemoryVectorStore │
│ ├─ JVector (cosine) │ ◄── ANN-search
│ └─ SQLite (мета) │ ◄── заметки + lastUsedAt + useCount
└───────────────────────┘
```
## Где используется
Бэкенды эмбеддингов (через `AGENTIK_EMBEDDING_BACKEND`):
- `:standalone` подключает как `AGENTIK_MEMORY_BACKEND=vector`
(с `AGENTIK_EMBEDDING_BACKEND=http|siglip`).
- **`HTTP`** — POST на `${OPENAI_BASE_URL}/v1/embeddings`. Семантический поиск
через OpenAI-совместимый endpoint (vLLM, OpenAI, LiteLLM-proxy).
Кэширование LRU(256) на уровне `EmbeddingHttpProvider` для дедупликации.
- **`SIGLIP`** — on-device SigLIP2 через ONNX Runtime (768-мерный вектор).
Никаких внешних вызовов; модель и токенизатор должны лежать на диске.
## Подключение
## Как подключить
```kotlin
plugins { kotlin("jvm") }
dependencies {
implementation("pw.binom.agentik:memory-vector:$version")
// Транзитивно: :memory-api + jvector + sqldelight + text-embedding-kmp
implementation("pw.binom.agentik:memory-vector:0.1.0")
implementation("pw.binom.agentik:memory-api:0.1.0")
}
val memory = VectorMemorySystem.open(
dbPath = Path("~/.agentik/mem.db"),
embedding = HttpEmbeddingClient(
apiUrl = "http://192.168.88.135:8001/v1",
apiKey = "no-key-needed",
model = "text-embedding-3-small",
dimension = 1536,
),
)
```
`:standalone` инициализирует бэкенд автоматически по `AGENTIK_MEMORY_BACKEND=vector`
+ `AGENTIK_EMBEDDING_BACKEND=…`.
## Версии
## Размерности
`gradle/libs.versions.toml` → `[versions] agentik-memory-vector`.
| Backend | Модель | Dim |
|---|---|---|
| `HTTP` (OpenAI) | `text-embedding-3-small` (default) | 1536 |
| `HTTP` (OpenAI) | `text-embedding-3-large` | 3072 |
| `SIGLIP` | SigLIP2-base | 768 (фиксировано) |
**Зависит от** `pw.binom.ai.embeddingtext:api-jvm:3.0.0-SNAPSHOT`
и `pw.binom.ai.embeddingtext:siglip-jvm:3.0.0-SNAPSHOT` из репо
`caffeine` (см. `../gradle/libs.versions.toml`). Оба опубликованы
вручную (`Binom-PIN-Caffeine`).
Для `HTTP` размерность управляется через `AGENTIK_EMBEDDING_DIMENSION`; для
`SIGLIP` — определяется автоматически.
## Как работает embedding-флоу
## Где смотреть версии
1. `memory.save(cat, "text")` — text → embedding (HTTP или SigLIP)
→ row в SQLite + вектор в JVector-индекс.
2. `memory.query(cat, "q")` — q → embedding → ANN top-K (default K=10)
→ скоры, deduplication, реплес с timestamp.
- `version` из `gradle.properties` (`version=0.1.0`)
- релизы: `https://git.binom.pw/subochev/agentik/releases`
## Тесты
## Сборка
```bash
./gradlew :memory-vector:build
```
./gradlew :memory-vector:jvmTest
```
JVM-only. Тянет `pw.binom.agentik:memory-api` и `com.github.jvector:jvector:3.0.6`.
Покрывают: round-trip, ANN top-K, SigLIP (если модель скачана),
SQLite-migration. SigLIP-тест skipped без модели на диске.
## Чего здесь НЕТ
- Никакого HTTP-клиента к LLM для генерации ответов. Это только
embedding-клиент. Сам LLM-вызов — в `:standalone`.
## Текущий статус
Используется продакшеном. Подходит для крупных памятей (10000+
заметок) и семантических запросов.