Skip to main content

ito_core/harness/
codex.rs

1use super::streaming_cli::CliHarness;
2use super::types::{HarnessName, HarnessRunConfig};
3
4/// Runs the `codex` CLI in non-interactive exec mode (`codex exec`).
5///
6/// Selected via `ito ralph --harness codex`; requires the Codex CLI on PATH.
7///
8/// # Examples
9///
10/// ```
11/// use ito_core::harness::{CodexHarness, Harness, HarnessName};
12///
13/// let h = CodexHarness;
14/// assert_eq!(h.name(), HarnessName::Codex);
15/// assert!(h.streams_output());
16/// ```
17#[derive(Debug, Default)]
18pub struct CodexHarness;
19
20impl CliHarness for CodexHarness {
21    fn harness_name(&self) -> HarnessName {
22        HarnessName::Codex
23    }
24
25    fn binary(&self) -> &str {
26        "codex"
27    }
28
29    fn build_args(&self, config: &HarnessRunConfig) -> Vec<String> {
30        let mut args = vec!["exec".to_string()];
31        if let Some(model) = config.model.as_deref() {
32            args.push("--model".to_string());
33            args.push(model.to_string());
34        }
35        if config.allow_all {
36            args.push("--yolo".to_string());
37        }
38        args.push(config.prompt.clone());
39        args
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use std::collections::BTreeMap;
47
48    enum Allow {
49        All,
50        None,
51    }
52
53    fn config(allow: Allow, model: Option<&str>) -> HarnessRunConfig {
54        let allow_all = match allow {
55            Allow::All => true,
56            Allow::None => false,
57        };
58        HarnessRunConfig {
59            prompt: "do stuff".to_string(),
60            model: model.map(String::from),
61            cwd: std::env::temp_dir(),
62            env: BTreeMap::new(),
63            interactive: false,
64            allow_all,
65            inactivity_timeout: None,
66        }
67    }
68
69    #[test]
70    fn harness_name_is_codex() {
71        let harness = CodexHarness;
72        assert_eq!(harness.harness_name(), HarnessName::Codex);
73    }
74
75    #[test]
76    fn binary_is_codex() {
77        let harness = CodexHarness;
78        assert_eq!(harness.binary(), "codex");
79    }
80
81    #[test]
82    fn build_args_with_allow_all() {
83        let harness = CodexHarness;
84        let cfg = config(Allow::All, Some("o3"));
85        let args = harness.build_args(&cfg);
86        assert_eq!(args, vec!["exec", "--model", "o3", "--yolo", "do stuff"]);
87    }
88
89    #[test]
90    fn build_args_without_allow_all() {
91        let harness = CodexHarness;
92        let cfg = config(Allow::None, Some("o3"));
93        let args = harness.build_args(&cfg);
94        assert_eq!(args, vec!["exec", "--model", "o3", "do stuff"]);
95    }
96}