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 Authentication

Loads and refreshes the local Codex CLI ChatGPT credentials.

module Request

Converts OpenAI Chat Completions requests into Codex Responses input.

module Response

Converts Codex Responses API results into OpenAI Chat Completions.

module Responses

Applies the Codex-specific settings while preserving the Responses API payload.

module ServerSentEvents

Incrementally 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 nil when 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 :authentication Interface(:credentials) | Nil

A credential source.

option :codex_home String

The Codex home directory containing auth.json.

option :client_version String | Nil

The Codex CLI version used for model discovery; defaults to CODEX_CLIENT_VERSION or codex --version.

option :endpoint String | Async::HTTP::Endpoint

The Codex backend endpoint.

option :client Interface(: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 request Protocol::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