Перейти к содержимому

Интеграция с Codex

opencodex заставляет Codex работать через прокси, редактируя две вещи, которые читает Codex: его конфигурацию ($CODEX_HOME/config.toml, по умолчанию ~/.codex/config.toml) и каталог моделей. Каждая правка идемпотентна и обратима.

Прокси предоставляет один маршрут входа Codex openai без префикса с режимами аккаунтов Pool (по умолчанию) и Direct, а также openai-apikey/<model> для настроенного API-ключа. Pool включает основной и добавленные аккаунты; Direct использует только bearer вызывающего/основного аккаунта. Маршруты не откатываются друг на друга. Поставлявшиеся v1-конфигурации мигрируют на маркер 2 и сохраняют config.json.pre-openai-tiers-v2.bak для ручного восстановления.

ocx init, ocx start и ocx sync вызывают инжектор. При привязке к loopback по умолчанию он сохраняет встроенный id провайдера Codex openai и направляет этого провайдера на opencodex:

# root keys, before the first table
model_catalog_json = "/absolute/path/to/opencodex-catalog.json"
# Auto-injected by opencodex
openai_base_url = "http://127.0.0.1:10100/v1"
[features]
fast_mode = true

По умолчанию прокси слушает порт 10100 и обслуживает POST /v1/responses, POST /v1/responses/compact, POST /v1/images/generations, POST /v1/images/edits, GET /v1/models, GET /healthz и управляющую поверхность /api/*.

Встроенный инструмент Codex image_gen не проходит через /v1/responses — расширение codex-rs напрямую отправляет POST на {base_url}/images/generations (или /images/edits, когда приложены референсные изображения) с той же bearer-аутентификацией ChatGPT, что и для чата. Поскольку внедрённый base_url указывает на opencodex, прокси ретранслирует эти вызовы вышестоящему OpenAI:

  • Один forward-кандидат с учётом режима: Pool выбирает подходящий основной/добавленный аккаунт; Direct использует OAuth-bearer вызывающего. Настроенный режим одинаково применяется и к запросу изображения.
  • Провайдер с API-ключом OpenAI: используется только тогда, когда ни один forward-кандидат не «владеет» сбоем аутентификации. Сломанные или истёкшие учётные данные Pool никогда не маскируются отдельно оплачиваемым использованием API.
  • Ни того, ни другого: прокси возвращает понятную ошибку вместо безликого 404. Маршрутизируемые провайдеры (Cursor, Gemini, Kiro, …) не могут обслуживать генерацию изображений; если вы вообще не хотите предлагать этот инструмент, отключите его в Codex командой codex features disable image_generation ([features] image_generation = false в config.toml).

Если hostname не является loopback-адресом, Codex должен отправлять сгенерированный заголовок API-аутентификации. Поэтому инжектор в этом случае использует выделенного провайдера:

# root keys
model_provider = "opencodex"
model_catalog_json = "/absolute/path/to/opencodex-catalog.json"
# appended at the end of the file
# Auto-injected by opencodex
[model_providers.opencodex]
name = "OpenCodex Proxy"
base_url = "http://your-host:10100/v1"
wire_api = "responses"
requires_openai_auth = true
env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" }
# supports_websockets = true # only when config.websockets is true

Когда маршрутизацией управляет OpenCodex, в обоих режимах он записывает $CODEX_HOME/opencodex.config.toml как справочную и резервную конфигурацию. На loopback в ней лежат корневые ключи, которые можно объединить вручную, если автоматическое внедрение было удалено; вне loopback — форма с выделенным провайдером. В режиме внешнего провайдера этот профиль остается без изменений.

Codex CLI, TUI, App и SDK читают один и тот же домашний каталог Codex. opencodex определяет его из CODEX_HOME, с откатом на ~/.codex, и управляет файлами:

$CODEX_HOME/config.toml
$CODEX_HOME/opencodex.config.toml
$CODEX_HOME/opencodex-catalog.json
$CODEX_HOME/models_cache.json

В WSL, если CODEX_HOME не задан и Linux-файл ~/.codex/config.toml отсутствует, opencodex дополнительно ищет единственный домашний каталог Windows Codex Desktop по пути /mnt/c/Users/*/.codex/config.toml. Когда кандидат ровно один, используется именно этот каталог, чтобы режим app-server в WSL и Windows Codex Desktop разделяли одни и те же файлы конфигурации и аутентификации. Чтобы переопределить это обнаружение, задайте CODEX_HOME явно.

