Passer au contenu principal
OpenAI

4 février 2026

Ingénierie

Débloquer le harnais Codex : la construction de notre App Server

Par Celia Chen, membre du personnel technique

Chargement…

L’agent de programmation Codex d’OpenAI est disponible sur de nombreuses plateformes : l’application Web(s'ouvre dans une nouvelle fenêtre), le CLI(s'ouvre dans une nouvelle fenêtre), l’extension IDE(s'ouvre dans une nouvelle fenêtre) et la nouvelle application Codex pour macOS. Sous le capot, ils sont tous alimentés par le même moteur Codex : la boucle d'agent et la logique qui sous-tend toutes les expériences Codex. Le lien essentiel entre eux? Le serveur d'applications Codex(s'ouvre dans une nouvelle fenêtre), une API JSON-RPC1 bidirectionnelle conviviale pour les clients.

Dans cette publication, nous allons présenter le serveur d'applications Codex et partager nos expériences sur les meilleures façons d'intégrer les capacités de Codex à votre produit pour aider vos utilisateurs à améliorer considérablement leurs flux de travail. Nous aborderons l’architecture et le protocole du serveur d’applications et la façon dont il s’intègre à différentes interfaces Codex, ainsi que des conseils pour tirer parti de Codex, que vous souhaitiez transformer Codex en réviseur de code, en agent SRE ou en assistant de codage.

Origine du serveur d'applications

Avant de plonger dans l’architecture, il est utile de connaître l’historique du serveur d'applications. Au départ, le serveur d'applications était un moyen pratique de réutiliser le harnais Codex entre les produits, évoluant progressivement pour devenir notre protocole standard.

Le CLI Codex a commencé comme une TUI (interface utilisateur de terminal), ce qui signifie que Codex est accessible via le terminal. Lorsque nous avons développé l’extension VS Code (une méthode plus conviviale pour les IDE d’interagir avec les agents Codex), nous avions besoin d’un moyen d’utiliser le même cadre afin de piloter la même boucle d’agent depuis une IU d’IDE sans la réimplémenter. Cela signifiait prendre en charge des modèles d’interaction riches au-delà du schéma demande/réponse, tels que l’exploration de l’espace de travail, la diffusion en continu de la progression pendant que l’agent raisonne, et l’émission de différences. Nous avons d’abord expérimenté en exposant Codex en tant que serveur MCP(s'ouvre dans une nouvelle fenêtre), mais il s'est avéré difficile de maintenir la sémantique MCP d'une manière qui ait du sens pour VS Code. Nous avons plutôt introduit un protocole JSON-RPC qui reflétait la boucle TUI, ce qui est devenu la première version non officielle(s'ouvre dans une nouvelle fenêtre) du serveur d'applications. À l’époque, nous ne nous attendions pas à ce que d’autres clients dépendent du serveur d’applications; par conséquent, il n’a pas été conçu comme une API stable.

Au cours des mois suivants, à mesure que l’adoption de Codex augmentait, les équipes internes et les partenaires externes souhaitaient pouvoir intégrer le même harnais dans leurs propres produits afin d’accélérer les flux de travail de développement logiciel de leurs utilisateurs. Par exemple, JetBrains et Xcode souhaitaient une expérience d’agent de niveau IDE, tandis que l’application de bureau Codex devait orchestrer de nombreux agents Codex en parallèle. Ces exigences nous ont poussés à concevoir une surface de plateforme sur laquelle nos produits et les intégrations de nos partenaires pourraient compter de manière sécuritaire au fil du temps. Il devait être facile à intégrer et rétrocompatible, ce qui signifie que nous pouvions faire évoluer le protocole sans perturber les clients existants.

Ensuite, nous verrons comment nous avons conçu l’architecture et le protocole afin que différents clients puissent utiliser le même harnais.

À l'intérieur du harnais Codex

Tout d'abord, examinons de plus près ce qui se trouve à l'intérieur du harnais Codex et comment le serveur d'applications Codex le rend accessible aux clients. Dans notre dernier blogue Codex, nous avons analysé la boucle d’agent principale qui orchestre l’interaction entre l’utilisateur, le modèle et les outils. Voici la logique centrale du harnais Codex, mais l'expérience complète de l'agent ne s'arrête pas là :

