Aller au contenu

Intégration à Codex

opencodex fait passer Codex par le proxy en modifiant deux éléments lus par Codex : sa configuration ($CODEX_HOME/config.toml, par défaut ~/.codex/config.toml) et son catalogue de modèles. Chaque modification est idempotente et réversible.

Le proxy expose une route non qualifiée openai pour la connexion Codex, avec les modes de compte Pool (par défaut) et Direct, ainsi que openai-apikey/<model> pour la clé API configurée. Pool comprend le compte principal et les comptes ajoutés ; Direct utilise uniquement le jeton Bearer du compte appelant ou principal. Ces routes ne se rabattent jamais l’une sur l’autre. Les configurations v1 distribuées migrent vers le marqueur 2 et conservent config.json.pre-openai-tiers-v2.bak pour une restauration manuelle.

ocx init, ocx start et ocx sync appellent l’injecteur. Sur la liaison de bouclage par défaut, il conserve l’identifiant du fournisseur openai intégré à Codex et fait pointer ce fournisseur vers 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"
# only when fastMode is set; unset adds no [features] table
[features]
fast_mode = true

Le fast_mode injecté suit le réglage à trois états fastMode : true écrit fast_mode = true, false écrit fast_mode = false, et une valeur non définie laisse tout fast_mode existant intact sans ajouter de table [features].