В режиме выделенного провайдера requires_openai_auth = true сохраняет поведение зависящих от аккаунта интерфейсов Codex App/TUI таким же, как в нативном Codex. opencodex также обслуживает /v1/responses по WebSocket. Выделенный провайдер объявляет supports_websockets = true только при "websockets": true; на loopback встроенный провайдер Codex может сначала попробовать WebSocket, и прокси с выключенной функцией вернёт 426, после чего Codex откатится на HTTP/SSE.

Форма loopback по умолчанию помечает новые треды нативным провайдером Codex openai, поэтому обычная история возобновления не требует перепривязки. При первой синхронизации треды, помеченные старыми сборками opencodex, также возвращаются к openai. Режим выделенного провайдера вне loopback, пока активен, зеркалирует историю под провайдером opencodex и при выходе восстанавливает метаданные из резервной копии. Чтобы вообще не трогать историю, задайте syncResumeHistory: false.

Codex показывает модели из каталога на диске (по умолчанию $CODEX_HOME/opencodex-catalog.json). При запуске и при ocx sync opencodex:

  1. Создаёт резервную копию нетронутого каталога — один раз, в ~/.opencodex/catalog-backup.json (чтобы выделение избранных было обратимым).
  2. Загружает актуальные каталоги моделей подходящих провайдеров (кеш ~5 минут; при сбое используется последний удачный список, затем настроенный models[]). У forward-аутентификации нет конечной точки моделей, а Cursor использует свой RPC GetUsableModels вместо /models.
  3. Объединяет маршрутизируемые модели как записи с пространством имён (provider/model), клонированные из шаблона нативного каталога Codex, чтобы строгий парсер Codex их принял.
  4. Фильтрует по config.disabledModels и непустому списку разрешённых selectedModels каждого провайдера.
  5. Переранжирует так, чтобы избранные модели шли первыми (см. ниже), и записывает объединённый каталог обратно.

У маршрутизируемых записей каталога идентичность GPT-5 также переписывается на настоящее имя вышестоящей модели. Элементы управления рассуждениями берутся из метаданных провайдера и модели по шкале Codex low | medium | high | xhigh | max | ultra; неподдерживаемые значения сопоставляются или ограничиваются перед запросом к вышестоящему провайдеру.

spawn_agent в Codex объявляет первые 5 видимых в селекторе моделей каталога после сортировки по приоритету. subagentModels принимает до пяти id — нативные GPT-слаги без префикса или маршруты provider/model — и присваивает им приоритеты 0–4, чтобы они сортировались первыми:

{
"subagentModels": [
"gpt-5.5",
"gpt-5.6-sol",
"anthropic/claude-opus-5",
"xai/grok-4.5",
"cursor/gpt-5.6-terra"
]
}

Ранжирование приоритетов: избранные (0–4) < остальные маршрутизируемые (5) < нативные (9). Этим также можно управлять из веб-дашборда.

Когда аккаунт ChatGPT добавляется в пул аккаунтов Codex, opencodex проверяет его перед сохранением небольшим потоковым запросом к бэкенду Codex Responses. Запрос использует настоящий массив элементов Responses (input: [{ type: "message", ... }]), дожидается response.completed и по умолчанию использует gpt-5.4-mini. Если эта модель возвращает HTTP 400, выполняется повтор с gpt-5.5; структурированные сведения об ошибке вышестоящего провайдера показываются без раскрытия сырых тел ответов. Фоновая перепроверка — отдельная функция, по умолчанию выключенная; она выполняется только когда включён Token Guardian, политика обновления chatgpt равна proactive, а tokenGuardian.codexWarmupEnabled установлен в true.

opencodex никогда не запирает вас. ocx stop — единственная команда, полностью возвращающая нативный Codex: она останавливает прокси, останавливает фоновый сервис, если он установлен, и убирает каждую внедрённую строку и каждую маршрутизируемую запись каталога, так что обычный codex работает ровно так, как будто opencodex никогда не существовал:

Terminal window
ocx stop # stop the proxy + service, restore native Codex
ocx restore # restore without stopping (alias: ocx eject)
ocx restore back # point plain Codex at the running proxy again

Когда opencodex работает как управляемый фоновый сервис, он устанавливает OCX_SERVICE=1, поэтому перезапуск, инициированный сервисом, не дёргает конфигурацию Codex — нативный Codex восстанавливают только явные ocx stop / ocx service stop.