class Codex < Interface
- Inherits from
Interface
Adapts OpenAI Chat Completions HTTP to the ChatGPT Codex Responses backend.
This experimental integration uses the Codex-specific backend, not the public OpenAI Platform API. Responses API tool calls are returned to the HTTP client; this provider never executes them.
Nested Classes and Modules
class AuthenticationLoads and refreshes the local Codex CLI ChatGPT credentials.
module RequestConverts OpenAI Chat Completions requests into Codex Responses input.
module ResponseConverts Codex Responses API results into OpenAI Chat Completions.
module ResponsesApplies the Codex-specific settings while preserving the Responses API payload.
module ServerSentEventsIncrementally decodes Codex Responses API server-sent events.
Definitions
def self.client_version
Return the configured or installed Codex CLI version.
Signature
-
returns
String | Nil The Codex CLI version, or
nilwhen it cannot be detected.
Implementation
def self.client_version
if version = ENV["CODEX_CLIENT_VERSION"]
return version unless version.empty?
end
output, status = Open3.capture2("codex", "--version")
return unless status.success?
return output[/\bcodex(?:-cli)?\s+(\S+)/, 1]
rescue Errno::ENOENT
nil
end
def initialize(authentication: nil, codex_home: ENV.fetch("CODEX_HOME", Authentication::DEFAULT_CODEX_HOME), client_version: ENV["CODEX_CLIENT_VERSION"], endpoint: DEFAULT_ENDPOINT, client: nil, **client_options)
Initialize the experimental ChatGPT Codex API adapter.
Signature
-
option
:authenticationInterface(:credentials) | Nil A credential source.
-
option
:codex_homeString The Codex home directory containing
auth.json.-
option
:client_versionString | Nil The Codex CLI version used for model discovery; defaults to
CODEX_CLIENT_VERSIONorcodex --version.-
option
:endpointString | Async::HTTP::Endpoint The Codex backend endpoint.
-
option
:clientInterface(:call) | Nil An optional HTTP client.
Implementation
def initialize(authentication: nil, codex_home: ENV.fetch("CODEX_HOME", Authentication::DEFAULT_CODEX_HOME), client_version: ENV["CODEX_CLIENT_VERSION"], endpoint: DEFAULT_ENDPOINT, client: nil, **client_options)
@endpoint = Async::HTTP::Endpoint[endpoint]
@authentication = authentication || Authentication.new(codex_home: codex_home)
@client_version = client_version
@client_version_detected = client_version && !client_version.empty?
@client = client || Async::HTTP::Client.new(@endpoint, **client_options)
@owns_client = client.nil?
end
def models
Fetch and normalize the authenticated Codex model catalog.
Signature
-
returns
Protocol::HTTP::Response The OpenAI-compatible model list.
Implementation
def models
client_version = self.client_version
unless client_version
return error_response(500, "Set CODEX_CLIENT_VERSION or install the Codex CLI to discover models", "server_error")
end
credentials = @authentication.credentials
upstream = request_models(credentials, client_version)
if upstream.status == 401
upstream.close
credentials = @authentication.credentials(refresh: true)
upstream = request_models(credentials, client_version)
end
unless upstream.status >= 200 && upstream.status < 300
return upstream
end
model_catalog_response(upstream)
rescue Authentication::Error
error_response(502, "Codex authentication failed", "server_error")
rescue StandardError
error_response(502, "Codex model discovery failed", "server_error")
end
def call(request)
Convert supported Chat Completions requests or proxy Responses requests.
Signature
-
parameter
requestProtocol::HTTP::Request The incoming OpenAI-compatible request.
-
returns
Protocol::HTTP::Response The translated or proxied response.
Implementation
def call(request)
path = request.path.split("?", 2).first
unless request.method == "POST" && %w[/v1/chat/completions /v1/responses].include?(path)
return error_response(404, "Only /v1/chat/completions and /v1/responses are supported", "not_found_error")
end
payload = JSON.parse(request.read)
return error_response(400, "Expected a JSON object", "invalid_request_error") unless payload.is_a?(Hash)
responses_api = path == "/v1/responses"
if responses_api
transformed = Responses.prepare(payload)
else
if payload["n"] && payload["n"] != 1
return error_response(400, "Codex Chat Completions supports n=1 only", "invalid_request_error")
end
if chat_tools?(payload)
return error_response(400, "Codex tool turns require the /v1/responses endpoint", "invalid_request_error")
end
transformed = Request.transform(payload)
end
credentials = @authentication.credentials
upstream = request_codex(transformed, request, credentials)
if upstream.status == 401
upstream.close
credentials = @authentication.credentials(refresh: true)
upstream = request_codex(transformed, request, credentials)
end
unless upstream.status >= 200 && upstream.status < 300
return upstream
end
if responses_api && payload["stream"]
return upstream
elsif responses_api
return responses_response(upstream)
end
if payload["stream"]
return streaming_response(upstream, request, payload, transformed[:model])
end
return completion_response(upstream, transformed[:model])
rescue JSON::ParserError, KeyError, ArgumentError, TypeError => error
error_response(400, error.message, "invalid_request_error")
rescue Authentication::Error
error_response(502, "Codex authentication failed", "server_error")
rescue StandardError
error_response(502, "Codex provider request failed", "server_error")
end
def close
Close the HTTP client and authentication source when owned.
Implementation
def close
@client.close if @owns_client
@authentication.close if @authentication.respond_to?(:close)
end