use std::path::PathBuf;
#[derive(Debug, Clone, Default)]
pub struct ExecOptions {
pub model: Option<String>,
pub sandbox: Option<SandboxMode>,
pub approval: Option<ApprovalPolicy>,
pub full_auto: bool,
pub profile: Option<String>,
pub config_overrides: Vec<(String, String)>,
pub working_dir: Option<PathBuf>,
pub ephemeral: bool,
pub output_schema: Option<String>,
pub images: Vec<PathBuf>,
pub env_vars: Vec<(String, String)>,
}
#[derive(Debug, Clone, Default)]
pub struct ResumeOptions {
pub session_id: Option<String>,
pub last: bool,
pub model: Option<String>,
pub full_auto: bool,
pub working_dir: Option<PathBuf>,
pub env_vars: Vec<(String, String)>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SandboxMode {
ReadOnly,
WorkspaceWrite,
DangerFullAccess,
}
impl SandboxMode {
pub fn as_str(&self) -> &'static str {
match self {
Self::ReadOnly => "read-only",
Self::WorkspaceWrite => "workspace-write",
Self::DangerFullAccess => "danger-full-access",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ApprovalPolicy {
Untrusted,
OnFailure,
OnRequest,
Never,
}
impl ApprovalPolicy {
pub fn as_str(&self) -> &'static str {
match self {
Self::Untrusted => "untrusted",
Self::OnFailure => "on-failure",
Self::OnRequest => "on-request",
Self::Never => "never",
}
}
}
impl ExecOptions {
pub fn to_cli_args(&self) -> Vec<String> {
let mut args = Vec::new();
if let Some(ref model) = self.model {
args.extend(["-m".to_owned(), model.clone()]);
}
if let Some(sandbox) = self.sandbox {
args.extend(["--sandbox".to_owned(), sandbox.as_str().to_owned()]);
}
if let Some(approval) = self.approval {
args.extend(["--approval-policy".to_owned(), approval.as_str().to_owned()]);
}
if self.full_auto {
args.push("--full-auto".to_owned());
}
if let Some(ref profile) = self.profile {
args.extend(["--profile".to_owned(), profile.clone()]);
}
for (key, value) in &self.config_overrides {
args.extend(["-c".to_owned(), format!("{key}={value}")]);
}
if self.ephemeral {
args.push("--ephemeral".to_owned());
}
if let Some(ref schema) = self.output_schema {
args.extend(["--output-schema".to_owned(), schema.clone()]);
}
for image in &self.images {
args.extend(["--image".to_owned(), image.display().to_string()]);
}
args
}
}
impl ResumeOptions {
pub fn to_cli_args(&self) -> Vec<String> {
let mut args = Vec::new();
if let Some(ref id) = self.session_id {
args.push(id.clone());
}
if self.last {
args.push("--last".to_owned());
}
if let Some(ref model) = self.model {
args.extend(["-m".to_owned(), model.clone()]);
}
if self.full_auto {
args.push("--full-auto".to_owned());
}
args
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_options_produce_no_args() {
let opts = ExecOptions::default();
assert!(opts.to_cli_args().is_empty());
}
#[test]
fn model_and_full_auto() {
let opts = ExecOptions {
model: Some("o4-mini".to_owned()),
full_auto: true,
..Default::default()
};
let args = opts.to_cli_args();
assert_eq!(args, vec!["-m", "o4-mini", "--full-auto"]);
}
#[test]
fn sandbox_and_approval() {
let opts = ExecOptions {
sandbox: Some(SandboxMode::ReadOnly),
approval: Some(ApprovalPolicy::OnFailure),
..Default::default()
};
let args = opts.to_cli_args();
assert!(args.contains(&"--sandbox".to_owned()));
assert!(args.contains(&"read-only".to_owned()));
assert!(args.contains(&"--approval-policy".to_owned()));
assert!(args.contains(&"on-failure".to_owned()));
}
#[test]
fn config_overrides() {
let opts = ExecOptions {
config_overrides: vec![
("key1".to_owned(), "val1".to_owned()),
("key2".to_owned(), "val2".to_owned()),
],
..Default::default()
};
let args = opts.to_cli_args();
assert_eq!(args, vec!["-c", "key1=val1", "-c", "key2=val2"]);
}
#[test]
fn images() {
let opts = ExecOptions {
images: vec![PathBuf::from("a.png"), PathBuf::from("b.jpg")],
..Default::default()
};
let args = opts.to_cli_args();
assert_eq!(args, vec!["--image", "a.png", "--image", "b.jpg"]);
}
#[test]
fn resume_options() {
let opts = ResumeOptions {
session_id: Some("sess_123".to_owned()),
model: Some("o4-mini".to_owned()),
full_auto: true,
..Default::default()
};
let args = opts.to_cli_args();
assert_eq!(args, vec!["sess_123", "-m", "o4-mini", "--full-auto"]);
}
#[test]
fn resume_last() {
let opts = ResumeOptions {
last: true,
..Default::default()
};
let args = opts.to_cli_args();
assert_eq!(args, vec!["--last"]);
}
#[test]
fn profile_and_ephemeral() {
let opts = ExecOptions {
profile: Some("custom".to_owned()),
ephemeral: true,
..Default::default()
};
let args = opts.to_cli_args();
assert_eq!(args, vec!["--profile", "custom", "--ephemeral"]);
}
#[test]
fn output_schema() {
let opts = ExecOptions {
output_schema: Some(r#"{"type":"object"}"#.to_owned()),
..Default::default()
};
let args = opts.to_cli_args();
assert_eq!(args, vec!["--output-schema", r#"{"type":"object"}"#]);
}
}