Documentation
¶
Overview ¶
Package codex implements a native client for the Codex Responses API — the same backend the Codex CLI / Codex Desktop talk to (POST https://chatgpt.com/backend-api/codex/responses).
It is a Go port of the proxy core of https://github.com/icebear0828/codex-proxy: it authenticates with a ChatGPT account (OAuth access token, refreshed as needed), translates an OpenAI-style chat request into the Codex Responses wire format, streams the Server-Sent-Events response back, and translates the events into plain text + tool calls + usage.
Unlike codex-proxy this does not stand up an HTTP server; it is an in-process client so karma can use a ChatGPT subscription as just another model provider.
Index ¶
- Constants
- func IsRetryable(err error) bool
- func ParseModelName(input string) (modelID, serviceTier, effort string)
- type APIError
- type Client
- type Config
- type ContentPart
- type InputItem
- type Message
- type ModelInfo
- type Reasoning
- type RequestOptions
- type ResponsesRequest
- type Result
- type SSEEvent
- type TextFormat
- type TokenSource
- type Tool
- type ToolCall
- type Usage
Constants ¶
const ( // DefaultOAuthClientID is the public OAuth client id used by Codex (and // codex-proxy) for the refresh-token grant. DefaultOAuthClientID = "app_EMoamEEZ73f0CkXaXp7hrann" // DefaultOAuthTokenEndpoint is the OpenAI OAuth token endpoint. DefaultOAuthTokenEndpoint = "https://auth.openai.com/oauth/token" )
const DefaultBaseURL = "https://chatgpt.com/backend-api"
DefaultBaseURL is the Codex backend the Codex CLI / Desktop use.
Variables ¶
This section is empty.
Functions ¶
func IsRetryable ¶
IsRetryable reports whether err (or anything it wraps) is a transient *APIError. HTTP- and stream-layer Codex failures both flow through APIError, so this is the single retry signal for the Codex provider.
func ParseModelName ¶
ParseModelName splits a model string into its base id and any trailing service-tier / reasoning-effort suffixes.
Types ¶
type APIError ¶
type APIError struct {
Status int
Body string
Headers http.Header // response headers, when from an HTTP response
}
APIError is returned for non-2xx HTTP responses and for mid-stream `error` / `response.failed` events from the Codex backend. Stream events are mapped to an HTTP-equivalent Status (see statusForCode) so callers can apply one consistent retry/recovery policy — mirroring codex-proxy's codexApiErrorFromEvent.
func (*APIError) IsCloudflareChallenge ¶
IsCloudflareChallenge reports whether the response is a Cloudflare bot challenge (vs. an application error). Port of codex-proxy's isCfChallengeError: a 403/503 whose body or headers carry CF challenge markers.
func (*APIError) RetryAfter ¶
RetryAfter returns how long to wait before retrying, from the Retry-After header or the error body's resets_in_seconds / resets_at (Codex 429s), or 0.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to the Codex Responses API on behalf of a ChatGPT account.
func Shared ¶
Shared returns a process-wide cached Client for the given config so the session cookie jar (cf_clearance / __cf_bm), warmup state, and token-refresh state stay warm across calls — the single-process analogue of codex-proxy's long-lived account sessions. Falls back to a fresh client on cache miss.
func (*Client) CreateResponse ¶
CreateResponse POSTs a streaming Responses request over HTTP and returns the raw response. The caller owns response.Body and must Close it. Non-2xx responses are returned as *APIError. Prefer Generate, which adds the WebSocket transport + consumption.
func (*Client) Generate ¶
func (c *Client) Generate(ctx context.Context, req *ResponsesRequest, onText, onReasoning func(string) error) (*Result, error)
Generate runs a Responses request over the most reliable available transport and consumes the stream, returning the fully collected Result. onText / onReasoning, when non-nil, receive streamed deltas.
WebSocket is tried first — it is the transport codex-proxy uses for its primary endpoints and the one the backend advertises via prefer_websockets; the HTTP-SSE POST path is markedly more prone to transient 502s. On a WebSocket *transport* failure (before any output) it transparently falls back to HTTP SSE. A genuine upstream API error (rate limit, etc.) is surfaced as *APIError and not retried over the other transport.
func (*Client) ListModels ¶
ListModels discovers the models available to the account by probing the same Codex backend endpoints the Codex CLI uses, returning the flattened list. It returns an empty slice (no error) if the backend exposes no discovery endpoint — any model the account supports can still be requested by id.
type Config ¶
type Config struct {
BaseURL string
Originator string
AppVersion string
UserAgent string // full User-Agent override; default derived from host
Residency string // x-openai-internal-codex-residency override
ClientID string // OAuth client id (refresh grant)
TokenEndpoint string // OAuth token endpoint
HTTPClient *http.Client
DisableWebSocket bool // force HTTP-SSE transport (skip the WebSocket primary)
}
Config configures a Client. Zero values fall back to sensible defaults and the CODEX_* environment variables.
type ContentPart ¶
type ContentPart struct {
Type string `json:"type"` // "input_text" | "input_image"
Text string `json:"text,omitempty"` // for input_text
ImageURL string `json:"image_url,omitempty"` // for input_image (url or data: URI)
}
ContentPart is a single part of a multimodal user message.
type InputItem ¶
type InputItem struct {
Type string `json:"type,omitempty"`
Role string `json:"role,omitempty"`
Content any `json:"content,omitempty"`
CallID string `json:"call_id,omitempty"`
Name string `json:"name,omitempty"`
Arguments string `json:"arguments,omitempty"`
Output string `json:"output,omitempty"`
}
InputItem is one entry in the Responses `input` array. It is intentionally a flat struct covering every item shape the Codex API accepts:
- message: {role, content} (Type == "")
- function_call: {type, call_id, name, arguments}
- function_call_output: {type, call_id, output}
Content is either a string or a []ContentPart (for images).
type Message ¶
type Message struct {
Role string // "user" | "assistant" | "system" | "developer" | "tool"
Content string
Images []string // image URLs or data: URIs (user messages)
ToolCalls []ToolCall // assistant tool calls to replay
ToolCallID string // tool result correlation id
}
Message is a provider-agnostic chat message used to build a Responses request.
type ModelInfo ¶
type ModelInfo struct {
ID string
DisplayName string
Description string
SupportedReasoningEfforts []string
}
ModelInfo describes a model available to the authenticated account.
type Reasoning ¶
type Reasoning struct {
Effort string `json:"effort,omitempty"`
Summary string `json:"summary,omitempty"`
}
Reasoning controls reasoning effort + summary mode on the Responses API.
type RequestOptions ¶
type RequestOptions struct {
Model string
Instructions string // collected system/developer text
Messages []Message
Tools []Tool
ToolChoice any
ReasoningEffort string // explicit override; suffix on Model is used otherwise
ServiceTier string // explicit override; suffix on Model is used otherwise
}
RequestOptions describes a Codex Responses request in protocol-neutral terms.
type ResponsesRequest ¶
type ResponsesRequest struct {
Model string `json:"model"`
Instructions string `json:"instructions,omitempty"`
Input []InputItem `json:"input"`
Stream bool `json:"stream"`
Store bool `json:"store"`
Reasoning *Reasoning `json:"reasoning,omitempty"`
ServiceTier string `json:"service_tier,omitempty"`
Tools []Tool `json:"tools,omitempty"`
ToolChoice any `json:"tool_choice,omitempty"`
ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
Text *TextFormat `json:"text,omitempty"`
PromptCacheKey string `json:"prompt_cache_key,omitempty"`
ClientMetadata map[string]string `json:"client_metadata,omitempty"`
Include []string `json:"include,omitempty"`
}
ResponsesRequest is the body POSTed to /codex/responses. The Codex backend requires stream=true and store=false, so those fields are always serialized.
func BuildRequest ¶
func BuildRequest(opts RequestOptions) *ResponsesRequest
BuildRequest translates protocol-neutral options into a CodexResponsesRequest.
type Result ¶
type Result struct {
Text string
Reasoning string
ToolCalls []ToolCall
Usage Usage
ResponseID string
}
Result is the fully-collected outcome of a (non-streaming) Codex response.
type SSEEvent ¶
type SSEEvent struct {
Event string
Data json.RawMessage
}
SSEEvent is a single parsed Server-Sent Event from the Codex stream.
type TextFormat ¶
type TextFormat struct {
Format struct {
Type string `json:"type"` // "text" | "json_object" | "json_schema"
Name string `json:"name,omitempty"`
Schema map[string]any `json:"schema,omitempty"`
Strict *bool `json:"strict,omitempty"`
} `json:"format"`
}
TextFormat carries structured-output / JSON-mode configuration.
type TokenSource ¶
type TokenSource struct {
// contains filtered or unexported fields
}
TokenSource provides a valid ChatGPT access token + account id for Codex requests, transparently refreshing the token when it is close to expiry.
It is safe for concurrent use. Tokens are loaded from (in order):
- The CODEX_ACCESS_TOKEN env var (with optional CODEX_REFRESH_TOKEN / CODEX_ACCOUNT_ID), or
- The Codex CLI auth file at $CODEX_HOME/auth.json (default ~/.codex/auth.json), supporting both the nested `tokens` object the CLI writes and a flat token layout.
On refresh the new tokens are written back to the auth file when one was the source, so the refreshed access token survives process restarts.
func NewTokenSource ¶
func NewTokenSource(clientID, tokenEndpoint string, httpClient *http.Client) (*TokenSource, error)
NewTokenSource builds a TokenSource, resolving tokens from the environment or the Codex CLI auth file. clientID/tokenEndpoint may be empty to use defaults.
func (*TokenSource) Residency ¶
func (ts *TokenSource) Residency() string
Residency returns the account's compute residency (e.g. "us"), or "" if the token does not carry the claim.
type Tool ¶
type Tool struct {
Type string `json:"type"` // "function"
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Parameters map[string]any `json:"parameters,omitempty"`
Strict bool `json:"strict,omitempty"`
}
Tool is a function tool definition in the Codex Responses format. Note the flattened shape (name/parameters at the top level) — this differs from the OpenAI Chat Completions nesting under `function`.