devflow_core/agents/
codex.rs1use super::{AgentAdapter, AgentDriver, InteractivityMode};
9use crate::phase_id::PhaseId;
10use std::path::PathBuf;
11
12pub struct CodexDriver;
16
17impl AgentDriver for CodexDriver {
18 fn name(&self) -> &'static str {
19 "OpenAI Codex"
20 }
21
22 fn render_prompt(&self, intent: &crate::prompt::StageIntent) -> String {
23 crate::prompt::render_workflow_style(intent, &self.workflow_root())
24 }
25
26 fn build_command(
27 &self,
28 _phase: PhaseId,
29 prompt: &str,
30 extra_writable_roots: &[PathBuf],
31 ) -> (&'static str, Vec<String>) {
32 let mut args: Vec<String> = vec![
33 "-a".into(),
36 "never".into(),
37 "exec".into(),
38 "--sandbox".into(),
39 "workspace-write".into(),
40 "--json".into(),
41 ];
42 if !extra_writable_roots.is_empty() {
47 let list = extra_writable_roots
48 .iter()
49 .map(|root| {
50 let escaped = root
51 .display()
52 .to_string()
53 .replace('\\', "\\\\")
54 .replace('"', "\\\"");
55 format!("\"{escaped}\"")
56 })
57 .collect::<Vec<_>>()
58 .join(",");
59 args.push("-c".into());
60 args.push(format!("sandbox_workspace_write.writable_roots=[{list}]"));
61 }
62 args.push(prompt.to_string());
63 ("codex", args)
64 }
65
66 fn parse_completion(&self, output: &str) -> Option<crate::agent_result::AgentResult> {
71 crate::agent_result::parse_codex_event_result(output)
72 }
73
74 fn environment(&self) -> Vec<(String, String)> {
75 vec![
79 ("GIT_CONFIG_COUNT".into(), "2".into()),
80 ("GIT_CONFIG_KEY_0".into(), "commit.gpgsign".into()),
81 ("GIT_CONFIG_VALUE_0".into(), "false".into()),
82 ("GIT_CONFIG_KEY_1".into(), "tag.gpgsign".into()),
83 ("GIT_CONFIG_VALUE_1".into(), "false".into()),
84 ]
85 }
86
87 fn interactivity_mode(&self, stage: crate::stage::Stage) -> InteractivityMode {
88 use crate::stage::Stage;
89 match stage {
90 Stage::Define | Stage::Plan => InteractivityMode::RequiresExistingArtifact,
94 _ => InteractivityMode::HeadlessSafe,
95 }
96 }
97}
98
99pub struct CodexAgent;
102
103impl AgentAdapter for CodexAgent {
104 fn name(&self) -> &'static str {
105 CodexDriver.name()
106 }
107
108 fn exec_command(
109 &self,
110 phase: PhaseId,
111 prompt: &str,
112 extra_writable_roots: &[PathBuf],
113 ) -> (&'static str, Vec<String>) {
114 CodexDriver.build_command(phase, prompt, extra_writable_roots)
115 }
116
117 fn extra_env(&self) -> Vec<(String, String)> {
118 CodexDriver.environment()
119 }
120
121 fn completion_signal_detected(&self, _output: &str) -> bool {
122 false
123 }
124
125 fn render_prompt(&self, intent: &crate::prompt::StageIntent) -> String {
126 CodexDriver.render_prompt(intent)
127 }
128}