Skip to content

Agent Runner & Codex Adapter

The AgentRunner is the framework layer that dispatches AI workloads to provider-specific adapters. In production, CodexAdapter invokes the Codex CLI as a subprocess. In tests, FakeAgentAdapter returns pre-configured responses.

Why an adapter layer?

Stages submit typed AgentTask objects to AgentRunner. The runner selects the appropriate adapter, applies timeouts, coordinates cancellation, and returns a normalized AgentResult. This keeps stages and the framework decoupled from any specific AI provider.

CodexAdapter — the production adapter

CodexAdapter (in src/agents/adapters/codex.py) invokes the Codex CLI binary as a subprocess. Key behavior:

  1. Builds the CLI invocation with --json (streaming structured output mode), --schema for JSON-schema enforcement, and provider config flags.
  2. Inherits OPENAI_API_KEY and OPENAI_BASE_URL from the process environment (or explicitly from CodexRuntimeConfig.env).
  3. Streams output lines and emits agent_stream / agent_log events.
  4. Registers the subprocess PID with CancellationManager for forceful termination on cancellation.
  5. Parses the final JSON output and returns an AgentResult.

Local vs. AWS behavior

Context OPENAI_BASE_URL Isolation
Local dev Not set (direct OpenAI) or http://localhost:4000/v1 (llm-proxy) Subprocess in local shell
AWS scan runner https://llm-proxy.internal/v1 Subprocess in ECS container
Tests N/A FakeAgentAdapter — no subprocess

No Docker isolation is used for agents. The subprocess runs directly in the runner process.

Codex CLI flags used

Flag Purpose
--json Streaming JSON output mode
--schema <json> Enforce structured output schema
--model <id> Model identifier (from RunPolicy.model)
--model-reasoning-effort <level> "low", "medium", "high"

Cancellation

When CancellationManager.cancel_active_agent_calls() is called:

  1. CodexAdapter.cancel(task_id) sends SIGTERM to the subprocess.
  2. If the process does not exit within the grace period, SIGKILL follows.

The adapter raises CodexAdapterCancelled which the runner translates to AgentCancelled. BaseStage catches this and returns a cancelled StageOutput.

Configuration

# Required
VEGA_CODEX_BIN=/usr/local/bin/codex
OPENAI_API_KEY=sk-...

# Optional
OPENAI_BASE_URL=http://localhost:4000/v1   # vega-llm-proxy
VEGA_CODEX_REASONING_EFFORT=medium         # low | medium | high
VEGA_CODEX_COLLAB=true
VEGA_CODEX_CWD=/tmp/codex-workdir

See Configuration for the full variable list.

Debugging agent calls

  1. Check agent_started and agent_completed / agent_failed events.
  2. Set VEGA_CODEX_REASONING_EFFORT=high for better output quality at higher cost.
  3. Check agent_log events for raw subprocess output lines.
  4. Confirm OPENAI_API_KEY and OPENAI_BASE_URL are set correctly.
  5. Run the manual debug runner: python tests/manual/e2e_scan_debug.py.

Comparison: old vs. new

Old architecture New architecture
codex binary called directly from stage scripts CodexAdapter via AgentRunner interface
Codex isolation via Docker Direct subprocess (no Docker wrapper)
Stage-specific Codex invocation logic Common invocation in CodexAdapter.run()
Cancellation by subprocess pid in stage Cancellation registered with CancellationManager
No adapter abstraction AgentAdapter protocol → multiple adapters
FakeCodexRunner ad-hoc FakeAgentAdapter in testing/