Files
molecule-ai-workspace-templ…/config.yaml
infra-runtime-be 80237bcabc
CI / Adapter unit tests (push) Successful in 35s
CI / Template validation (static) (push) Successful in 40s
CI / Adapter unit tests (pull_request) Successful in 32s
CI / Template validation (static) (pull_request) Successful in 1m25s
CI / Template validation (runtime) (push) Successful in 2m43s
CI / T4 tier-4 conformance (live) (push) Successful in 2m40s
CI / T4 tier-4 conformance (live) (pull_request) Successful in 50s
CI / validate (push) Successful in 9s
CI / Template validation (runtime) (pull_request) Successful in 3m13s
CI / validate (pull_request) Successful in 4s
feat(codex): YAML-driven provider abstraction — replace hardcoded minimax script
Replace the hardcoded codex_minimax_config.sh single-provider routing
with a generic providers: registry in config.yaml and a Python adapter
layer (provider_config.py) that resolves the picked provider against
the env + writes ~/.codex/config.toml accordingly. Shape mirrors the
claude-code template's provider registry / _resolve_provider /
_project_vendor_auth pattern (PR template-claude-code#24), adapted to
codex's file-based config (config.toml + auth.json) rather than the
Anthropic SDK's env-var contract.

Three auth modes supported in the registry:
  - chatgpt_subscription  (CODEX_AUTH_JSON / CODEX_CHATGPT_AUTH_JSON)
  - openai_api            (OPENAI_API_KEY)
  - openai_compat_responses (third-party Responses-API endpoints +
                             vendor env key, e.g. MiniMax token-plan)

Resolution honors the verified prod precedence from PR#11: when a
subscription credential is present it wins over a model-prefix match,
so prod-Reviewer / prod-Researcher workspaces with both CODEX_AUTH_JSON
and MINIMAX_API_KEY set continue to route through the subscription
(NO model_provider override → built-in OpenAI/Responses path). The
verified gpt-5.5 + 5.4 + 5.3-codex roster is preserved unchanged.

Backward compat: codex_minimax_config.sh stays in the image as a
fallback for one release so external ops scripts + the existing test
fixtures that exec it directly keep working; start.sh prefers the new
python helper when available.

Adding a new codex-compatible provider is now a one-entry config.yaml
edit instead of a code change in the boot scripts.

Tests:
  - tests/test_provider_abstraction.py (new, 16 cases) — registry load,
    resolution precedence (subscription / explicit / model-prefix /
    credential-aware), render output for each auth mode, idempotent
    write + stale-override cleanup, fail-closed on misconfigured entry.
  - tests/test_modernization_pr1.py updated: roster assertion relaxed
    from equality to "verified OpenAI set is a subset of the model
    list" (the multi-provider abstraction adds third-party entries
    alongside the OpenAI roster); per-model required_env validated
    against the providers registry rather than hardcoded to
    OPENAI_API_KEY.

