Help us shape the future of Go! Take the 2026 Go Developer Survey

codex

package
v0.8.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package codex implements agent.Adapter against OpenAI's `codex` CLI (the `codex exec` non-interactive subcommand). It mirrors agent/goose for the Launch/stream scaffold and agent/claude for the NativeSchema:true contract; the agent package itself stays import-free of harness specifics.

Capabilities().NativeSchema is TRUE: `codex exec --output-schema <FILE>` API-constrains the model's final response (OpenAI Responses structured output), so the agent_message text is pure conforming JSON. The adapter writes the step's output_schema to a container temp file (via the same sh -c command), passes --output-schema, and strict-json.Unmarshals the LAST agent_message text into a map; the engine re-validates it against output_schema (engine ValidateOutputMap). Layer 2 (free-text parsing) is never reached — codex is the first non-Claude NativeSchema:true adapter (conformance Bucket 14).

Gate independence is structural: every Launch runs a bare `codex exec` with --ephemeral and never a resume/fork subcommand; ValidateConfig rejects the corresponding with-keys.

Index

Constants

View Source
const AdapterRef = "openai/codex"

AdapterRef must match the workflow `uses:` literal byte-for-byte.

Variables

View Source
var DefaultEnvAllowlist = []string{"OPENAI_API_KEY", "CODEX_HOME"}

DefaultEnvAllowlist — env names the codex adapter forwards into each `codex exec`. Single source of truth for the CLI --agent-env default and resume's implicit allowlist. OPENAI_API_KEY overlaps goose's allowlist → defaultAgentEnv dedups (see cli/agent_registry.go). CODEX_HOME points codex at its auth.json/config dir (the ChatGPT-OAuth provisioning path). The adapter forces no env (--ephemeral handles session persistence).

Functions

This section is empty.

Types

type Adapter

type Adapter struct {
	// contains filtered or unexported fields
}

Adapter is the agent.Adapter implementation for OpenAI codex. One Adapter per CLI invocation; multiple Launch calls per Adapter; all in-memory state is read-only after construction. Each logical invocation gets an opaque isolated CODEX_HOME; only deterministic retries of that same run/node/key reuse it. Provider sessions never cross Launch boundaries (`codex exec --ephemeral`).

func New

func New(opts ...Option) (*Adapter, error)

New constructs an Adapter.

func (*Adapter) Capabilities

func (*Adapter) Capabilities() agent.Caps

Capabilities returns Caps{NativeSchema: true} — codex's --output-schema constrains generation API-side; layer 2 is never reached.

func (*Adapter) Launch

func (a *Adapter) Launch(ctx context.Context, handle container.Handle, inv agent.AgentInvocation) (<-chan agent.AgentEvent, <-chan agent.AgentOutcome, error)

Launch runs `codex exec --json ...` inside handle via the streaming Backend.Exec. codex's --json emits JSONL flushed live; Launch scans it and emits ONE Live AgentEvent per line so the engine's agentEventSink journals it immediately, records the LAST agent_message text (last-wins), captures the terminal usage + any error/turn.failed message, then sends exactly one AgentOutcome.

STREAMING GRANULARITY (accepted limitation): codex exec --json is EVENT-granular, not token-granular — each agent_message arrives as ONE complete item.completed line (no item.updated/text deltas). So events (tool calls, reasoning) render live, but the answer TEXT does NOT stream character-by-character like goose/claude. Token deltas exist only on codex's mcp-server/app-server JSON-RPC interface, which the stdin-less container.Cmd seam cannot drive. See the spec §1 streaming note.

γ contract: returns IMMEDIATELY with both channels open; events closes BEFORE outcome (defer LIFO); never reuses a session.

func (*Adapter) Ref

func (*Adapter) Ref() string

Ref returns the agent-runtime identifier this adapter satisfies.

func (*Adapter) RequiredEnv

func (*Adapter) RequiredEnv() []string

RequiredEnv implements agent.CredentialNamer. Returns the CREDENTIAL env var name codex authenticates with. OPENAI_API_KEY is defined in DefaultEnvAllowlist; CODEX_HOME is a config directory (not a credential) and is intentionally excluded.

func (*Adapter) ValidateConfig

func (a *Adapter) ValidateConfig(with ir.RawConfig) error

ValidateConfig enforces codex's with-schema (session-reject → unknown-key → required-prompt → per-key types+enums). Deterministic (sorted keys); runs twice per node (run-start walk + defensive dispatch) → idempotent. No provider-conditional auth gate: codex auth (ChatGPT-OAuth or OPENAI_API_KEY) cannot be statically probed — a missing credential surfaces as a loud turn.failed at Launch.

func (*Adapter) Version

func (a *Adapter) Version(ctx context.Context, handle container.Handle) (string, error)

Version runs `codex --version` inside handle and parses the leading semver. Recorded in run.started.Runtimes; re-resolved on resume; drift hard-errors.

type ErrRuntimeNotFound

type ErrRuntimeNotFound struct {
	Ref       string
	Container string
	Cause     error
}

ErrRuntimeNotFound — Version failed.

func (*ErrRuntimeNotFound) Error

func (e *ErrRuntimeNotFound) Error() string

func (*ErrRuntimeNotFound) Unwrap

func (e *ErrRuntimeNotFound) Unwrap() error

type ErrSessionReuseAttempted

type ErrSessionReuseAttempted struct{ Key string }

ErrSessionReuseAttempted — a with-key that would re-use a codex session, breaking gate independence (spec §5.5). Defense-in-depth: the adapter always runs bare `codex exec`, never a resume/fork subcommand.

func (*ErrSessionReuseAttempted) Error

func (e *ErrSessionReuseAttempted) Error() string

type ErrStreamParse

type ErrStreamParse struct {
	Line  []byte
	Cause error
}

ErrStreamParse backs the parse unit tests; Launch tolerates a stray non-JSON line.

func (*ErrStreamParse) Error

func (e *ErrStreamParse) Error() string

func (*ErrStreamParse) Unwrap

func (e *ErrStreamParse) Unwrap() error

type ErrUnexpectedExit

type ErrUnexpectedExit struct {
	ExitCode int
	Output   string
}

ErrUnexpectedExit is sent (bare) when codex exited with no usable result. Output is the captured stdout/diag tail. The engine default branch maps it to retryable_failure.

func (*ErrUnexpectedExit) Error

func (e *ErrUnexpectedExit) Error() string

type Option

type Option func(*Adapter)

Option configures the Adapter at construction time (functional-options).

func WithBackend

func WithBackend(b container.Backend) Option

WithBackend supplies the container.Backend used by Version and Launch.

func WithEnv

func WithEnv(env map[string]string) Option

WithEnv supplies the env-var allowlist forwarded into each `codex exec` exec environment. Copied into agent.SecretEnv (redacts under fmt verbs; json:"-" so secrets never reach the state log). Empty map permitted.

func WithPricing

func WithPricing(t pricing.Table) Option

WithPricing injects the pricing.Table used to derive a USD cost from token usage. Tests pass a self-contained fixture table; production leaves it unset so New defaults it to pricing.Default() (embedded rates ⊕ $AWF_PRICING_FILE).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL