use super::{AgentAdapter, AgentDriver, InteractivityMode};
use crate::phase_id::PhaseId;
use std::path::PathBuf;
pub struct CodexDriver;
impl AgentDriver for CodexDriver {
fn name(&self) -> &'static str {
"OpenAI Codex"
}
fn render_prompt(&self, intent: &crate::prompt::StageIntent) -> String {
crate::prompt::render_workflow_style(intent, &self.workflow_root())
}
fn build_command(
&self,
_phase: PhaseId,
prompt: &str,
extra_writable_roots: &[PathBuf],
) -> (&'static str, Vec<String>) {
let mut args: Vec<String> = vec![
"-a".into(),
"never".into(),
"exec".into(),
"--sandbox".into(),
"workspace-write".into(),
"--json".into(),
];
if !extra_writable_roots.is_empty() {
let list = extra_writable_roots
.iter()
.map(|root| {
let escaped = root
.display()
.to_string()
.replace('\\', "\\\\")
.replace('"', "\\\"");
format!("\"{escaped}\"")
})
.collect::<Vec<_>>()
.join(",");
args.push("-c".into());
args.push(format!("sandbox_workspace_write.writable_roots=[{list}]"));
}
args.push(prompt.to_string());
("codex", args)
}
fn parse_completion(&self, output: &str) -> Option<crate::agent_result::AgentResult> {
crate::agent_result::parse_codex_event_result(output)
}
fn environment(&self) -> Vec<(String, String)> {
vec![
("GIT_CONFIG_COUNT".into(), "2".into()),
("GIT_CONFIG_KEY_0".into(), "commit.gpgsign".into()),
("GIT_CONFIG_VALUE_0".into(), "false".into()),
("GIT_CONFIG_KEY_1".into(), "tag.gpgsign".into()),
("GIT_CONFIG_VALUE_1".into(), "false".into()),
]
}
fn interactivity_mode(&self, stage: crate::stage::Stage) -> InteractivityMode {
use crate::stage::Stage;
match stage {
Stage::Define | Stage::Plan => InteractivityMode::RequiresExistingArtifact,
_ => InteractivityMode::HeadlessSafe,
}
}
}
pub struct CodexAgent;
impl AgentAdapter for CodexAgent {
fn name(&self) -> &'static str {
CodexDriver.name()
}
fn exec_command(
&self,
phase: PhaseId,
prompt: &str,
extra_writable_roots: &[PathBuf],
) -> (&'static str, Vec<String>) {
CodexDriver.build_command(phase, prompt, extra_writable_roots)
}
fn extra_env(&self) -> Vec<(String, String)> {
CodexDriver.environment()
}
fn completion_signal_detected(&self, _output: &str) -> bool {
false
}
fn render_prompt(&self, intent: &crate::prompt::StageIntent) -> String {
CodexDriver.render_prompt(intent)
}
}