Le proxy écoute sur le port 10100 par défaut et sert POST /v1/responses, POST /v1/responses/compact, POST /v1/images/generations, POST /v1/images/edits, GET /v1/models, GET /healthz et la surface de gestion /api/*.

L’outil image_gen intégré à Codex ne passe pas par /v1/responses : l’extension codex-rs envoie directement une requête POST à {base_url}/images/generations (ou à /images/edits lorsque des images de référence sont jointes), avec la même authentification Bearer ChatGPT que pour le chat. Comme le base_url injecté pointe vers opencodex, le proxy relaie ces appels au service OpenAI en amont.

Ce mécanisme est distinct de l’Image Bridge, qui ne s’active que lorsqu’un tour Responses déclare l’outil hébergé image_generation alors qu’un modèle autre qu’OpenAI est sélectionné. Les appels autonomes /images/generations n’entrent jamais dans ce pont.

  • Un seul candidat au transfert, selon le mode : Pool sélectionne un compte principal ou ajouté éligible ; Direct utilise le jeton Bearer OAuth de l’appelant. Le mode configuré s’applique uniformément à la requête d’image.
  • Fournisseur OpenAI à clé API : il n’est utilisé que lorsqu’aucun candidat au transfert n’est responsable d’un échec d’authentification. Un identifiant Pool défaillant ou expiré n’est jamais masqué par une utilisation de l’API facturée séparément.
  • Fournisseur personnalisé explicite : définissez images.provider sur l’identifiant d’un fournisseur openai-responses personnalisé à clé API dont le point de terminaison implémente l’API OpenAI Images. Une sélection explicite échoue sans repli et ne se rabat jamais sur un autre service en amont payant. Les identifiants de fournisseur gérés par le registre ne sont pas acceptés ici ; omettez images.provider pour utiliser les niveaux OpenAI intégrés.
  • Repli Google Antigravity (CCA) : lorsqu’aucun candidat au transfert OpenAI ni fournisseur à clé n’est configuré, /v1/images/generations — mais pas /images/edits — se rabat sur le point de terminaison Antigravity Cloud Code Assist avec le modèle gemini-3.1-flash-image. Ce repli se déclenche aussi après un échec de résolution de l’authentification OpenAI, par exemple en cas d’identifiant ChatGPT absent ou expiré, et pas seulement lorsqu’aucun candidat OpenAI n’est configuré. Il nécessite ocx login google-antigravity ; le jeton OAuth n’est envoyé qu’à l’hôte de registre CCA épinglé, jamais à une substitution baseUrl de la configuration. La réponse conserve la forme {created, data:[{b64_json}]} attendue par Codex.
  • Aucun des deux : le proxy renvoie une erreur explicite plutôt qu’une erreur 404 générique. Les fournisseurs routés (Cursor, Gemini, Kiro, …) ne peuvent pas assurer le relais de l’outil image_generation. Si vous ne souhaitez pas proposer cet outil, désactivez-le dans Codex avec codex features disable image_generation ([features] image_generation = false dans config.toml).

La déclaration de l’outil accompagne toujours la requête Responses du modèle. Pour les fournisseurs Responses à clé API, opencodex convertit l’espace de noms privé image_gen de Codex en un alias accepté en amont, image_gen__<inner-name> (par exemple image_gen__imagegen). Lorsque cet alias exploitable remplace la déclaration du client, opencodex retire toute déclaration hébergée image_generation en double. Il remappe l’appel de fonction vers l’espace de noms explicite image_gen avant que Codex ne le reçoive, puis réencode l’appel natif lorsque l’historique est rejoué ultérieurement en amont. La génération d’images côté client reste ainsi appelable sur les services compatibles avec l’API publique qui réservent cet espace de noms ou refusent les noms de fonction contenant un point. Le mode de transfert ChatGPT reste inchangé et conserve sa forme native Responses Lite.

Pour une passerelle personnalisée compatible OpenAI, configurez un fournisseur dédié et sélectionnez-le uniquement pour les requêtes Images autonomes :

{
"providers": {
"custom-images": {
"adapter": "openai-responses",
"baseUrl": "https://gateway.example.com/v1",
"authMode": "key",
"apiKey": "${IMAGE_GATEWAY_API_KEY}"
}
},
"images": {
"provider": "custom-images",
"timeoutMs": 300000
}
}

Le point de terminaison personnalisé doit accepter POST /v1/images/generations et /v1/images/edits, puis renvoyer la structure de réponse OpenAI Images attendue par Codex. La clé configurée pour le fournisseur remplace le jeton Bearer de l’appelant avant l’envoi de la requête en amont.

Remarque : ce passage concerne uniquement l’outil Codex image_generation — le relais /images/generations. Les modèles Gemini capables de produire des images les génèrent directement dans la réponse au moyen de l’adaptateur google (avec responseModalities: ["TEXT", "IMAGE"]), indépendamment de ce relais. Consultez la page Adaptateurs.

Lorsque hostname ne désigne pas l’interface de bouclage, Codex doit envoyer l’en-tête d’authentification API généré. L’injecteur utilise donc un fournisseur dédié :

# 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_key = "OPENCODEX_API_AUTH_TOKEN"
# supports_websockets = true # only when config.websockets is true

Lorsque OpenCodex gère le routage, les deux modes écrivent $CODEX_HOME/opencodex.config.toml comme configuration de référence et de repli. Sur l’interface de bouclage, ce fichier contient les clés racine que vous pouvez fusionner manuellement si l’injection automatique a été supprimée ; hors bouclage, il contient la forme avec fournisseur dédié. Le mode de fournisseur externe laisse ce profil intact.

La CLI, la TUI, l’application et le SDK Codex utilisent tous le même répertoire personnel Codex. opencodex le détermine à partir de CODEX_HOME, avec ~/.codex comme valeur de repli, et gère les fichiers suivants :

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

Sous WSL, si CODEX_HOME n’est pas défini et que ~/.codex/config.toml n’existe pas côté Linux, opencodex recherche également un unique répertoire personnel de Codex Desktop pour Windows à l’emplacement /mnt/c/Users/*/.codex/config.toml. S’il trouve exactement un candidat, il utilise ce répertoire afin que le mode app-server sous WSL et Codex Desktop sous Windows partagent les mêmes fichiers de configuration et d’authentification. Définissez explicitement CODEX_HOME pour désactiver cette détection.

Codex peut conserver l’état de ses fils dans un répertoire SQLite distinct. Pour les opérations d’historique, OpenCodex applique le même ordre de priorité que Codex : la clé racine sqlite_home de config.toml, puis CODEX_SQLITE_HOME, puis le répertoire CODEX_HOME effectif. Les chemins SQLite relatifs sont résolus depuis le répertoire de travail courant. Lorsqu’une valeur explicite de CODEX_SQLITE_HOME est présente pendant l’installation ou la réparation du service, le lanceur persistant enregistre son chemin absolu au moment de l’installation, afin que le proxy d’arrière-plan continue d’utiliser la même base de données. Si config.toml ou sa clé racine sqlite_home est absent, OpenCodex poursuit avec les valeurs de repli de l’environnement et du répertoire personnel. Si le fichier est illisible ou impossible à analyser, ou si la clé existe mais est vide ou n’est pas une chaîne, la résolution du répertoire SQLite s’arrête afin de ne pas risquer d’effectuer des opérations d’historique sur une autre base de données.

