Раскрываем Codex harness: как мы создали App Server
@ai_longreadsВ этой статье команда OpenAI рассказывает об архитектуре Codex App Server — протоколе для интеграции Codex в различные продукты, от IDE до веб-приложений.
Это AI-перевод статьи, сделанный каналом Про AI: Лучшие Статьи и Исследования.
Раскрываем Codex harness: как мы создали App Server
Unlocking the Codex harness: how we built the App Server Оригинальный текст:
В этом посте мы представим Codex App Server, поделимся нашими наработками о лучших способах интеграции возможностей Codex в ваш продукт, чтобы помочь пользователям ускорить рабочие процессы. Мы рассмотрим архитектуру и протокол App Server, его интеграцию с различными поверхностями Codex, а также дадим советы по использованию Codex — хотите ли вы превратить его в код-ревьюера, SRE-агента или помощника по написанию кода.
Происхождение App Server
Прежде чем погрузиться в архитектуру, полезно узнать предысторию App Server. Изначально App Server был практичным способом переиспользования Codex harness (обвязки) между продуктами, который постепенно эволюционировал в наш стандартный протокол.
Codex CLI начинался как TUI (терминальный пользовательский интерфейс), то есть доступ к Codex осуществлялся через терминал. Когда мы создавали расширение для VS Code (более удобный для IDE способ взаимодействия с агентами Codex), нам понадобился способ использовать тот же harness, чтобы управлять тем же агентным циклом из IDE-интерфейса без повторной реализации. Это означало поддержку богатых паттернов взаимодействия помимо запрос/ответ: исследование рабочего пространства, потоковую передачу прогресса по мере рассуждений агента и генерацию диффов. Сначала мы экспериментировали с представлением Codex как MCP-сервера, но поддержание семантики MCP в виде, имеющем смысл для VS Code, оказалось сложным. Вместо этого мы ввели JSON-RPC протокол, отражающий цикл TUI, который стал неофициальной первой версией App Server. В то время мы не ожидали, что другие клиенты будут зависеть от App Server, поэтому он не проектировался как стабильный API.
По мере роста популярности Codex в последующие месяцы внутренние команды и внешние партнёры захотели получить возможность встраивать тот же harness в свои продукты для ускорения рабочих процессов разработки. Например, JetBrains и Xcode хотели IDE-уровня агентного опыта, а десктопному приложению Codex нужно было оркестрировать множество агентов Codex параллельно. Эти требования подтолкнули нас к созданию платформенной поверхности, на которую могли бы безопасно полагаться как наши продукты, так и партнёрские интеграции. Она должна была быть простой в интеграции и обратно совместимой — чтобы мы могли развивать протокол без поломки существующих клиентов.
Далее мы рассмотрим, как мы спроектировали архитектуру и протокол, чтобы разные клиенты могли использовать один и тот же harness.
Внутри Codex harness
Сначала рассмотрим, что находится внутри Codex harness и как Codex App Server предоставляет его клиентам. В нашем предыдущем блог-посте мы разобрали основной агентный цикл, оркестрирующий взаимодействие между пользователем, моделью и инструментами. Это ядро логики Codex harness, но полный агентный опыт включает больше:
- Жизненный цикл и персистентность потоков (threads). Thread — это разговор Codex между пользователем и агентом. Codex создаёт, возобновляет, форкает и архивирует потоки, а также сохраняет историю событий, чтобы клиенты могли переподключаться и отображать согласованную временную шкалу.
- Конфигурация и аутентификация. Codex загружает конфигурацию, управляет настройками по умолчанию и запускает потоки аутентификации вроде «Войти через ChatGPT», включая состояние учётных данных.
- Выполнение инструментов и расширения. Codex выполняет shell/file-инструменты в песочнице и подключает интеграции вроде MCP-серверов и skills (навыков), чтобы они могли участвовать в агентном цикле в рамках единой модели политик.
Вся агентная логика, включая основной агентный цикл, находится в части кодовой базы Codex CLI под названием «Codex core». Codex core — это одновременно библиотека, где живёт весь агентный код, и среда выполнения, которую можно запустить для работы агентного цикла и управления персистентностью одного потока Codex (разговора).
Чтобы быть полезным, Codex harness должен быть доступен клиентам. Здесь на сцену выходит App Server.
App Server — это одновременно JSON-RPC протокол между клиентом и сервером и долгоживущий процесс, хостящий потоки Codex core. Как видно из диаграммы, процесс App Server имеет четыре основных компонента: stdio reader, процессор сообщений Codex, менеджер потоков и core threads. Менеджер потоков запускает одну core-сессию для каждого потока, а процессор сообщений Codex напрямую взаимодействует с каждой core-сессией для отправки клиентских запросов и получения обновлений.
Один клиентский запрос может породить множество событий-обновлений, и именно эти детальные события позволяют нам строить богатый UI поверх App Server. Более того, stdio reader и процессор сообщений Codex служат слоем трансляции между клиентом и потоками Codex core. Они транслируют клиентские JSON-RPC запросы в операции Codex core, слушают внутренний поток событий Codex core и затем преобразуют эти низкоуровневые события в небольшой набор стабильных, готовых для UI JSON-RPC уведомлений.
JSON-RPC протокол между клиентом и App Server полностью двунаправленный. Типичный поток имеет клиентский запрос и множество серверных уведомлений. Кроме того, сервер может инициировать запросы, когда агенту нужен ввод — например, одобрение — и затем приостановить ход до ответа клиента.
Примитивы разговора
Далее разберём примитивы разговора — строительные блоки протокола App Server. Проектирование API для агентного цикла непросто, потому что взаимодействие пользователь/агент — это не простой запрос/ответ. Один пользовательский запрос может развернуться в структурированную последовательность действий, которую клиент должен точно отобразить: ввод пользователя, инкрементальный прогресс агента, артефакты, созданные по пути (например, диффы). Чтобы сделать этот поток взаимодействия простым для интеграции и устойчивым для разных UI, мы остановились на трёх ключевых примитивах с чёткими границами и жизненными циклами:
- Item (элемент). Item — это атомарная единица ввода/вывода в Codex. Элементы типизированы (например, сообщение пользователя, сообщение агента, выполнение инструмента, запрос одобрения, дифф), и каждый имеет явный жизненный цикл:
- item/started — когда элемент начинается
- опциональные события item/*/delta по мере потоковой передачи контента (для потоковых типов элементов)
- item/completed — когда элемент финализируется с терминальной нагрузкой
Этот жизненный цикл позволяет клиентам начинать рендеринг немедленно по started, стримить инкрементальные обновления по delta и финализировать по completed.
- Turn (ход). Turn — это одна единица работы агента, инициированная пользовательским вводом. Он начинается, когда клиент отправляет ввод (например, «запусти тесты и суммаризируй ошибки») и заканчивается, когда агент завершает генерацию выходов для этого ввода. Turn содержит последовательность элементов, представляющих промежуточные шаги и выходы.
- Thread (поток). Thread — это долговременный контейнер для продолжающейся сессии Codex между пользователем и агентом. Он содержит множество ходов. Потоки можно создавать, возобновлять, форкать и архивировать. История потока персистируется, чтобы клиенты могли переподключаться и отображать согласованную временную шкалу.
Теперь рассмотрим упрощённый разговор между клиентом и агентом, где разговор представлен примитивами:
В начале разговора клиент и сервер должны установить рукопожатие initialize. Клиент должен отправить единственный запрос initialize перед любым другим методом, а сервер подтверждает ответом. Это даёт серверу возможность объявить capabilities (возможности) и позволяет обеим сторонам согласовать версионирование протокола, флаги функций и значения по умолчанию до начала реальной работы.
Когда клиент делает новый запрос, он сначала создаёт thread, затем turn. Сервер отправляет уведомления о прогрессе (thread/started и turn/started). Он также отправляет зарегистрированные входные данные как элементы, вроде сообщения пользователя.
Вызовы инструментов также отправляются клиенту как элементы. Кроме того, сервер может запросить одобрение клиента перед выполнением действия, отправив серверный запрос. Одобрение приостановит ход до ответа клиента «allow» или «deny».
В конце сервер отправляет сообщение агента и затем завершает ход с turn/completed. События delta сообщения агента стримят части сообщения до финализации элемента с item/completed.
Сообщения на диаграмме упрощены для читаемости. Если хотите увидеть JSON для полного хода, можете запустить тестовый клиент из репозитория Codex CLI:
Интеграция с клиентами
Теперь посмотрим, как разные клиентские поверхности встраивают Codex через App Server. Мы рассмотрим три паттерна: локальные приложения и IDE, веб-среда Codex и TUI.
Во всех трёх транспорт — JSON-RPC через stdio (JSONL). JSON-RPC упрощает создание клиентских привязок на языке по вашему выбору. Поверхности Codex и партнёрские интеграции реализовали клиенты App Server на языках включая Go, Python, TypeScript, Swift и Kotlin. Для TypeScript можно генерировать определения напрямую из Rust-протокола командой:
Для других языков можно сгенерировать бандл JSON Schema и подать его в предпочитаемый генератор кода командой:
Локальные клиенты обычно включают или получают платформо-специфичный бинарник App Server, запускают его как долгоживущий дочерний процесс и держат двунаправленный stdio-канал открытым для JSON-RPC. В нашем расширении VS Code и десктопном приложении, например, поставляемый артефакт включает платформо-специфичный бинарник Codex и привязан к протестированной версии, чтобы клиент всегда запускал именно те биты, которые мы провалидировали.
Не каждая интеграция может часто выпускать обновления клиента. Некоторые партнёры вроде Xcode разделяют циклы релизов, сохраняя клиент стабильным и позволяя ему указывать на более новый бинарник App Server при необходимости. Таким образом они могут принимать серверные улучшения (например, лучшую авто-компактификацию в Codex core или новые поддерживаемые ключи конфигурации) и выкатывать исправления багов без ожидания релиза клиента. JSON-RPC поверхность App Server спроектирована обратно совместимой, поэтому старые клиенты могут безопасно общаться с новыми серверами.
Codex Web использует Codex harness, но запускает его в контейнерной среде. Воркер провизионирует контейнер с checkout'нутым рабочим пространством, запускает бинарник App Server внутри него и поддерживает долгоживущий JSON-RPC через stdio канал. Веб-приложение (работающее во вкладке браузера пользователя) общается с бэкендом Codex через HTTP и SSE, которые стримят события задач от воркера. Это сохраняет браузерный UI лёгким, при этом давая нам согласованную среду выполнения для десктопа и веба.
Поскольку веб-сессии эфемерны (вкладки закрываются, сети отваливаются), веб-приложение не может быть источником истины для долгоживущих задач. Хранение состояния и прогресса на сервере означает, что работа продолжается даже если вкладка исчезает. Потоковый протокол и сохранённые сессии потоков облегчают переподключение новой сессии, продолжение с места остановки и синхронизацию без перестройки состояния в клиенте.
Исторически TUI был «нативным» клиентом, работавшим в том же процессе, что и агентный цикл, и общавшимся напрямую с Rust core типами, а не через протокол App Server. Это ускоряло раннюю итерацию, но также делало TUI особым случаем.
Теперь, когда App Server существует, мы планируем рефакторить TUI, чтобы он использовал его и вёл себя как любой другой клиент: запускал дочерний процесс App Server, говорил JSON-RPC через stdio и рендерил те же потоковые события и одобрения. Это открывает рабочие процессы, где TUI может подключаться к серверу Codex на удалённой машине, держа агента близко к вычислениям и продолжая работу даже если ноутбук засыпает или отключается, при этом доставляя живые обновления и контролы локально.
Выбор правильного протокола
Codex App Server будет основным методом интеграции, который мы поддерживаем в будущем, но существуют и другие методы с более ограниченной функциональностью. По умолчанию мы рекомендуем клиентам использовать Codex App Server для интеграции с Codex, но стоит рассмотреть разные методы интеграции и понять их плюсы и минусы. Ниже — наиболее распространённые способы работы с Codex и когда каждый может подойти.
Запустите codex mcp-server и подключитесь из любого MCP-клиента, поддерживающего stdio-серверы (например, OpenAI Agents SDK). Это хороший выбор, если у вас уже есть MCP-based рабочий процесс и вы хотите вызывать Codex как вызываемый инструмент. Минус в том, что вы получаете только то, что предоставляет MCP, поэтому Codex-специфичные взаимодействия, опирающиеся на более богатую семантику сессий (например, обновления диффов), могут нечётко отображаться через MCP endpoints (точки доступа).
Некоторые экосистемы предлагают портируемый интерфейс, который может работать с несколькими провайдерами моделей и средами выполнения. Это может подойти, если вам нужна одна абстракция для координации нескольких агентов. Компромисс в том, что эти протоколы часто сходятся к общему подмножеству возможностей, что может затруднить представление более богатых взаимодействий, особенно когда важна провайдер-специфичная семантика инструментов и сессий. Эта область быстро развивается, и мы ожидаем появления более общих стандартов по мере выяснения лучших примитивов для представления реальных агентных рабочих процессов (skills — хороший пример этого).
Выбирайте App Server, когда хотите получить полный Codex harness, представленный как стабильный, готовый для UI поток событий. Вы получаете как полную функциональность агентного цикла, так и другие поддерживающие функции вроде входа через ChatGPT, обнаружения моделей и управления конфигурацией. Основная цена — работа по интеграции, поскольку вам нужно создать клиентскую JSON-RPC привязку на вашем языке. На практике, однако, Codex может сделать большую часть тяжёлой работы, если подать ему JSON schema и документацию. Многие команды, с которыми мы работали, смогли быстро сделать работающую интеграцию, используя Codex.
Лёгкий, скриптуемый CLI-режим для разовых задач и CI-прогонов. Хороший выбор для автоматизации и пайплайнов, где вам нужна одна команда для запуска до завершения неинтерактивно, потоковый структурированный вывод для логов и выход с чётким сигналом успеха или неудачи.
TypeScript-библиотека для программного управления локальными агентами Codex изнутри вашего приложения. Лучше всего подходит, когда вам нужен нативный библиотечный интерфейс для серверных инструментов и рабочих процессов без создания отдельного JSON-RPC клиента. Поскольку она вышла раньше App Server, она сейчас поддерживает меньше языков и меньшую поверхность. При наличии интереса разработчиков мы можем добавить дополнительные SDK, обёртывающие протокол App Server, чтобы команды могли покрыть большую часть поверхности harness без написания JSON-RPC привязок.
Двигаемся дальше
В этом посте мы поделились тем, как мы подходим к проектированию нового стандарта для взаимодействия с агентами и как превратить Codex harness в стабильный, дружественный к клиентам протокол. Мы рассмотрели, как App Server предоставляет Codex core, позволяет клиентам управлять полным агентным циклом и питает широкий спектр поверхностей, включая TUI, локальные IDE-интеграции и веб-среду выполнения.
Если это вдохновило вас на идеи по интеграции Codex в ваши собственные рабочие процессы, стоит попробовать App Server. Весь исходный код находится в open-source репозитории Codex CLI. Делитесь обратной связью и запросами функций. Мы рады слышать вас и продолжать делать агентов более доступными для всех.
Подпишитесь на канал и каждый день читайте лучшие материалы про AI переведенные на русский!
Нашли интересную статью для перевода? Пришлите нашему боту: @ailongreadsbot