Prior art:
  - template-claude-code config.yaml providers registry +
    adapter.py _load_providers / _resolve_provider / _project_vendor_auth
  - OpenClaw multi-provider routing (internal#440)
  - PR#11 subscription-wins-over-minimax precedence (internal#513)

Tracks internal#514. NOT a fix for the MiniMax Chat-vs-Responses
incompatibility on CLI 0.130 — that remains a downstream-vendor gap
and is now data in the YAML registry (wire_api: responses) so a future
shim flips a YAML field rather than touching boot scripts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 13:18:50 -07:00

197 lines
8.8 KiB
YAML

name: OpenAI Codex CLI
description: >-
OpenAI Codex CLI (@openai/codex) wrapped as a Molecule workspace runtime.
Each session holds a long-lived `codex app-server` child + one thread,
so A2A messages process in-order with full conversation continuity —
no fresh subprocess per turn.
Three auth paths are supported (adapter picks at boot via the
`providers:` registry below):
A. Codex/ChatGPT subscription via CODEX_AUTH_JSON (auth.json blob;
preferred when present — overrides the model-prefix match so a
workspace with both a subscription and a vendor key like
MINIMAX_API_KEY routes to the subscription as intended).
B. Direct OpenAI API key via OPENAI_API_KEY (codex's documented
pay-as-you-go fallback).
C. Third-party endpoint serving the OpenAI Responses API on a
vendor-specific base_url + env key (e.g. MiniMax token-plan).
Add a new such provider by appending one entry to `providers:` —
no adapter or boot-script code changes needed.
version: 0.2.0
tier: 2
# Provider registry — single source of truth for codex provider routing.
# The adapter reads this list at boot, resolves the picked model + env
# credentials to a provider entry, and renders ~/.codex/config.toml
# accordingly (no override for built-in OpenAI auth modes; a
# [model_providers.<slug>] block for openai_compat_responses).
#
# Adding a new provider = one entry below. The boot scripts stay
# generic and open-source-friendly: vendor URLs and env-var names are
# public/documented (e.g. api.openai.com, api.minimax.io), with no
# deployer-specific infrastructure baked into the template.
#
# Schema per entry:
# name : human-readable label (used in boot banner).
# auth_mode : one of
# chatgpt_subscription — auth.json blob via CODEX_AUTH_JSON
# (or CODEX_CHATGPT_AUTH_JSON alias);
# no config.toml model_provider override
# so codex uses its native OpenAI/Responses
# provider, with the model picked via
# thread/start from runtime_config.model.
# openai_api — direct OpenAI key via OPENAI_API_KEY;
# same "no override" shape as above.
# openai_compat_responses — third-party Responses-API endpoint;
# adapter renders a [model_providers.<slug>]
# block + model_provider = "<slug>" pin.
# model_prefixes : lowercase model-id prefixes for routing match.
# model_aliases : exact lowercase model ids for routing match.
# base_url : null for built-in OpenAI modes; HTTPS URL for
# openai_compat_responses.
# auth_env : env-var names the adapter checks for satisfied
# credentials. First non-built-in entry is the
# "env_key" emitted to config.toml for compat
# providers.
# wire_api : optional; defaults to "responses". CLI 0.130
# removed the "chat" variant — only "responses"
# is parse-valid today. Left in registry so a
# future shim re-introducing a chat-style wire
# is a YAML edit.
# model_provider_slug : optional TOML slug; defaults to `name` if
# absent.
# model_id_override : optional model id to write into config.toml
# when the wire-protocol model name differs
# from the canvas-shown id (e.g. MiniMax's
# codex-MiniMax-M2.7 vs the generic gpt-* line).
providers:
- name: openai-subscription
auth_mode: chatgpt_subscription
model_prefixes: [gpt-]
model_aliases: []
base_url: null
# CODEX_AUTH_JSON wins over the older CODEX_CHATGPT_AUTH_JSON alias
# when both are set (preserves the pre-existing precedence).
auth_env: [CODEX_AUTH_JSON, CODEX_CHATGPT_AUTH_JSON]
- name: openai-api
auth_mode: openai_api
model_prefixes: [gpt-]
model_aliases: []
base_url: null
auth_env: [OPENAI_API_KEY]
# MiniMax token-plan codex CLI route. The endpoint is documented at
# platform.minimax.io/docs/token-plan/codex-cli. KNOWN LIMITATION:
# MiniMax's token-plan endpoint serves OpenAI Chat-Completions, NOT
# the Responses API. CLI 0.130 hard-removed the `chat` wire variant,
# so this leg parses + boots cleanly under wire_api = "responses" but
# the runtime call to /v1/responses 404s on MiniMax's side. The
# registry entry stays in the open-source default so any deployer
# that adds a Responses-supporting MiniMax variant (proxy / future
# MiniMax feature) just sets MINIMAX_API_KEY and works — no code
# change. Tracked as a downstream-vendor gap, not a template defect.
- name: minimax-token-plan
auth_mode: openai_compat_responses
model_prefixes: [codex-minimax-, minimax-codex-, minimax-]
model_aliases: []
base_url: https://api.minimax.io/v1
auth_env: [MINIMAX_API_KEY]
wire_api: responses
model_provider_slug: minimax
model_id_override: codex-MiniMax-M2.7
runtime: codex
runtime_config:
# Default codex model. Pass-through to `thread/start`'s `model`
# field; codex resolves the rest. `gpt-5.5` is codex 0.130's own
# `thread/start` default (verified live 2026-05-17 against
# codex-cli 0.130.0 linux/amd64: thread/start returned
# "model":"gpt-5.5"). The prior `gpt-5` default was a DEAD id —
# there is no plain `gpt-5` in the May-2026 codex roster, so a
# workspace on the OpenAI leg failed/hung the first turn. Roster
# below is the verified May-2026 set (OpenAI Codex Models +
# Configuration Reference). Tracks codex CLI releases — bump
# deliberately alongside the @openai/codex pin (RFC §1, §6).
model: gpt-5.5
# Models surfaced in the canvas Config tab dropdown. Per-entry
# required_env follows the picked auth path: gpt-* lines accept
# either CODEX_AUTH_JSON (subscription) or OPENAI_API_KEY (direct).
# MiniMax codex entries route through the `minimax-token-plan`
# provider (see top-level `providers:` registry) and require
# MINIMAX_API_KEY only. The adapter resolves the actual provider
# from this list + the env at boot; required_env here drives the
# canvas validation hint, not the resolution itself.
models:
- id: gpt-5.5
name: GPT-5.5 (OpenAI subscription or API key)
required_env: [OPENAI_API_KEY]
- id: gpt-5.4
name: GPT-5.4 (OpenAI subscription or API key)
required_env: [OPENAI_API_KEY]
- id: gpt-5.4-mini
name: GPT-5.4 mini (OpenAI subscription or API key)
required_env: [OPENAI_API_KEY]
- id: gpt-5.3-codex
name: GPT-5.3 Codex (OpenAI subscription or API key)
required_env: [OPENAI_API_KEY]
- id: gpt-5.3-codex-spark
name: GPT-5.3 Codex Spark (OpenAI subscription or API key)
required_env: [OPENAI_API_KEY]
- id: gpt-5.2
name: GPT-5.2 (OpenAI subscription or API key)
required_env: [OPENAI_API_KEY]
# MiniMax token-plan codex route — public endpoint
# (api.minimax.io). See `providers:` registry note on the
# Chat-vs-Responses compatibility gap; entries kept so the
# canvas surfaces the option for any deployer that adds a
# Responses-supporting variant.
- id: codex-minimax-m2.7
name: MiniMax M2.7 codex (third-party token-plan)
required_env: [MINIMAX_API_KEY]
# Default required_env — the canvas surfaces this when no model is
# picked. OPENAI_API_KEY is the documented direct path; subscription
# and MiniMax paths are validated by the adapter via the registry.
required_env: [OPENAI_API_KEY]
# Provider names surfaced in the canvas Config tab dropdown. The
# actual routing decision is made in adapter.setup() against the
# top-level `providers:` registry; this list is the UI surface.
providers:
- openai-subscription
- openai-api
- minimax-token-plan
# 0 = no executor-side timeout. Per-turn timeout is enforced inside
# executor.py at _TURN_TIMEOUT (currently 600s).
timeout: 0
# codex's tool set is built-in (file ops, terminal, apply_patch, web
# fetch). No extension surface from our side today.
skills: []
a2a:
port: 8000
streaming: true
push_notifications: true
# Bridge config — consumed by executor.py.
bridge:
# codex app-server is a stdio child, not a network service. No URL
# or port to configure. Listed here for symmetry with hermes' bridge
# block; when we add overrides (e.g. custom codex binary path) they
# land here.
app_server_command: codex
app_server_args: ["app-server"]
delegation:
retry_attempts: 3
retry_delay: 5
timeout: 120
escalate: true
template_schema_version: 1