Sous Windows, un shell Orca peut définir à la fois CODEX_HOME et ORCA_CODEX_HOME sur le répertoire personnel de l’environnement d’exécution intégré à Orca, alors que l’application ChatGPT/Codex continue de lire %USERPROFILE%\\.codex. ocx status et ocx doctor signalent précisément cette divergence et affichent des chemins cibles expurgés. Si le service d’arrière-plan a été installé depuis ce shell Orca, désinstallez-le d’abord depuis le shell d’origine. Définissez ensuite CODEX_HOME sur le répertoire de l’application, supprimez ORCA_CODEX_HOME, relancez la synchronisation ou la restauration, puis réinstallez le service.

En mode fournisseur dédié, requires_openai_auth = true maintient les surfaces de l’application et de la TUI Codex soumises à un compte, comme dans Codex natif. opencodex sert également /v1/responses par WebSocket. Le fournisseur dédié n’annonce supports_websockets = true que lorsque "websockets": true. Sur l’interface de bouclage, le fournisseur intégré de Codex peut tenter WebSocket en premier ; si cette fonction est désactivée, le proxy renvoie 426 et Codex se rabat sur HTTP/SSE.

La configuration de bouclage par défaut conserve l’étiquette du fournisseur natif openai de Codex sur les nouveaux fils ; la reprise normale de l’historique ne nécessite donc aucun remappage. La synchronisation et la restauration n’appliquent qu’un manifeste de sauvegarde correspondant et rétablissent exactement le fournisseur, la source et l’indicateur d’événement d’origine. Une ligne opencodex sans manifeste reste inchangée ; utilisez ocx recover-history --legacy-openai --yes uniquement pour forcer explicitement ce réétiquetage hérité. Cette commande est volontairement large : elle réétiquette en openai chaque fil contenant un message utilisateur et actuellement marqué opencodex, normalise exec en cli et active l’indicateur d’événement — y compris l’historique légitime d’un fournisseur dédié. Sauvegardez l’état et ne l’utilisez que si vous souhaitez cette portée complète. Hors bouclage, le mode fournisseur dédié continue de refléter l’historique sous le fournisseur opencodex tant qu’il est actif, puis restaure les métadonnées sauvegardées lorsqu’il prend fin. Définissez syncResumeHistory: false pour ne pas modifier l’historique.

Codex affiche les modèles provenant d’un catalogue sur disque — par défaut $CODEX_HOME/opencodex-catalog.json. Au démarrage et lors de ocx sync, opencodex :

  1. Sauvegarde une fois le catalogue d’origine dans ~/.opencodex/catalog-backup.json, afin que la mise en avant des modèles soit réversible.
  2. Récupère les catalogues en direct des fournisseurs admissibles — mise en cache pendant ~5 min, puis repli sur la dernière liste valide et enfin sur la valeur configurée de models[]. L’authentification par transfert ne possède aucun point de terminaison de modèles, et Cursor utilise son appel RPC GetUsableModels plutôt que /models.
  3. Fusionne les modèles routés sous forme d’entrées qualifiées (provider/model), clonées depuis un modèle de catalogue Codex natif afin que l’analyseur strict de Codex les accepte.
  4. Filtre config.disabledModels et la liste d’autorisation selectedModels non vide de chaque fournisseur.
  5. Reclasse les modèles afin que ceux mis en avant apparaissent en premier — voir ci-dessous — puis réécrit le catalogue fusionné.

L’identité GPT-5 des entrées routées du catalogue est également remplacée par le véritable nom du modèle en amont. Les contrôles de raisonnement proviennent des métadonnées du fournisseur et du modèle selon l’échelle low | medium | high | xhigh | max | ultra de Codex ; les valeurs non prises en charge sont converties ou plafonnées avant l’envoi de la requête en amont.

