Hindsight должен был обработать большой архив из Cursor: рабочие чаты, планы и принятые решения. Для извлечения фактов ему нужны запросы к языковой модели.
До этого запросы уходили через внешний роутер. Работало, но добавляло отдельную оплату и ещё одну зависимость. При этом доступ к Codex у меня уже был через OAuth и подписку — отдельного ключа официального OpenAI API не было.
Поэтому задача выглядела так: дать Hindsight привычный OpenAI API, а авторизацию через Codex оставить внутри собственного контура.
Сразу обозначу границу результата. Собственная точка входа заработала, Hindsight умеет к ней подключаться, а доступ без учётных данных закрывается. Но чистого сравнения скорости и качества с внешним роутером пока нет. Переводить на неё весь импорт без такого сравнения я не стал.
Что требовалось от API#
Hindsight не нужен полный набор OpenAI API. Для текущего контура хватало трёх маршрутов:
GET /health
GET /v1/models
POST /v1/chat/completions
Требования были конкретными:
- доступ по Bearer-токену;
- ответ
/v1/modelsв привычном формате; - выбор модели по умолчанию;
- обычная и потоковая выдача ответа;
- отсутствие передачи клиентских учётных данных дальше, в Codex;
- запуск как отдельного сервиса и понятное поведение после перезапуска.
Последний пункт оказался не менее важен, чем сам HTTP-ответ. Рабочий слой должен переживать отказ, повторный запуск и ошибки соседних компонентов.
Схема исходного контура была простой:
Первый вариант: отдельный прокси#
Сначала мы собрали простой отдельный прокси. Он должен был взять доступный в Hermes Codex OAuth, спрятать его за HTTP-слоем и отдать Hindsight обычный base_url с Bearer-авторизацией.
Для проверки гипотезы этого хватало. Для постоянного контура появлялись дополнительные обязанности: отдельно запускать и обновлять процесс, хранить учётные данные, ограничивать доступ, обрабатывать ошибки и следить за совместимостью с разными форматами запросов.
Если тот же маршрут можно было встроить в Hermes, отдельный процесс становился лишним звеном.
Что нашли в Hermes и вокруг него#
В документации Hermes были описаны две нужные части:
- локальный HTTP-сервер для внешних клиентов, использующий подписку провайдера;
- провайдер
openai-codex, который получает доступ через ChatGPT OAuth или код устройства и хранит учётные данные в хранилище Hermes.
Но из этого ещё не следовало, что openai-codex можно без доработок использовать внутри hermes proxy. Это пришлось проверять по исходникам, PR, командной строке и локальным тестам.
Полезными оказались три PR в репозитории Hermes:
- PR #54877 переиспользовал пул Codex-учётных данных и переводил Chat Completions в Responses. В ходе ревью нашли потерю
toolsиtool_choice, проблемы с текстовыми ответами без потоковой выдачи и расхождения между документацией и--help. - PR #62297 добавлял пул Codex OAuth. Отдельно проверялись логирование источника клиента, права на файл учётных данных и документация. В тестах было
49 passed. - PR #62510 добавлял аутентифицированный верхний сервис Codex. В нём проверялись обновление через пул, права
0600, тип файла и границы передачи заголовков.
Из этих изменений следовало несколько ограничений:
- OAuth-токен нельзя просто передать наружу;
- Bearer-токен клиента нельзя отправлять в Codex;
- совместимость с Responses API и вызовами инструментов требует отдельных тестов;
- обновление учётных данных должно проходить через их пул, а не через случайное чтение файла.
Параллельно мы посмотрели несколько самостоятельных реализаций: mehdic/codex-proxy, dvcrn/codex-oauth-proxy, Securiteru/codex-openai-proxy, EvanZhouDev/openai-oauth, icebear0828/codex-proxy и David-Factor/codex-responses-proxy.
Они подтвердили, что задача повторяется в разных проектах, но готовый прокси нельзя выбирать только по наличию HTTP-маршрута. Нужно отдельно проверять схему авторизации, потоковую выдачу, Responses API, вызовы инструментов, повторные попытки и хранение учётных данных.
В итоге мы выбрали нативный путь: провайдер openai-codex внутри hermes proxy, а внешний интерфейс для Hindsight оставили совместимым с API OpenAI. Локальная реализация опиралась на ветку native-codex-single, основанную на PR #54877 и изменённую после ревью.
Токен не передавался через аргументы командной строки или переменные процесса. Доступ хранился в файле, а проверка выполнялась без вывода самого значения.
Проверка HTTP-слоя#
Сначала проверили, что сервис закрывает доступ без учётных данных:
/health → 401
/v1/models → 401
С авторизацией из защищённого файла получили:
/health → 200
/v1/models → 200
/v1/models возвращал JSON в формате OpenAI. Моделью по умолчанию была gpt-5.5.
Затем отправили настоящий запрос:
POST /v1/chat/completions
Запрос прошёл. После этого отдельно проверили stream=true. Обычный JSON-ответ ещё не подтверждает совместимость с клиентом: агентские инструменты часто ждут потоковую выдачу и обрабатывают её по частям.
К моменту перехода на нативный путь проверили:
/v1/modelsвозвращает ожидаемый формат;/v1/chat/completionsотвечает200;- потоковая выдача работает;
- Bearer-токен принимается на внешней точке входа;
- клиентский заголовок авторизации не передаётся в Codex;
- проверки Hermes завершились результатом
49 passed.
Это уже был сервис, к которому можно подключать другой компонент, а не скрипт, отвечающий только на /health.
Зачем здесь Hindsight#
Hindsight должен был разобрать экспорт из Cursor. Сырой архив для импорта не годился: в нём были рабочие разговоры, планы, служебные файлы, MCP, инструменты, навыки, изображения и кэши.
Перед импортом мы отфильтровали корпус, оставили полезные чаты и планы, добавили очистку чувствительных данных и проверили шаблоны секретов. После этого собрали пакет JSONL:
полезных документов: 4 594
фрагментов Hindsight: 7 271
размер пакета: около 192 МБ
Импорт сделали возобновляемым. Отдельный файл состояния хранит последний индекс, поэтому после остановки процесс продолжает работу с сохранённой позиции.
Секреты не передавались через argv:
argv secret leaks = 0
Внешняя языковая модель нужна Hindsight только для retain и извлечения фактов. Векторные представления и повторная сортировка результатов работают локально:
embeddings: BAAI/bge-m3
reranker: BAAI/bge-reranker-v2-m3
Поэтому прокси не обязан реализовывать /v1/embeddings. Для этого контура достаточно chat completions.
Почему внешний роутер пока не списан#
До эксперимента Hindsight ходил через внешний совместимый с API OpenAI роутер с моделью openai/gpt-5.6-luna.
Для retain важны не только цена и скорость. Модель должна извлекать факты, сохранять предсказуемую структуру ответа и не наполнять память лишними записями. На выбранном роутере openai/gpt-5.6-luna соответствовала этим требованиям. Опубликованный тариф составлял 101 ₽ за 1 млн входных токенов и 608 ₽ за 1 млн выходных.
Зафиксированный импорт GBrain израсходовал:
входные токены: 1 644 544
выходные токены: 460 421
стоимость: около 446 ₽
Полный импорт из Cursor тогда не обсчитывали: в журналах сохранилось число фрагментов, но не суммарный расход токенов.
Сначала retain выполнялся с одним параллельным запросом. Затем проверили два:
HINDSIGHT_API_LLM_MAX_CONCURRENT=4
HINDSIGHT_API_RETAIN_LLM_MAX_CONCURRENT=2
HINDSIGHT_API_CONSOLIDATION_LLM_MAX_CONCURRENT=1
BATCH_SIZE=2
На участке 154 → 168 получили:
14 фрагментов / 423,7 секунды ≈ 1,98 фрагмента/мин
До этого скорость составляла примерно 1,0–1,1 фрагмента/мин. В журналах не было 429, 5xx или тайм-аутов, Hindsight оставался в состоянии healthy, а пакеты возвращали status=200.
Повышать параллельность до 3 или 4 сразу не стали. Для памяти важнее качество извлечения, стабильность схемы и отсутствие тихих потерь, чем одна удачная цифра пропускной способности.
Пробный запуск через собственную точку входа#
На основной импорт новый маршрут не включали. Для проверки создали отдельный canary-bank, чтобы не смешивать эксперимент с основной памятью и не ломать возобновляемый импорт.
Временно установили такую конфигурацию:
HINDSIGHT_API_LLM_BASE_URL=https://your-openai-compatible-endpoint.example/v1
HINDSIGHT_API_LLM_MODEL=gpt-5.5
HINDSIGHT_API_RETAIN_LLM_MAX_CONCURRENT=1
Первая ошибка оказалась не в API. PostgreSQL внутри Docker упёрся в стандартный размер /dev/shm — 64M:
could not resize shared memory segment
No space left on device
HTTP-слой был доступен, Hindsight до него доходил, но запись в память падала на уровне базы. Для PostgreSQL добавили:
shm_size: 1g
Пересоздали контейнеры и повторили проверку:
- Hindsight поднялся со статусом
healthy; - соединение с моделью прошло;
- запись в bank вернула
200; - пакет
retainна участке240 → 242вернул200.
Функциональная проверка прошла. Но короткий замер скорости показал:
2 фрагмента / 262,2 секунды ≈ 0,46 фрагмента/мин
Это хуже предыдущего участка через внешний роутер. Сравнение нельзя считать честным: параллельно выполнялась задача consolidation, которая влияла на время.
Поэтому эксперимент остановили. Основной конфиг Hindsight вернули на стабильный роутер, а импорт Cursor оставили на паузе с сохранённым состоянием.
Что доказано, а что нет#
Доказано#
- собственная точка входа, совместимая с API OpenAI, поверх Codex OAuth;
- ответ
401без учётных данных; - рабочие
/healthи/v1/models; - рабочий
chat/completions; - проверенная потоковая выдача;
- нативный
openai-codexв Hermes; - подключение Hindsight к собственной точке входа;
- изоляция эксперимента через
canary-bank; - исправление ошибки Docker/PostgreSQL с общей памятью;
- возобновляемый импорт после остановки;
- отсутствие передачи клиентского токена в Codex.
Пока не доказано#
- что собственная точка входа быстрее внешнего роутера на одинаковом чистом тесте;
- что качество фактов совпадает на длинной выборке;
- что новый маршрут нужно оставить постоянным именно для Hindsight;
- что
chat completionsхватит будущим клиентам; - что сейчас нужны
/v1/embeddings, Responses API и полный набор вызовов инструментов.
Рабочий 200 доказывает только успешный запрос. Он не доказывает скорость, качество памяти и готовность к длительной эксплуатации.
Следующий эксперимент#
Чтобы выбрать маршрут, нужен воспроизводимый тест:
- Продолжить импорт Cursor по сохранённым контрольным точкам.
- Взять одинаковые 10–20 фрагментов и одну модельную задачу.
- Убрать параллельный
consolidationи прочие факторы, влияющие на замер. - Сравнить внешний роутер и собственную точку входа по скорости, ответам
401/403/429/5xx, тайм-аутам и качеству извлечённых фактов. - После этого решить, какой маршрут оставить для Hindsight.
- Отдельно определить необходимый набор совместимости для будущих клиентов.
До такого сравнения внешний интерфейс можно считать рабочим, но постоянный маршрут — ещё нет.
Где проходит инженерная граница#
Свой API поверх Codex — это не отдельный продукт и не красивый адрес. Это слой между клиентом и авторизацией, который приходится сопровождать.
В нём есть:
- проверка доступа;
- потоковая выдача;
- выбор модели;
- запуск через systemd;
- тайм-ауты и ограничения скорости;
- хранение и обновление учётных данных;
- поведение Docker и PostgreSQL;
- состояние длительного импорта;
- восстановление после остановки.
Если слой должен работать постоянно, нужно заранее знать, что произойдёт при 401, 429, падении базы, остановке процесса и повторном запуске через несколько часов.
В нашем случае собственная точка входа уже работает, но решение о постоянной эксплуатации отложено до чистого сравнения. Для личной инфраструктуры этого достаточно: сначала проверяем границы, потом выбираем маршрут, затем расширяем совместимость.
Если вы строите совместимый с API OpenAI слой поверх Codex OAuth, подключаете Hermes Agent или Hindsight либо разбираете собственную ИИ-инфраструктуру, напишите мне в Telegram или на почту. Помогу проверить границы совместимости, хранение учётных данных и поведение системы при сбоях.



