* refactor(memory): rename package second-brain to memory * refactor(memory): use OpenAI env naming and fix trailing slash * feat(memory): add chunking with env-configurable size and overlap * feat(memory): dedup search results by source in top-K * test(memory): add chunking, batching, dedup, live tests * docs(memory): update README and project map after rename * docs(handoff): add handoff and ADR-032 for memory refactor * docs(handoff): set PR number * fix(ci): reduce index.py complexity to rank A --------- Co-authored-by: opencode-agent <agent@opencode.local>
4.2 KiB
4.2 KiB
ADR-032: Rename to memory, OpenAI env, chunking, batching, dedup (PR #75)
Статус
Accepted (2026-07-26)
Контекст
Python-пакет src/memory/ (RAG CLI для opencode-memory plugin) имел 7 проблем: нейминг-путаница (3 разных имени для одного пакета), нестандартный env-нейминг (AI_PROVIDER_API_URL ≠ AI_PROVIDER_BASE_URL из .env.example/opencode.json), реальная 404-бага из-за trailing slash, грубый индекс (1 эмбеддинг на файл без чанков), отсутствие batching (риск упереться в OpenAI лимит input), отсутствие дедупа в search (засорение top-K одним файлом), захардкоженная модель эмбеддингов.
PR #1 в серии из 2 — этот PR чинит CLI, PR #2 интегрирует CLI в плагин через setup-memory.sh.
Решение
- Нейминг:
pyproject.tomlname=second-brain→memory,[project.scripts] rag = "src.memory.cli:main"(script entry point, совместимость с wrapper).cli.pyprog="rag"→prog="memory". Модульsrc/memory/НЕ переименован (src-layout,packages=["src"]). - Env-нейминг OpenAI-стандарт:
OPENAI_BASE_URL/OPENAI_API_KEY(вместоAI_PROVIDER_API_URL/AI_PROVIDER_API_KEY).API_URL.rstrip("/")фиксит trailing-slash.EMBEDDING_MODELиз envOPENAI_EMBEDDING_MODEL(defaultgemini-embedding-2-preview). - Chunking:
_chunk_text(text, size, overlap)вindex.py, параметры из envMEMORY_CHUNK_SIZE(512)/MEMORY_CHUNK_OVERLAP(64).file_mapсchunk_idx/offset/text. Graceful приsize<=overlap(1 chunk, не infinite loop). - Batching:
BATCH_SIZE = int(os.environ.get("OPENAI_EMBEDDING_BATCH_SIZE", "2048"))вembedder.py.embed_textsрежет texts > BATCH_SIZE, конкатенирует результаты. Default 2048 = OpenAI лимит для text-embedding-3-small. - Дедуп:
search.pyпосле sort по score итерирует сseenset, оставляет highest score per source, останавливается на K уникальных source'ов. - Тесты:
test_chunking.py(7 edge cases),test_embedder_live.py(2 live, skip без RUN_LIVE), + 4 embedder теста (default/custom model, trailing slash, batches), + 3 index теста (long file, env override, .rag skip), + 1 search тест (dedup).
Альтернативы
- Полный rename
src/memory/→src/rag/— отклонено: src-layoutpackages=["src"]в pyproject, rename модуля требует обновления всех imports (cli, embedder, index, search, tests, main). Script entry pointrag = "src.memory.cli:main"даёт исполняемыйragбез rename модуля. Module namememory(что package делает) + script namerag(как пользователь вызывает) — разумное разделение. - Читать
OPENAI_BASE_URL/EMBEDDING_MODEL/BATCH_SIZEвembed_textsкаждый вызов (вместо module-level) — отклонено: лишний overhead на каждый вызов (env lookup + int parse), несовместимость с существующимAPI_URLmodule-level паттерном. Module-level +importlib.reloadв тестах — trade-off: простой код, хрупкие reload-тесты. - Дропать empty files из индекса (вместо 1 записи с пустым чанком) — отклонено: меняет существующее поведение (раньше empty files попадали в индекс с 1 embedding). Empty embedding даёт score 0, файл остаётся в index для completeness.
- Параметризовать
_chunk_textчерез argparse вместо env — отклонено: env-параметры позволяют настраивать без правки CLI invocation, совместимо с setup-memory.sh wrapper (env передаётся через process env, не флаги).