Les lignes non natives du catalogue routé utilisent tool_mode: "code_mode_only". Codex peut ainsi exposer son point d’entrée officiel exec et les outils MCP imbriqués, notamment Browser et Computer Use, tandis qu’opencodex ne route que l’appel de fonction ordinaire du modèle. L’exécution des outils, les autorisations et les confirmations restent locales à Codex ; opencodex n’implémente pas un second navigateur ni un second exécuteur de contrôle du bureau.

Pour les fournisseurs Responses à clé qui n’acceptent pas la grammaire de l’outil personnalisé exec de Codex, opencodex encode cette déclaration et son historique sous forme d’outil de fonction en amont, puis restaure le cycle de vie diffusé de l’appel de fonction en custom_tool_call avant que Codex ne le reçoive. Le routage natif par transfert OpenAI et l’outil personnalisé apply_patch, qui est pris en charge, restent inchangés.

Avant le premier appel, les tours routés en mode code reçoivent aussi les règles de l’hôte pour les outils auxiliaires imbriqués : tools.apply_patch prend une seule chaîne qui commence et se termine par les lignes de marqueur de patch seules, sans habillage ; l’isolate ne dispose pas de import, et les commandes longues sont interrogées via write_stdin. Lorsqu’un résultat exec en mode code sur le chemin natif Responses routé, Kiro ou Cursor contient encore l’un des messages d’échec de l’hôte, opencodex ajoute une indication d’une ligne qui nomme la règle. Cette modification ne réécrit ni le code du modèle ni le texte de son patch.

Le fournisseur sélectionné doit prendre en charge les appels de fonctions ou d’outils. Un fournisseur purement textuel dépourvu de cette prise en charge ne peut pas utiliser exec, Browser ni Computer Use. Les lignes OpenAI natives conservent leur mode d’outil en amont.

Après toute modification de ces métadonnées par ocx sync, redémarrez l’application Codex et ouvrez une nouvelle tâche. Les processus app-server et les tâches existants peuvent conserver le catalogue et le plan d’outils chargés au démarrage.

Un modèle personnalisé peut posséder un nom d’affichage lisible qui remplace le libellé présenté par Codex dans son sélecteur de modèles, sans modifier le routage. Ce nom ne renseigne que le champ display_name de l’entrée du catalogue : l’identifiant de routage (<provider>/<model>), l’ordre de résolution des collisions d’alias, le fournisseur et les noms commerciaux natifs d’OpenAI restent inchangés.

Ajoutez un nom d’affichage depuis la CLI ; si le proxy est actif, il synchronise immédiatement le catalogue :

Terminal window
ocx models add deepseek deepseek-v4 --display-name "DeepSeek V4" --context-window 128000

Les clients Codex distants peuvent récupérer le même catalogue généré avec une clé ordinaire du plan de données — le même identifiant que celui utilisé pour /v1/responses, et non un jeton de gestion ou d’administration :

Terminal window
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
&& mv "$tmp" "$dest"
ocx sync-cache

La réponse contient le document opencodex-catalog.json brut, sans identifiants de fournisseur. Lorsqu’il est disponible, l’en-tête x-opencodex-codex-version indique la version de l’environnement d’exécution Codex du serveur, afin que les clients puissent détecter un écart de version.

Vous pouvez également définir ou modifier ce nom dans l’API de gestion — POST /api/custom-models ou PUT /api/custom-models/<id> avec une chaîne displayName — et dans le tableau de bord web. Le caractère / est refusé, car il entrerait en collision avec le séparateur des identifiants de routage.

GET /v1/catalog existe pour que la lecture d’une liste de modèles ne coûte pas un jeton d’administration. La route est en lecture seule (GET et HEAD), accepte x-opencodex-api-key, un jeton bearer ou x-api-key, et renvoie exactement les mêmes octets que la route de gestion. Les réponses portent un ETag fort — renvoyez-le dans If-None-Match pour revalider et obtenir un 304 — et Cache-Control: private, no-cache. Une clé du plan de données admise ici n’obtient rien sur le plan de gestion : /api/catalog et toutes les routes /api/* exigent toujours le jeton d’administration ou une session du tableau de bord.

Le nom d’affichage sert uniquement à l’affichage et reste stable entre les régénérations. À chaque ocx sync et à chaque actualisation du catalogue, opencodex reconstruit les entrées routées depuis config.json, y compris customModels ; le nom configuré est donc réappliqué au lieu de revenir à l’identifiant de routage. Un service géré tente également cette synchronisation peu après le démarrage du proxy. Si cette tentative au démarrage échoue, par exemple lors d’une connexion hors ligne, le catalogue déjà enregistré est conservé et le prochain ocx sync réussi réapplique le nom configuré. Les véritables noms natifs du service en amont, par exemple gpt-5.6-sol → “GPT-5.6-Sol”, proviennent de l’instantané amont épinglé et ne sont jamais remplacés par un nom d’affichage personnalisé.

Si config.toml sélectionne déjà un fournisseur autre que openai ou opencodex, OpenCodex ne modifie pas le fichier. Il ignore également l’écriture des profils, l’actualisation du catalogue et du cache, ainsi que la restauration immédiate ou en arrière-plan des métadonnées de l’historique Codex. Les outils qui gèrent un fournisseur personnalisé étiquettent souvent les sessions existantes avec son identifiant ; remplacer l’identifiant actif peut faire disparaître ces sessions pourtant intactes de la vue d’historique de Codex. La même protection s’applique à un fournisseur externe sélectionné par un ancien profil racine.

Confiez la configuration des fournisseurs Codex à un seul outil. Pour placer OpenCodex derrière un gestionnaire de fournisseurs existant, faites pointer ce fournisseur vers http://127.0.0.1:10100/v1 avec un transfert direct Responses — wire_api = "responses" dans le TOML Codex — et non avec une traduction Chat Completions. Lorsque l’authentification de l’API du proxy est activée, transmettez aussi l’en-tête x-opencodex-api-key depuis OPENCODEX_API_AUTH_TOKEN, comme dans la configuration hors bouclage ci-dessus. Pour autoriser OpenCodex à injecter directement le routage, rétablissez d’abord le fournisseur openai intégré de Codex, supprimez toute clé racine openai_base_url appartenant à l’utilisateur, puis relancez ocx start.

S’il manque un modèle dans Codex, ou si l’ordre ou la visibilité du catalogue semble incorrect, vérifiez les éléments suivants dans l’ordre :

  1. selectedModels sur le fournisseur — une liste d’autorisation non vide n’expose que ces identifiants à Codex ; une liste vide ou absente expose tous les modèles découverts. Un identifiant absent de la liste d’autorisation n’atteint jamais le catalogue.
  2. disabledModels au niveau supérieur — masque les modèles dans le catalogue comme dans /v1/models, et fait passer les identifiants GPT natifs non qualifiés à visibility: "hide".
  3. liveModels: false — Avec liveModels: false, si models est vide ou absent, la liste initiale commence par le defaultModel configuré, puis les identifiants de retainModels. Les doublons sont supprimés en conservant leur première occurrence. Une liste models explicite non vide est au contraire suivie de retainModels, sans ajout implicite d’un autre defaultModel. Ce dernier peut toujours être inscrit explicitement dans models ou retainModels. Si aucun de ces champs ne fournit d’identifiant, la liste initiale est vide. Cet ordre ne garantit pas l’ordre final du sélecteur. selectedModels, disabledModels et la désactivation du fournisseur restent applicables. authMode: "forward" conserve sa branche distincte et n’utilise pas cette liste statique routée. Ces règles ne changent pas le repli en cas d’échec de la découverte en direct.
  4. Cursor GetUsableModels — l’adaptateur Cursor découvre les modèles par son appel RPC protobuf GetUsableModels, et non par /models ; une modification côté Cursor peut donc changer les identifiants visibles indépendamment des autres fournisseurs.
  5. Cache et ocx sync — les catalogues en direct sont mis en cache pendant environ cinq minutes (modelCacheTtlMs, par défaut 300000). Exécutez ocx sync pour forcer une nouvelle récupération et réécrire le catalogue immédiatement.
  6. Processus Codex app-server actif — réécrire le catalogue sur disque ne suffit pas tant qu’un processus Codex app-server de longue durée — Codex Desktop ou hôte d’arrière-plan de la CLI — conserve l’ancienne liste en mémoire. ocx sync et ocx sync-cache émettent un avertissement lorsqu’ils détectent ces processus. ocx sync --restart-codex les redémarre et quitte puis relance entièrement l’application Codex Desktop sous macOS, Linux et Windows, afin que le sélecteur relise le catalogue. Pour laisser l’application Desktop ouverte, passez --restart-app-server-only ou arrêtez vous-même les processus app-server concernés.

Si Codex réessaye puis échoue avec une erreur comme stream disconnected before completion: error sending request for url (http://127.0.0.1:10100/v1/responses) — ou si Claude Code signale un échec de connexion comparable — le proxy opencodex n’est pas actif : aucun processus n’écoute sur le port configuré, et le client affiche donc lui-même cette erreur de connexion brute. Redémarrez le proxy :

Terminal window
ocx start # foreground
ocx service install # persistent: auto-starts on login and respawns on crash

ocx status indique si le proxy est actif et affiche la même suggestion de redémarrage lorsqu’il ne l’est pas ; ocx doctor évalue la sûreté du redémarrage — couverture par le service ou l’intercepteur.

La synchronisation du catalogue rend les modèles de sous-agents sélectionnés disponibles dans Codex. Consultez le sélecteur de modèles de l’application Codex pour connaître l’ordre des modèles, et la surface des sous-agents pour le comportement de la délégation v1/base/v2 et de ses mécanismes de repli.

L’ajout ou la réauthentification vérifie normalement le compte avant son enregistrement par une petite requête attendant response.completed. Le modèle par défaut est gpt-5.6-luna, avec un essai sur gpt-5.5 en cas de HTTP 400 ou HTTP 404. Les erreurs publiques contiennent des catégories fixes, sans corps de réponse brut.

Si la lecture authentifiée des quotas avec le nouveau jeton OAuth confirme un quota de 5 heures, hebdomadaire ou mensuel épuisé, le compte est enregistré sans appel au modèle et affiche Validation en attente. Il reste exclu du routage après un redémarrage ou un renouvellement du jeton. Après récupération du quota, actualisez les quotas : une lecture récente et complète avec de la capacité disponible permet une petite requête de validation. Seule sa réussite active le compte. Tout échec conserve la restriction. Les lectures passives ne déclenchent pas cette requête. Un quota inconnu à l’inscription conserve la vérification habituelle.

ocx account refresh openai et ocx account list openai --quota --refresh consultent uniquement les quotas. La validation du modèle consomme du quota et nécessite une session humaine du tableau de bord : après récupération, ouvrez ocx gui et cliquez sur Refresh quotas. Sur un hôte sans interface graphique, accédez à son tableau de bord depuis votre navigateur ; le jeton administrateur seul n’autorise pas la validation. Un compte en pause peut être validé sans être repris ni sélectionné. Les erreurs d’autorisation restent visibles jusqu’à une validation ou une réauthentification réussie.

La revalidation en arrière-plan est distincte et désactivée par défaut. Elle nécessite Token Guardian, la politique proactive du fournisseur openai et tokenGuardian.codexWarmupEnabled, et ignore les comptes dont la validation d’inscription est en attente.

Pourquoi un compte a cessé de servir les requêtes

Section intitulée « Pourquoi un compte a cessé de servir les requêtes »

Lorsqu’un compte quitte la sélection du pool, la raison accompagne la décision au lieu d’être recalculée pour l’affichage : une interface ne peut donc pas présenter un compte comme sain pendant que le routage l’écarte. GET /api/codex-auth/accounts expose reauthReason à côté de needsReauth pour chaque compte : missing_credential si aucun identifiant n’a été enregistré, refresh_failed si le renouvellement échoue de façon répétée, et quota_unauthorized si la lecture des quotas elle-même a été refusée.

Un renouvellement du compte principal qui n’aboutit pas répond toujours 503 avec Retry-After, car une nouvelle tentative peut réussir. Le message précise désormais qu’un échec persistant signifie que le compte principal doit être réauthentifié, au lieu de demander seulement de réessayer.

codexPool.excludedPlans liste les clés de forfait que la sélection automatique du pool ignore, comparées sans tenir compte de la casse au forfait enregistré sur chaque compte. Absent par défaut : une installation existante effectue exactement la même rotation qu’avant.

Terminal window
ocx config set codexPool '{"excludedPlans":["free"]}'

C’est une politique de sélection, pas un blocage. Un compte écarté conserve ses identifiants, son historique de quota et son affinité de thread, reste visible dans la liste des comptes et demeure joignable par sélection explicite comme work/gpt-5.5. Seule la rotation automatique cesse de le choisir, y compris lorsqu’il est déjà le compte actif ou déjà lié à un thread — l’état exact que laisse un abonnement expiré.

Le compte Codex principal reste exempt de l’exclusion par forfait : le routage en mode sélection seule ne lit pas ses identifiants natifs protégés. Si tous les comptes éligibles du pool sont exclus, la sélection automatique ne renvoie aucun compte. Les routes désignant explicitement un compte restent disponibles, avec les contrôles de pause, d’authentification et de droits du modèle. La carte et le CLI affichent le forfait exclu séparément de l’état des identifiants. Il n’existe pas de réglage minimumPlan, faute d’ordre total des forfaits.

ocx stop arrête le proxy et le service d’arrière-plan installé, puis tente de restaurer Codex natif. OpenCodex retire les éléments de routage dont il peut vérifier la propriété et signale une restauration incomplète si les fichiers de configuration ne peuvent pas être récupérés en toute sécurité.

Si la configuration ou le profil actuel diffère de l’original sauvegardé et que le journal ne contient pas le hash de l’état injecté de ce fichier, la récupération automatique conserve les deux fichiers et le journal sans les modifier. Un fichier déjà identique à son original n’est pas réécrit. La réinjection d’une configuration routée refuse aussi cet état incertain ; une configuration native peut créer un nouvel instantané. Voir les règles de récupération.

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

Lorsque opencodex s’exécute comme service d’arrière-plan géré, il définit OCX_SERVICE=1 afin qu’un redémarrage déclenché par le service ne modifie pas sans cesse la configuration Codex. Seule l’exécution explicite de ocx stop ou ocx service stop restaure Codex natif.

Une transition de fournisseur peut renvoyer history_paginated_requires_native_writer si le stockage concerné prend en charge la pagination, même pour ses lignes legacy. Cette raison ne refuse plus la configuration Codex, le profil de référence ni le catalogue de modèles. ocx sync et ocx start écrivent toujours ces fichiers et définissent model_catalog_json, afin que le sélecteur de modèles Codex continue d’afficher tous les modèles routés par OpenCodex. Seule cette raison interrompt le réétiquetage de l’historique des conversations, car Codex attribue les numéros d’historique paginé dans son propre processus d’écriture et aucune nouvelle tentative n’y change rien. Toute autre raison de contrôle préalable de l’historique — une base d’état illisible, un historique dont l’identité a changé, ou un contrôle préalable qui n’a pas pu s’exécuter — refuse encore toute la transition et l’annule, car ces cas peuvent réussir plus tard. Dans cet état, OpenCodex ne modifie jamais les fichiers d’historique paginé ni les lignes de conversation. Les conversations existantes conservent le fournisseur déjà associé et ne sont pas migrées ; les nouvelles conversations passent par le proxy. Lorsque le réétiquetage est interrompu, une table [model_providers.opencodex] déjà présente dans le répertoire d’accueil est conservée plutôt que retirée, y compris sous la forme root-override (loopback), afin que les conversations dont les lignes sont étiquetées opencodex gardent un identifiant de fournisseur qui existe encore. Le CLI affiche Codex resume history: left to Codex's native writer (history_paginated_requires_native_writer). ocx restore et la suppression de la configuration Codex refusent toujours sur history_paginated_requires_native_writer. Retirer la définition [model_providers.opencodex] alors que des lignes de conversation la référencent encore rendrait ces conversations irrésolubles, et le chemin de restauration n’a aucun moyen de conserver une table de fournisseur de compatibilité. Un répertoire d’accueil déjà paginé ne peut pas actuellement être désinstallé par le produit ; c’est un travail ouvert connu, et non le comportement voulu.

Ne réécrivez pas un historique paginé actif ni une ligne de conversation pour forcer une migration. Fermez la conversation avant toute récupération et signalez l’erreur exacte et les versions sans publier de données privées. Une sauvegarde ou le succès d’un script ne prouve pas le rétablissement de l’affichage : vérifiez la conversation après réouverture de Codex.