diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 4d97a2c316..34898774be 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -41,6 +41,7 @@ use crate::models::ContentItem; use crate::models::FunctionCallOutputPayload; use crate::models::ResponseInputItem; use crate::models::ResponseItem; +use crate::models::ShellToolCallParams; use crate::protocol::AskForApproval; use crate::protocol::Event; use crate::protocol::EventMsg; diff --git a/codex-rs/core/src/linux.rs b/codex-rs/core/src/linux.rs index 8fa07d549d..4f3ca34da5 100644 --- a/codex-rs/core/src/linux.rs +++ b/codex-rs/core/src/linux.rs @@ -195,7 +195,7 @@ mod tests_linux { async fn run_cmd(cmd: &[&str], writable_roots: &[PathBuf], timeout_ms: u64) { let params = ExecParams { command: cmd.iter().map(|elm| elm.to_string()).collect(), - workdir: None, + cwd: None, timeout_ms: Some(timeout_ms), }; @@ -268,7 +268,7 @@ mod tests_linux { async fn assert_network_blocked(cmd: &[&str]) { let params = ExecParams { command: cmd.iter().map(|s| s.to_string()).collect(), - workdir: None, + cwd: None, // Give the tool a generous 2‑second timeout so even slow DNS timeouts // do not stall the suite. timeout_ms: Some(2_000), diff --git a/codex-rs/core/src/models.rs b/codex-rs/core/src/models.rs index 2665e8c17b..b1a131da8c 100644 --- a/codex-rs/core/src/models.rs +++ b/codex-rs/core/src/models.rs @@ -102,6 +102,20 @@ impl From> for ResponseInputItem { } } +/// If the `name` of a `ResponseItem::FunctionCall` is either `container.exec` +/// or shell`, the `arguments` field should deserialize to this struct. +#[derive(Deserialize, Debug, Clone, PartialEq)] +pub struct ShellToolCallParams { + pub command: Vec, + pub workdir: Option, + + /// This is the maximum time in seconds that the command is allowed to run. + #[serde(rename = "timeout")] + // The wire format uses `timeout`, which has ambiguous units, so we use + // `timeout_ms` as the field name so it is clear in code. + pub timeout_ms: Option, +} + #[expect(dead_code)] #[derive(Deserialize, Debug, Clone)] pub struct FunctionCallOutputPayload { @@ -183,4 +197,23 @@ mod tests { assert_eq!(v.get("output").unwrap().as_str().unwrap(), "bad"); } + + #[test] + fn deserialize_shell_tool_call_params() { + let json = r#"{ + "command": ["ls", "-l"], + "workdir": "/tmp", + "timeout": 1000 + }"#; + + let params: ShellToolCallParams = serde_json::from_str(json).unwrap(); + assert_eq!( + ShellToolCallParams { + command: vec!["ls".to_string(), "-l".to_string()], + workdir: Some("/tmp".to_string()), + timeout_ms: Some(1000), + }, + params + ); + } }