GenAgent.Backends.Codex (GenAgentCodex v0.2.3)

Copy Markdown View Source

GenAgent.Backend implementation backed by CodexWrapper.

CodexWrapper 0.5.3 streams NDJSON while closing CLI stdin. This backend forwards translated events as they arrive, so handle_stream_event/2 can observe progress during a turn.

Session continuation

Codex reports its persistent thread identifier as thread_id in the first thread.started event of a turn, not in the terminal turn.completed event. The EventTranslator captures it and injects it into the :result event as session_id. This backend's update_session/2 then records it on the session struct, and the next turn is dispatched via ExecResume with that id.

terminate_session/1 has no native process to close. GenAgent cancels its prompt task on interrupt, watchdog, stop, or agent death, but the default Port runner closes pipes without guaranteeing that the CLI and its subprocesses have exited. Choose a runner with process-group termination when OS-level settlement is required.

Options accepted by start_session/1

Config-level (forwarded to CodexWrapper.Config.new/1):

  • :binary, :working_dir (aliased as :cwd), :env, :timeout, :verbose

Exec-level (forwarded to CodexWrapper.Exec):

  • :model, :sandbox, :approval_policy, :full_auto, :dangerously_bypass_approvals_and_sandbox, :skip_git_repo_check, :ephemeral, :config_overrides, :enabled_features, :disabled_features, :images, :output_schema

Options that cannot be preserved on exec resume (:cd, :add_dirs, :search) are rejected by start_session/1. Use :working_dir / :cwd for a directory that persists across turns. Session options are translated into supported resume arguments; :sandbox and :approval_policy use config overrides because resume does not accept their exec flags.

Backend-only:

  • :exec_fn -- a 2-arity function (prompt, session) -> {:ok, Enumerable.t()} | {:error, term()} that replaces the default Exec/ExecResume dispatch. Intended for tests.

Codex has no equivalent of Claude's --system-prompt; if you need system-level instructions, pass them via AGENTS.md in the working directory or through Codex's configuration layer.

Summary

Types

t()

@type t() :: %GenAgent.Backends.Codex{
  config: CodexWrapper.Config.t(),
  exec_fn: (String.t(), t() -> {:ok, Enumerable.t()} | {:error, term()}),
  exec_opts: keyword(),
  thread_id: String.t() | nil
}