1. Cycle de vie et persistance de fil. Un fil est une conversation dans Codex entre un utilisateur et un agent. Codex crée, reprend, forke et archive des fils, et conserve l’historique des événements afin que les clients puissent se reconnecter et afficher une chronologie cohérente.

2. Config et auth. Codex charge la configuration, gère les paramètres par défaut et exécute des flux d’authentification tels que « Se connecter avec ChatGPT », y compris l’état des informations d’identification.

3. Exécution de l'outil et des extensions. Codex exécute des outils coquilles/fichiers dans un bac à sable et connecte des intégrations telles que les serveurs MCP et les compétences afin qu'ils puissent participer à la boucle d'agent dans le cadre d'un modèle de politique cohérent.

Toute la logique d’agent que nous avons mentionnée ici, y compris la boucle d’agent principale, se trouve dans une partie du code source de CLI Codex appelée « noyau Codex(s'ouvre dans une nouvelle fenêtre) ». Le noyau Codex est à la fois une bibliothèque où tout le code d'agent est stocké et un environnement d'exécution qui peut être lancé pour exécuter la boucle d'agent et gérer la persistance d'un fil Codex (conversation).

Pour être utile, le harnais Codex doit être accessible aux clients. C’est là que le serveur d’applications entre en jeu.

Diagramme intitulé « Flux de processus du serveur d’applications ». Un client envoie des messages JSON-RPC à un lecteur stdio, qui achemine les demandes à un processeur de messages Codex. Le processeur interagit avec un gestionnaire de fils et un fil principal via des fils de recherche, des poignées de fil, des demandes soumises et des événements/mises à jour, puis renvoie des réponses au client.

Le serveur d'applications est à la fois le protocole JSON-RPC entre le client et le serveur, et un processus de longue durée qui héberge les fils de noyau Codex. Comme nous pouvons le voir dans le diagramme ci-dessus, un processus de serveur d'applications comporte quatre composants principaux : le lecteur stdio, le processeur de messages Codex, le gestionnaire de fils et les fils principaux. Le gestionnaire de fils initialise une session principale pour chaque fil, et le processeur de messages Codex communique ensuite directement avec chaque session principale pour soumettre les demandes des clients et recevoir des mises à jour.

Une demande client peut entraîner de nombreuses mises à jour d’événements, et ces événements détaillés nous permettent de créer une interface utilisateur riche sur le serveur d'applications. De plus, le lecteur stdio et le processeur de messages Codex servent de couche de traduction entre le client et les fils de noyau Codex. Ils traduisent les demandes JSON-RPC des clients en opérations du noyau Codex, écoutent le flux d’événements interne du noyau Codex, puis transforment ces événements de bas niveau en un ensemble restreint de notifications JSON-RPC stables, prêtes à l'emploi pour l'interface utilisateur.

Le protocole JSON-RPC entre le client et le serveur d'applications est entièrement bidirectionnel. Un fil typique comporte une demande d'un client et de nombreuses notifications d'un serveur. De plus, le serveur peut initier des demandes lorsque l’agent a besoin d’une entrée, comme une approbation, puis suspendre le tour jusqu’à ce que le client réponde.

Les primitives de conversation

Ensuite, nous allons décomposer les primitives de conversation, les éléments de base du protocole de serveur d'applications. Concevoir une API pour la boucle d'agent est délicat, car l'interaction utilisateur/agent n'est pas une simple demande/réponse. Une demande d’utilisateur peut se déployer en une séquence structurée d’actions que le client doit représenter fidèlement : l’entrée de l’utilisateur, la progression incrémentielle de l’agent, les artefacts produits en cours de route (p. ex. des diffs). Pour rendre ce flux d'interaction facile à intégrer et résilient à travers les interfaces utilisateur, nous avons opté pour trois primitives essentielles avec des limites et des cycles de vie bien définis :

1. Élément : Un élément est l’unité atomique d’entrée/sortie dans Codex. Les éléments sont classés par type (par exemple, message utilisateur, message agent, exécution d'outil, demande d'approbation, diff) et chacun a un cycle de vie explicite :

  • item/started lorsque l’élément débute
  • événements facultatifs item/*/delta en tant que flux de contenu (pour les types d’éléments à diffuser)
  • item/completed lorsque l’élément est finalisé avec sa charge utile finale

Ce cycle de vie permet aux clients de commencer le rendu immédiatement sur started, de recevoir des mises à jour incrémentielles sur delta, et de finaliser sur completed.

2. Tour : Un tour est une unité de travail de l’agent initiée par l’entrée de l’utilisateur. Cela commence lorsque le client soumet une entrée (par exemple, « exécuter des tests et résumer les échecs ») et se termine lorsque l’agent a terminé de produire des résultats pour cette entrée. Un tour comprend une séquence d’éléments représentant les étapes intermédiaires et les résultats produits en cours de route.

3. Fil : Un fil est le conteneur durable d'une session Codex en cours entre un utilisateur et un agent. Il comporte plusieurs tours. Les fils peuvent être créés, repris, bifurqués et archivés. L’historique du fil est conservé afin que les clients puissent se reconnecter et afficher une chronologie cohérente.

Maintenant, nous allons examiner une conversation simplifiée entre un client et un agent, où la conversation est représentée par des primitives :

Diagramme intitulé « Flux de messages du protocole client-serveur : établissement de liaison d'initialisation ». Un client envoie une demande d'initialisation avec clientInfo au serveur. Le serveur répond avec un événement de résultat contenant la chaîne userAgent "my_client/1.0".

Au début de la conversation, le client et le serveur doivent établir la liaison d'initialisation. Le client doit envoyer une seule demande d'initialisation avant toute autre méthode, et le serveur en accuse réception avec une réponse. Cela donne au serveur l’occasion de faire connaître ses capacités et permet aux deux parties de s’entendre sur la version du protocole, les indicateurs de fonctionnalité et les paramètres par défaut avant que le véritable travail ne commence. Voici un exemple de charge utile de l’extension VS Code d’OpenAI :

JSON

1
{
2
"method": "initialize",
3
"id": 0,
4
"params": {
5
"clientInfo": {
6
"name": "codex_vscode",
7
"title": "Codex VS Code Extension",
8
"version": "0.1.0"
9
}
10
}
11
}

Voici ce que le serveur retourne :

JSON

1
{
2
"id": 0,
3
"result": {
4
"userAgent": "codex_vscode/0.94.0-alpha.7 (Mac OS 26.2.0; arm64) vscode/2.4.22 (codex_vscode; 0.1.0)"
5
}
6
}
Diagramme intitulé « Flux de messages du protocole client-serveur : cycle de vie des fils et des tours. » Le client envoie des demandes thread/start et turn/start au serveur. Le serveur émet des événements—thread/started, turn/started, item/started et item/completed—indiquant un tour où le message utilisateur est « exécuter des tests et résumer les échecs. »

Lorsqu’un client effectue une nouvelle demande, il créera d’abord un fil, puis un tour. Le serveur enverra des notifications de progression (thread/started et turn/started). Il renverra également les entrées qu’il enregistre comme éléments, tel que le message utilisateur ici.

Diagramme intitulé « Flux de messages du protocole client-serveur : exécution d’outil avec approbation facultative ». Lors d'un appel d'outil, le serveur émet item/started, puis item/commandExecution/requestApproval avec une raison (« exécuter des tests »). Le client renvoie un événement d’approbation (allow/deny). Le serveur émet ensuite item/completed, indiquant l’exécution de la commande ("pnpm test").

Les appels d'outils sont aussi renvoyés au client sous forme d'éléments. De plus, le serveur peut demander l’approbation du client avant de pouvoir exécuter une action en envoyant une demande au serveur. L’approbation mettra le tour en pause jusqu’à ce que le client réponde par « autoriser » ou « refuser ». Voici à quoi ressemble le flux d’approbation dans l’extension VS Code :

Invite d’autorisation dans une interface à thème sombre demandant : « Voulez-vous m’autoriser à exécuter le test pnpm pour cet espace de travail? » Il répertorie les options : 1) Oui, 2) Oui et ne plus demander pour les commandes commençant par pnpm test, et 3) Non, avec un bouton Soumettre en bas.
Schéma intitulé « Flux de messages du protocole client-serveur : flux de messages d'agent de diffusion. » Le serveur diffuse un message assistant en plusieurs parties : item/started, deux événements agentMessage/delta (« exécuté 3 tests. », « tous réussis »), puis item/completed. Le tour se termine par turn/completed.

À la fin, le serveur envoie un message agent, puis termine le tour avec turn/completed. Les événements delta des messages agent transmettent des segments du message jusqu’à ce que le message soit finalisé avec item/completed.

Les messages dans le diagramme sont simplifiés pour faciliter la lisibilité. Si vous souhaitez visualiser le JSON pour un tour complet, vous pouvez exécuter le client test depuis le dépôt CLI Codex :

Bash

1
codex debug app-server send-message-v2 "run tests and summarize failures"

Intégration avec les clients

Maintenant, examinons comment différentes interfaces client intègrent Codex via le serveur d'applications. Nous aborderons trois modèles : les applications locales et IDE, l'environnement d'exécution Web Codex et le TUI.

Diagramme intitulé « Clients Codex intégrés avec le harnais Codex via le serveur d’applications. » Les clients de première partie (Codex Desktop App, TUI/CLI, Web Runtime) et les intégrations tierces (IDE JetBrains, VS Code, Xcode) communiquent avec le système Codex par des appels JSON-RPC.

Dans les trois cas, le transport est JSON-RPC via stdio (JSONL). JSON-RPC facilite la création de liaisons client dans la langue de votre choix. Les interfaces Codex et les intégrations partenaires ont mis en œuvre des clients de serveur d'applications dans des langages tels que Go, Python, TypeScript, Swift et Kotlin. Pour TypeScript, vous pouvez générer des définitions directement à partir du protocole Rust en exécutant :

Bash

1
codex app-server generate-ts

Pour les autres langues, vous pouvez générer un forfait de schémas JSON et l'intégrer dans votre générateur de code préféré en exécutant :

Bash

1
codex app-server generate-json-schema
Applications locales et IDE
Capture d’écran de VS Code avec l’extension Codex en cours d’exécution. Un fichier de test Rust est ouvert, et en dessous, le panneau Codex décrit l’exécution de fmt et cargo test -p codex-app-server, indiquant que le formatage et les tests sont en cours, en attente d’un résultat final de réussite ou d’échec.

Les clients locaux regroupent généralement un binaire de serveur d'applications spécifique à la plateforme ou le récupèrent, le lancent comme un processus enfant de longue durée et maintiennent un canal stdio bidirectionnel ouvert pour JSON-RPC. Dans notre extension VS Code et notre application de bureau, par exemple, l’artéfact livré inclut le binaire Codex spécifique à la plateforme et est fixé à une version testée afin que le client exécute toujours exactement les éléments que nous avons validés.

Toutes les intégrations ne peuvent pas expédier fréquemment des mises à jour pour les clients. Certains partenaires, comme Xcode, dissocient les cycles de publication en maintenant le client stable et en lui permettant de pointer vers un binaire plus récent du serveur d'applications lorsque nécessaire. Ainsi, ils peuvent adopter des améliorations côté serveur (par exemple, une meilleure compaction automatique dans le noyau Codex ou de nouvelles clés de configuration prises en charge) et déployer des correctifs de bogues sans attendre une version du client. La surface JSON-RPC du serveur d'applications est conçue pour être rétrocompatible, afin que les anciens clients puissent communiquer en toute sécurité avec des serveurs plus récents.

Web Codex
Capture d’écran d’une interface Web Codex montrant une mise à jour intitulée « Mise à jour du message de réussite de connexion ». Le panneau de gauche résume les changements, les tests et les fichiers modifiés, tandis que le panneau de droite affiche une différence de code pour login.rs avec une formulation actualisée du message de réussite de connexion.

Codex Web utilise le harnais Codex, mais l’exécute dans un environnement conteneur. Un travailleur provisionne un conteneur avec l’espace de travail extrait, lance le binaire du serveur d'applications à l’intérieur et maintient un canal JSON-RPC de longue durée sur stdio2. L’application Web (exécutée dans l’onglet du navigateur de l’utilisateur) communique avec l'arrière-plan Codex via HTTP et SSE, qui diffuse en continu les événements de tâche produits par le travailleur. Cela permet de maintenir l'IU côté navigateur légère tout en nous assurant un environnement d'exécution cohérent sur les ordinateurs de bureau et le web.

Étant donné que les sessions Web sont éphémères (les onglets se ferment, les réseaux se déconnectent), l’application Web ne peut pas être la source de vérité pour les tâches de longue durée. Conserver l’état et la progression sur le serveur signifie que le travail se poursuit même si l’onglet disparaît. Le protocole de diffusion en continu et les sessions de fil enregistrées permettent à une nouvelle session de se reconnecter facilement, de reprendre là où elle s'était arrêtée et de rattraper le retard sans reconstruire l'état dans le client.

TUI/CLI Codex
Capture d’écran d’un terminal exécutant le CLI Codex. Il affiche la bannière OpenAI Codex avec le modèle GPT-5.2 Codex medium, une commande utilisateur « expliquez-moi le serveur d'applications » et un statut « En cours ». Ci-dessous, une suggestion s’affiche : « rédigez des tests pour @filename », avec des options de raccourcis.

Historiquement, le TUI était un client « natif » qui s’exécutait dans le même processus que la boucle d’agent et communiquait directement avec les types principaux de Rust plutôt qu’avec le protocole du serveur d'application. Cela a rendu les premières itérations rapides, mais cela a aussi fait de la TUI une surface de cas particuliers.

Maintenant que le serveur d'applications existe, nous prévoyons de refactoriser le TUI(s'ouvre dans une nouvelle fenêtre) pour l’utiliser afin qu’elle se comporte comme n’importe quel autre client : lancer un processus enfant du serveur d'applications, communiquer en JSON-RPC via stdio et afficher les mêmes événements en continu et approbations. Cela permet d'activer des flux de travail où le TUI peut se connecter à un serveur Codex fonctionnant sur une machine distante, en gardant l'agent proche des ressources de calcul et en poursuivant le travail même si l'ordinateur portable se met en veille ou se déconnecte, tout en fournissant des mises à jour et des contrôles en direct localement.

Choisir le bon protocole

Le serveur d'applications Codex sera la méthode d’intégration de premier ordre que nous maintiendrons à l’avenir, mais il existe aussi d’autres méthodes aux fonctionnalités plus limitées. Par défaut, nous recommandons aux clients d’utiliser le serveur d'applications Codex pour s’intégrer à Codex, mais il est utile d’examiner différentes méthodes d’intégration et d’en comprendre les avantages et les inconvénients. Voici les façons les plus courantes de piloter Codex et les moments où chacune pourrait être appropriée.

Protocoles JSON-RPC

Codex en tant que serveur MCP

Exécutez codex mcp-server(s'ouvre dans une nouvelle fenêtre) et connectez-vous à partir de n’importe quel client MCP prenant en charge les serveurs stdio (p. ex. OpenAI Agents SDK(s'ouvre dans une nouvelle fenêtre)). C’est un bon choix si vous avez déjà un flux de travail basé sur MCP et que vous souhaitez utiliser Codex comme un outil que l’on peut appeler. L’inconvénient, c’est que vous n’obtenez que ce que MCP expose, donc les interactions spécifiques à Codex qui reposent sur une sémantique de session plus riche (p. ex., les mises à jour de diff) pourraient ne pas se mapper proprement via les endpoints MCP.

Protocoles de harnais d’agents interfournisseurs

Certains écosystèmes offrent une interface portable qui peut cibler plusieurs fournisseurs de modèles et environnements d’exécution. Cela pourrait être un bon choix si vous souhaitez une abstraction qui coordonne plusieurs agents. Le compromis est que ces protocoles convergent souvent vers le sous-ensemble commun de capacités, ce qui peut rendre plus difficile la représentation d'interactions plus riches, surtout lorsque la sémantique des outils et des sessions spécifiques au fournisseur est importante. Cet espace évolue rapidement, et nous nous attendons à ce que des normes plus courantes émergent à mesure que nous identifions les meilleurs éléments de base pour représenter les flux de travail des agents dans le monde réel (compétences(s'ouvre dans une nouvelle fenêtre) en est un bon exemple).

Serveur d'applications Codex

Choisissez le serveur d’applications lorsque vous souhaitez que l’ensemble du système Codex soit exposé sous forme de flux d’événements stable et convivial pour l’interface utilisateur. Vous bénéficiez à la fois de toutes les fonctionnalités complètes de la boucle d’agent et d’autres fonctionnalités de soutien telles que la connexion avec ChatGPT, la découverte de modèles et la gestion de la configuration. Le principal coût est le travail d'intégration, car vous devez créer la liaison JSON-RPC côté client dans votre langue. En pratique, cependant, Codex peut effectuer une grande partie du travail si vous lui fournissez le schéma JSON et la documentation. De nombreuses équipes avec lesquelles nous avons travaillé ont pu réaliser rapidement une intégration fonctionnelle grâce à Codex.

Autres façons d’intégrer Codex

Un mode CLI léger et scriptable pour des tâches ponctuelles et des exécutions CI. C’est un bon choix pour l’automatisation et les pipelines lorsque vous souhaitez qu’une seule commande s’exécute jusqu’à son terme de manière non interactive, diffuse des sorties structurées pour les journaux et se termine par un signal clair de réussite ou d’échec.

Une bibliothèque TypeScript pour contrôler de manière programmatique des agents Codex locaux depuis votre propre application. C’est idéal lorsque vous souhaitez une interface de bibliothèque native pour des outils et des flux de travail côté serveur, sans avoir à développer un client JSON-RPC distinct. Étant donné qu'il a été expédié avant le serveur d'applications, il prend actuellement en charge moins de langues et a une surface fonctionnelle plus limitée. S'il y a de l'intérêt de la part des développeurs, nous pourrions ajouter des SDK supplémentaires qui encapsulent le protocole de serveur d'applications afin que les équipes puissent couvrir une plus grande partie de la surface du harnais sans avoir à écrire de liaisons JSON-RPC.

Pour aller plus loin

Dans cet publication, nous avons partagé notre approche pour concevoir une nouvelle norme d'interaction avec les agents et comment transformer le harnais Codex en un protocole stable et convivial pour les clients. Nous avons expliqué comment le serveur d'applications expose le noyau Codex, permet aux clients de piloter la boucle complète de l'agent et alimente un large éventail d'interfaces, y compris le TUI, les intégrations locales d'IDE et l'environnement d'exécution Web.

Si cela vous a donné des idées pour intégrer Codex à vos propres flux de travail, il vaut la peine d’essayer le serveur d'applications. Tout le code source se trouve dans le dépôt(s'ouvre dans une nouvelle fenêtre) source ouverte CLI Codex. N'hésitez pas à partager vos commentaires et vos demandes de fonctionnalités. Nous sommes ravis d’avoir de vos nouvelles et de continuer à rendre les agents plus accessibles à tous.

Auteur

Celia Chen

Remerciements

Remerciements particuliers à Michael Bolin, Owen Lin, Eric Traut et Rasmus Rygaard pour leur contribution à cette publication, ainsi qu’à toute l’équipe Codex qui a travaillé sur le serveur d'applications.

Notes de bas de page

  1. 1

    Nous utilisons une variante « JSON‑RPC lite » : elle conserve la forme demande/réponse/notification, mais omet l'en-tête « jsonrpc »: « 2.0 » et est structurée comme JSONL sur stdio plutôt que comme JSON‑RPC 2.0 strict.

  2. 2

     “stdio” fait référence à stdin/stdout du serveur d'applications à l’intérieur du conteneur. Dans les configurations hébergées, ces flux sont souvent acheminés via un tunnel sur une connexion réseau persistante (p. ex., de type WebSocket) vers l’environnement d’exécution du conteneur, de sorte qu’ils se comportent comme stdio même s’ils ne sont pas de véritables tubes locaux.