# Как работает Code Memory Code Memory (CM) — локальная память кода для агентов. Перед первым шагом агента она кладёт в переписку нужный исходник: найденные функции, их зависимости, короткие файлы целиком и места вызова. Агенту не нужно искать код через `glob`, `grep` и `read`, поэтому он делает меньше вызовов модели и платит меньше токенов. Замеры — в [EFFICIENCY-AB.md](EFFICIENCY-AB.md), прошлые подходы и их неудачи — в [HISTORY.md](HISTORY.md). Документ описывает текущее поведение в DeepSeek Harness с настройками по умолчанию: `retrievalPolicy: adaptive`, `searchMode: exact`, `autoContext: true`, `autoUpdate: true`, бюджет исходника 6 000 байт. ## Откуда берётся экономия Агент работает циклом «вызов модели → инструмент → вызов модели». В каждом вызове модели заново отправляется вся переписка, поэтому **токены сессии ≈ число вызовов модели × размер переписки.** Без CM агент тратит вызовы на поиск: найти файл, прочитать, проверить, где вызывается функция. Каждый такой шаг — целый вызов, а каждый прочитанный файл повторяется во всех следующих вызовах. CM отдаёт нужный код заранее и сверяет его с диском, поэтому модель правит с первого шага. На шести задачах Geo Dash в трёх сериях по 36 сессий: 0 вызовов `read/grep/glob` с CM против 34–37 без него, токенов на 45–66% меньше, качество не ниже. Расход в кеше провайдера смещается соответственно: доля прочитанного из кеша снижается (меньше повторных вызовов), а абсолютные чтение, запись и выход уменьшаются. Цена падает слабее токенов, потому что убираются в основном дешёвые чтения из кеша. ## Что хранит CM | Слой | Что внутри | Откуда | |---|---|---| | Исходник | Точные байты каждого файла и его SHA-256; фрагменты ссылаются на `blob:` | Сохранённые файлы проекта | | Записи (units) | Файлы, функции, методы, типы, блоки с точными диапазонами байтов и строк | TypeScript compiler API | | Глоссарий символов | Имена, вид, место объявления, владелец | TypeScript compiler API | | Граф связей | `calls`, `contains` и другие связи с диапазоном-доказательством в исходнике | TypeScript compiler API | | Векторы | Эмбеддинг каждой записи: MiniLM-L6-v2, q8, 384 измерения | ONNX Runtime на CPU, база LanceDB | Всё хранится локально в `.code-memory/`; код уходит только в саму LLM. Индексируются JavaScript и TypeScript. Для Geo Dash: 224 файла, 16 465 записей, 29 186 символов, 130 773 связей, 7 503 вектора. ## Путь одного запроса ### 1. Очистка запроса Plugin берёт текст задачи из сообщений пользователя. `focusQuery` ([focus.ts](../src/code-memory/focus.ts)) убирает предложения, где не меньше 80% слов — общая лексика процесса агента (apply, workspace, preserve, interfaces, checks, summary…). Предложение остаётся всегда, если в нём есть `` `имя` ``, путь вида `file.js` или camelCase-идентификатор. Если убрать пришлось бы всё, используется исходный текст. ### 2. Выбор маршрута | Маршрут | Когда | Что делает | Индекс | Векторы | |---|---|---|---|---| | Текущий файл | Назван ровно один файл ≤ 6 000 байт без import/require/re-export | Читает его целиком прямо с диска ([direct.ts](../src/code-memory/direct.ts)) | Нет | Нет | | Именованный | Названы функции, типы или путь, и они есть в глоссарии | Точный якорь + ограниченное замыкание зависимостей по графу | Да | Нет | | Поиск места | Имён нет или они не найдены | Слова + векторы + граф | Да | Да | Для «поиска места» ([graph_retrieve.ts](../src/code-memory/graph_retrieve.ts)): - **слова (IDF):** редкое слово весит больше, совпадение с именем функции — втрое, `vendor/` и `generated/` ослаблены, длинные функции слегка штрафуются; берутся 32 лучших; - **векторы:** запрос кодируется той же MiniLM, берутся 24 ближайших по косинусу из всех векторов (`exact`); - **граф:** кандидат получает небольшую прибавку, если его соседи по вызовам тоже нашлись. Ранги складываются взвешенно; берутся до двух функций с оценкой не ниже 82% от лучшей. ### 3. Сборка контекста 1. Найденные функции целиком. 2. Их зависимости по графу: объявления до 1 200 байт, одна ступень, до 12 узлов. Большие — только первой строкой с пометкой о пропуске. 3. Короткие файлы (≤ 3 000 байт) — целиком, с пометкой `(whole file)`, если помещаются в бюджет. 4. Места вызова найденных функций из связей `calls`, включая вызовы на уровне модуля: `Call sites of creditAdReward: game/src/platform/rewarded-flow.js:34.` Если вызовов нет — так и написано. 5. Честная концовка: либо «ничего из нужных определений не пропущено», либо сколько пропущено. ### 4. Проверка версий Каждый файл из контекста перечитывается через файловую систему Harness, его хеш должен совпасть с индексом. Совпавший файл регистрируется как прочитанный (`fs/observed`): модель может сразу править без `read`. ### 5. Свежесть Перед каждым запросом через индекс CM сверяет хеши файлов. Если что-то изменилось, индекс и векторы пересобираются (неизменённые эмбеддинги берутся из кеша) и публикуются атомарно ([live.ts](../src/code-memory/live.ts)). Маршрут «текущий файл» всегда читает свежие байты. ## Что происходит дальше в сессии - **Инструкция в системном промпте:** файлы `(whole file)` полные, места вызова уже даны; правку в одном-двух местах делать сразу, но сначала продумать поведение, которое нужно сохранить (граничные случаи, порядок, ничьи, форма результата). - **`cm_retrieve_context`** доступен модели для дозапроса; `detail: expanded` — до 4 корней, две ступени, 24 узла. - **Повторное чтение не дублирует файл.** Если модель вызывает `read` для файла, который CM уже показал целиком и который не изменился, первый такой `read` получает короткую ссылку на контекст выше. Это хук Harness `tools/post-execute`; прошлые сообщения не переписываются, кеш провайдера не ломается. ## Скорость старта Каждая сессия — новый процесс. Импорт плагина ~0,18 с: TypeScript загружается только при пересборке индекса, разборе блоков или маршруте «текущий файл» ([ts.ts](../src/code-memory/ts.ts)). Загрузка индекса Geo Dash (JSON 92 МБ) ~0,85 с: строгая проверка UTF-8 через `TextDecoder`, полная проверка схемы и связей один раз — её результат запоминается отметкой `index.json.verified.json` по SHA-256 байтов и версии проверяющего кода. Выбор контекста ~0,2 с; векторный запрос добавляет загрузку MiniLM и LanceDB. ## exact и HNSW Оба режима — векторный поиск по одним эмбеддингам. `exact` (по умолчанию) считает косинус со всеми векторами — гарантированно ближайшие, миллисекунды на 7 503 векторах. `ann` (HNSW) обходит граф соседей: на Geo Dash векторная часть быстрее в 3,1–3,4 раза при recall около 99,6–100%, но в сессиях агента выигрыша не дал. Включается `searchMode: "ann"` и `npm run cm:ann`. ## Кеш провайдера Harness по умолчанию передаёт OpenAI ID сессии как `prompt_cache_key`, а последняя строка его системного промпта — рабочая папка; из-за этого новая сессия не берёт из кеша даже одинаковое начало промпта. Установщик и `start_harness.ps1` задают провайдеру `cacheRetention: "none"`: без ключа вторая сессия в той же папке прочитала из кеша 2 690 из 2 693 токенов первого вызова ([проверка](../evaluation/efficiency/cache-probe.json)). Это настройка Harness, а не CM. ## Клиенты | Клиент | Как подключается CM | Автоматический контекст | Токены к без CM | |---|---|---|---:| | DeepSeek Harness | Plugin ([plugin.ts](../src/harness/plugin.ts)) | Перед первым шагом | −45…−66% | | Codex | Хук `UserPromptSubmit` ([hooks/cli.ts](../src/hooks/cli.ts)) + MCP | Перед первым вызовом | −42% | | Claude Code | Хук `UserPromptSubmit` + MCP | Перед первым вызовом | −30% | Один MCP-сервер без хука экономии не даёт: модель его почти не вызывает. Подробно — [NATIVE-CLIENTS.md](NATIVE-CLIENTS.md). ## Компоненты кода | Путь | Что делает | |---|---| | `src/code-memory/indexer.ts` | Строит индекс через TypeScript compiler API | | `src/code-memory/store.ts` | Загружает и проверяет индекс, сверяет исходники | | `src/code-memory/vector.ts`, `minilm.ts` | Эмбеддинги и векторный поиск | | `src/code-memory/graph_retrieve.ts`, `knowledge.ts` | Маршруты, ранжирование, граф, места вызова | | `src/code-memory/direct.ts` | Маршрут «текущий файл» | | `src/code-memory/focus.ts` | Очистка запроса | | `src/code-memory/retrieve.ts` | Общий вход и формат контекста | | `src/code-memory/live.ts` | Автообновление индекса | | `src/harness/plugin.ts` | Plugin Harness: авто-контекст, инструмент, инструкция, повторное чтение | | `src/mcp/` | MCP-сервер для Codex и Claude Code | | `src/hooks/` | Хук `UserPromptSubmit`: авто-контекст в Codex и Claude Code | | `src/local-agent/`, `apps/local-viewer/` | Локальная служба и карта CM Atlas ([LOCAL-ATLAS.md](LOCAL-ATLAS.md)) | | `src/setup/` | Установщик для Harness, Codex и Claude Code ([INSTALL.md](INSTALL.md)) | ## Ограничения - Только JavaScript и TypeScript; динамические вызовы граф не видит. - Индекс большой (92 МБ JSON на 3,6 МБ исходника) и загружается в каждой сессии. - Экономия измерена на одном проекте и шести задачах; в Codex и Claude Code — по одной серии.