Compare commits

...

2 Commits

Author SHA1 Message Date
Channing Conger
e70beb5b93 Refactor to commoncli type so clap can merge 2025-11-17 16:56:00 -08:00
Channing Conger
52f0056368 Propagate top-level flags to exec subcommand
This fixes flags before the exec subcommend being ignored:
```
codex -m test-model exec "Hello world"
```

The above previously would ignore the -m override and use the configured
default.
2025-11-17 15:59:46 -08:00
9 changed files with 349 additions and 160 deletions

View File

@@ -44,6 +44,7 @@ const CHANNEL_CAPACITY: usize = 128;
pub async fn run_main(
codex_linux_sandbox_exe: Option<PathBuf>,
cli_config_overrides: CliConfigOverrides,
config_overrides: ConfigOverrides,
) -> IoResult<()> {
// Set up channels.
let (incoming_tx, mut incoming_rx) = mpsc::channel::<JSONRPCMessage>(CHANNEL_CAPACITY);
@@ -80,7 +81,7 @@ pub async fn run_main(
format!("error parsing -c overrides: {e}"),
)
})?;
let config = Config::load_with_cli_overrides(cli_kv_overrides, ConfigOverrides::default())
let config = Config::load_with_cli_overrides(cli_kv_overrides, config_overrides)
.await
.map_err(|e| {
std::io::Error::new(ErrorKind::InvalidData, format!("error loading config: {e}"))

View File

@@ -4,7 +4,12 @@ use codex_common::CliConfigOverrides;
fn main() -> anyhow::Result<()> {
arg0_dispatch_or_else(|codex_linux_sandbox_exe| async move {
run_main(codex_linux_sandbox_exe, CliConfigOverrides::default()).await?;
run_main(
codex_linux_sandbox_exe,
CliConfigOverrides::default(),
codex_core::config::ConfigOverrides::default(),
)
.await?;
Ok(())
})
}

View File

@@ -16,7 +16,10 @@ use codex_cli::login::run_login_with_chatgpt;
use codex_cli::login::run_login_with_device_code;
use codex_cli::login::run_logout;
use codex_cloud_tasks::Cli as CloudTasksCli;
use codex_common::ApprovalModeCliArg;
use codex_common::CliConfigOverrides;
use codex_common::CommonCli;
use codex_common::oss::get_default_model_for_oss_provider;
use codex_exec::Cli as ExecCli;
use codex_responses_api_proxy::Args as ResponsesApiProxyArgs;
use codex_tui::AppExitInfo;
@@ -32,9 +35,16 @@ mod wsl_paths;
use crate::mcp_cmd::McpCli;
use codex_core::LMSTUDIO_OSS_PROVIDER_ID;
use codex_core::OLLAMA_OSS_PROVIDER_ID;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
use codex_core::config::find_codex_home;
use codex_core::config::load_config_as_toml_with_cli_overrides;
use codex_core::config::resolve_oss_provider;
use codex_core::features::is_known_feature_key;
use codex_core::protocol::AskForApproval;
use codex_protocol::config_types::SandboxMode;
/// Codex CLI
///
@@ -207,6 +217,20 @@ struct LogoutCommand {
#[derive(Debug, Parser)]
struct AppServerCommand {
#[clap(flatten)]
common: CommonCli,
#[clap(flatten)]
config_overrides: CliConfigOverrides,
/// Configure when the model requires human approval before executing a command.
#[arg(long = "ask-for-approval", short = 'a')]
approval_policy: Option<codex_common::ApprovalModeCliArg>,
/// Enable web search (off by default). When enabled, the native Responses `web_search` tool is available to the model (no percall approval).
#[arg(long = "search", default_value_t = false)]
web_search: bool,
/// Omit to run the app server; specify a subcommand for tooling.
#[command(subcommand)]
subcommand: Option<AppServerSubcommand>,
@@ -433,7 +457,29 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
}
Some(Subcommand::AppServer(app_server_cli)) => match app_server_cli.subcommand {
None => {
codex_app_server::run_main(codex_linux_sandbox_exe, root_config_overrides).await?;
let mut cli_config_overrides = app_server_cli.config_overrides;
if app_server_cli.web_search {
cli_config_overrides
.raw_overrides
.push("features.web_search_request=true".to_string());
}
prepend_config_flags(&mut cli_config_overrides, root_config_overrides.clone());
let cli_kv_overrides = cli_config_overrides
.parse_overrides()
.map_err(anyhow::Error::msg)?;
let config_overrides = app_server_config_overrides_from_common(
&app_server_cli.common,
app_server_cli.approval_policy,
cli_kv_overrides,
codex_linux_sandbox_exe.clone(),
)
.await?;
codex_app_server::run_main(
codex_linux_sandbox_exe,
cli_config_overrides,
config_overrides,
)
.await?;
}
Some(AppServerSubcommand::GenerateTs(gen_cli)) => {
codex_app_server_protocol::generate_ts(
@@ -576,7 +622,7 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
// Thread through relevant top-level flags (at minimum, `--profile`).
let overrides = ConfigOverrides {
config_profile: interactive.config_profile.clone(),
config_profile: interactive.common.config_profile.clone(),
..Default::default()
};
@@ -605,6 +651,85 @@ fn prepend_config_flags(
.splice(0..0, cli_config_overrides.raw_overrides);
}
async fn app_server_config_overrides_from_common(
common: &CommonCli,
approval_policy: Option<ApprovalModeCliArg>,
cli_kv_overrides: Vec<(String, toml::Value)>,
codex_linux_sandbox_exe: Option<PathBuf>,
) -> anyhow::Result<ConfigOverrides> {
let (sandbox_mode, approval_policy) = if common.full_auto {
(
Some(SandboxMode::WorkspaceWrite),
Some(AskForApproval::OnRequest),
)
} else if common.dangerously_bypass_approvals_and_sandbox {
(
Some(SandboxMode::DangerFullAccess),
Some(AskForApproval::Never),
)
} else {
(
common.sandbox_mode.map(Into::into),
approval_policy.map(Into::into),
)
};
let model_provider = if common.oss {
let codex_home = find_codex_home()?;
let config_toml =
load_config_as_toml_with_cli_overrides(&codex_home, cli_kv_overrides).await?;
Some(
resolve_oss_provider(
common.oss_provider.as_deref(),
&config_toml,
common.config_profile.clone(),
)
.ok_or_else(|| {
anyhow::anyhow!(format!(
"No default OSS provider configured. Use --local-provider=provider or set oss_provider to either {LMSTUDIO_OSS_PROVIDER_ID} or {OLLAMA_OSS_PROVIDER_ID} in config.toml"
))
})?,
)
} else {
None
};
let model = if let Some(model) = &common.model {
Some(model.clone())
} else if common.oss {
model_provider
.as_deref()
.and_then(get_default_model_for_oss_provider)
.map(std::borrow::ToOwned::to_owned)
} else {
None
};
let cwd = common
.cwd
.as_ref()
.map(|p| p.canonicalize().unwrap_or_else(|_| p.to_path_buf()));
Ok(ConfigOverrides {
model,
review_model: None,
cwd,
approval_policy,
sandbox_mode,
model_provider,
config_profile: common.config_profile.clone(),
codex_linux_sandbox_exe,
base_instructions: None,
developer_instructions: None,
compact_prompt: None,
include_apply_patch_tool: None,
show_raw_agent_reasoning: common.oss.then_some(true),
tools_web_search_request: None,
experimental_sandbox_command_assessment: None,
additional_writable_roots: common.add_dir.clone(),
})
}
/// Build the final `TuiCli` for a `codex resume` invocation.
fn finalize_resume_interactive(
mut interactive: TuiCli,
@@ -633,39 +758,13 @@ fn finalize_resume_interactive(
/// root-level flags. Only overrides fields explicitly set on the resume-scoped
/// CLI. Also appends `-c key=value` overrides with highest precedence.
fn merge_resume_cli_flags(interactive: &mut TuiCli, resume_cli: TuiCli) {
if let Some(model) = resume_cli.model {
interactive.model = Some(model);
}
if resume_cli.oss {
interactive.oss = true;
}
if let Some(profile) = resume_cli.config_profile {
interactive.config_profile = Some(profile);
}
if let Some(sandbox) = resume_cli.sandbox_mode {
interactive.sandbox_mode = Some(sandbox);
}
interactive.common.apply_overrides(&resume_cli.common);
if let Some(approval) = resume_cli.approval_policy {
interactive.approval_policy = Some(approval);
}
if resume_cli.full_auto {
interactive.full_auto = true;
}
if resume_cli.dangerously_bypass_approvals_and_sandbox {
interactive.dangerously_bypass_approvals_and_sandbox = true;
}
if let Some(cwd) = resume_cli.cwd {
interactive.cwd = Some(cwd);
}
if resume_cli.web_search {
interactive.web_search = true;
}
if !resume_cli.images.is_empty() {
interactive.images = resume_cli.images;
}
if !resume_cli.add_dir.is_empty() {
interactive.add_dir.extend(resume_cli.add_dir);
}
if let Some(prompt) = resume_cli.prompt {
interactive.prompt = Some(prompt);
}
@@ -759,11 +858,55 @@ mod tests {
assert!(lines[1].contains("\u{1b}[36m"));
}
#[test]
fn exec_inherits_root_model_flag() {
let cli = MultitoolCli::try_parse_from(["codex", "-m", "codex-rapidash-300", "exec", "hi"])
.expect("parse");
let MultitoolCli { subcommand, .. } = cli;
let Subcommand::Exec(exec_cli) = subcommand.expect("exec present") else {
unreachable!()
};
assert_eq!(exec_cli.common.model.as_deref(), Some("codex-rapidash-300"));
assert_eq!(exec_cli.prompt.as_deref(), Some("hi"));
}
#[tokio::test]
async fn app_server_inherits_root_model_flag() {
let cli = MultitoolCli::try_parse_from(["codex", "-m", "codex-rapidash-300", "app-server"])
.expect("parse");
let MultitoolCli { subcommand, .. } = cli;
let Subcommand::AppServer(app_server_cli) = subcommand.expect("app-server present") else {
unreachable!()
};
assert!(app_server_cli.subcommand.is_none());
let cli_kv_overrides = app_server_cli
.config_overrides
.parse_overrides()
.expect("parse");
let config_overrides = app_server_config_overrides_from_common(
&app_server_cli.common,
app_server_cli.approval_policy,
cli_kv_overrides,
None,
)
.await
.expect("merge");
assert_eq!(
config_overrides.model.as_deref(),
Some("codex-rapidash-300")
);
}
#[test]
fn resume_model_flag_applies_when_no_root_flags() {
let interactive = finalize_from_args(["codex", "resume", "-m", "gpt-5-test"].as_ref());
assert_eq!(interactive.model.as_deref(), Some("gpt-5-test"));
assert_eq!(interactive.common.model.as_deref(), Some("gpt-5-test"));
assert!(interactive.resume_picker);
assert!(!interactive.resume_last);
assert_eq!(interactive.resume_session_id, None);
@@ -819,28 +962,33 @@ mod tests {
.as_ref(),
);
assert_eq!(interactive.model.as_deref(), Some("gpt-5-test"));
assert!(interactive.oss);
assert_eq!(interactive.config_profile.as_deref(), Some("my-profile"));
assert_eq!(interactive.common.model.as_deref(), Some("gpt-5-test"));
assert!(interactive.common.oss);
assert_eq!(
interactive.common.config_profile.as_deref(),
Some("my-profile")
);
assert_matches!(
interactive.sandbox_mode,
interactive.common.sandbox_mode,
Some(codex_common::SandboxModeCliArg::WorkspaceWrite)
);
assert_matches!(
interactive.approval_policy,
Some(codex_common::ApprovalModeCliArg::OnRequest)
);
assert!(interactive.full_auto);
assert!(interactive.common.full_auto);
assert_eq!(
interactive.cwd.as_deref(),
interactive.common.cwd.as_deref(),
Some(std::path::Path::new("/tmp"))
);
assert!(interactive.web_search);
let has_a = interactive
.common
.images
.iter()
.any(|p| p == std::path::Path::new("/tmp/a.png"));
let has_b = interactive
.common
.images
.iter()
.any(|p| p == std::path::Path::new("/tmp/b.png"));
@@ -860,7 +1008,7 @@ mod tests {
]
.as_ref(),
);
assert!(interactive.dangerously_bypass_approvals_and_sandbox);
assert!(interactive.common.dangerously_bypass_approvals_and_sandbox);
assert!(interactive.resume_picker);
assert!(!interactive.resume_last);
assert_eq!(interactive.resume_session_id, None);

View File

@@ -0,0 +1,108 @@
use clap::Parser;
use clap::ValueHint;
use std::path::PathBuf;
use crate::SandboxModeCliArg;
/// Flags shared across multiple Codex CLIs.
#[derive(Parser, Debug, Default, Clone)]
pub struct CommonCli {
/// Optional image(s) to attach to the initial prompt.
#[arg(
long = "image",
short = 'i',
value_name = "FILE",
value_delimiter = ',',
num_args = 1..,
global = true
)]
pub images: Vec<PathBuf>,
/// Model the agent should use.
#[arg(long, short = 'm', global = true)]
pub model: Option<String>,
/// Convenience flag to select the local open source model provider. Equivalent to -c
/// model_provider=oss; verifies a local LM Studio or Ollama server is running.
#[arg(long = "oss", default_value_t = false, global = true)]
pub oss: bool,
/// Specify which local provider to use (lmstudio or ollama).
/// If not specified with --oss, will use config default or show selection.
#[arg(long = "local-provider", global = true)]
pub oss_provider: Option<String>,
/// Configuration profile from config.toml to specify default options.
#[arg(long = "profile", short = 'p', global = true)]
pub config_profile: Option<String>,
/// Select the sandbox policy to use when executing model-generated shell
/// commands.
#[arg(long = "sandbox", short = 's', value_enum, global = true)]
pub sandbox_mode: Option<SandboxModeCliArg>,
/// Convenience alias for low-friction sandboxed automatic execution (-a on-request, --sandbox workspace-write).
#[arg(long = "full-auto", default_value_t = false, global = true)]
pub full_auto: bool,
/// Skip all confirmation prompts and execute commands without sandboxing.
/// EXTREMELY DANGEROUS. Intended solely for running in environments that are externally sandboxed.
#[arg(
long = "dangerously-bypass-approvals-and-sandbox",
alias = "yolo",
default_value_t = false,
conflicts_with = "full_auto",
global = true
)]
pub dangerously_bypass_approvals_and_sandbox: bool,
/// Tell the agent to use the specified directory as its working root.
#[clap(long = "cd", short = 'C', value_name = "DIR", global = true)]
pub cwd: Option<PathBuf>,
/// Additional directories that should be writable alongside the primary workspace.
#[arg(
long = "add-dir",
value_name = "DIR",
value_hint = ValueHint::DirPath,
global = true
)]
pub add_dir: Vec<PathBuf>,
}
impl CommonCli {
/// Apply overrides from another `CommonCli`, giving precedence to fields that
/// are explicitly set on `other`.
pub fn apply_overrides(&mut self, other: &CommonCli) {
if let Some(model) = &other.model {
self.model = Some(model.clone());
}
if other.oss {
self.oss = true;
}
if let Some(provider) = &other.oss_provider {
self.oss_provider = Some(provider.clone());
}
if let Some(profile) = &other.config_profile {
self.config_profile = Some(profile.clone());
}
if let Some(sandbox) = other.sandbox_mode {
self.sandbox_mode = Some(sandbox);
}
if other.full_auto {
self.full_auto = true;
}
if other.dangerously_bypass_approvals_and_sandbox {
self.dangerously_bypass_approvals_and_sandbox = true;
}
if let Some(cwd) = &other.cwd {
self.cwd = Some(cwd.clone());
}
if !other.images.is_empty() {
self.images = other.images.clone();
}
if !other.add_dir.is_empty() {
self.add_dir.extend(other.add_dir.clone());
}
}
}

View File

@@ -10,6 +10,9 @@ pub use approval_mode_cli_arg::ApprovalModeCliArg;
#[cfg(feature = "cli")]
mod sandbox_mode_cli_arg;
#[cfg(feature = "cli")]
mod common_cli;
#[cfg(feature = "cli")]
pub use sandbox_mode_cli_arg::SandboxModeCliArg;
@@ -22,6 +25,9 @@ mod config_override;
#[cfg(feature = "cli")]
pub use config_override::CliConfigOverrides;
#[cfg(feature = "cli")]
pub use common_cli::CommonCli;
mod sandbox_summary;
#[cfg(feature = "sandbox_summary")]

View File

@@ -1,6 +1,7 @@
use clap::Parser;
use clap::ValueEnum;
use codex_common::CliConfigOverrides;
use codex_common::CommonCli;
use std::path::PathBuf;
#[derive(Parser, Debug)]
@@ -10,58 +11,14 @@ pub struct Cli {
#[command(subcommand)]
pub command: Option<Command>,
/// Optional image(s) to attach to the initial prompt.
#[arg(long = "image", short = 'i', value_name = "FILE", value_delimiter = ',', num_args = 1..)]
pub images: Vec<PathBuf>,
/// Model the agent should use.
#[arg(long, short = 'm')]
pub model: Option<String>,
/// Use open-source provider.
#[arg(long = "oss", default_value_t = false)]
pub oss: bool,
/// Specify which local provider to use (lmstudio or ollama).
/// If not specified with --oss, will use config default or show selection.
#[arg(long = "local-provider")]
pub oss_provider: Option<String>,
/// Select the sandbox policy to use when executing model-generated shell
/// commands.
#[arg(long = "sandbox", short = 's', value_enum)]
pub sandbox_mode: Option<codex_common::SandboxModeCliArg>,
/// Configuration profile from config.toml to specify default options.
#[arg(long = "profile", short = 'p')]
pub config_profile: Option<String>,
/// Convenience alias for low-friction sandboxed automatic execution (-a on-request, --sandbox workspace-write).
#[arg(long = "full-auto", default_value_t = false)]
pub full_auto: bool,
/// Skip all confirmation prompts and execute commands without sandboxing.
/// EXTREMELY DANGEROUS. Intended solely for running in environments that are externally sandboxed.
#[arg(
long = "dangerously-bypass-approvals-and-sandbox",
alias = "yolo",
default_value_t = false,
conflicts_with = "full_auto"
)]
pub dangerously_bypass_approvals_and_sandbox: bool,
/// Tell the agent to use the specified directory as its working root.
#[clap(long = "cd", short = 'C', value_name = "DIR")]
pub cwd: Option<PathBuf>,
/// Model and execution controls shared with the interactive CLI.
#[clap(flatten)]
pub common: CommonCli,
/// Allow running Codex outside a Git repository.
#[arg(long = "skip-git-repo-check", default_value_t = false)]
pub skip_git_repo_check: bool,
/// Additional directories that should be writable alongside the primary workspace.
#[arg(long = "add-dir", value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
pub add_dir: Vec<PathBuf>,
/// Path to a JSON Schema file describing the model's final response shape.
#[arg(long = "output-schema", value_name = "FILE")]
pub output_schema: Option<PathBuf>,

View File

@@ -11,6 +11,7 @@ pub mod event_processor_with_jsonl_output;
pub mod exec_events;
pub use cli::Cli;
use codex_common::CommonCli;
use codex_common::oss::ensure_oss_provider_ready;
use codex_common::oss::get_default_model_for_oss_provider;
use codex_core::AuthManager;
@@ -59,6 +60,17 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
let Cli {
command,
common,
skip_git_repo_check,
color,
last_message_file,
json: json_mode,
prompt,
output_schema: output_schema_path,
config_overrides,
} = cli;
let CommonCli {
images,
model: model_cli_arg,
oss,
@@ -67,16 +79,10 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
full_auto,
dangerously_bypass_approvals_and_sandbox,
cwd,
skip_git_repo_check,
add_dir,
color,
last_message_file,
json: json_mode,
sandbox_mode: sandbox_mode_cli_arg,
prompt,
output_schema: output_schema_path,
config_overrides,
} = cli;
..
} = common;
// Determine the prompt source (parent or subcommand) and read from stdin if needed.
let prompt_arg = match &command {

View File

@@ -1,20 +1,18 @@
use clap::Parser;
use clap::ValueHint;
use codex_common::ApprovalModeCliArg;
use codex_common::CliConfigOverrides;
use std::path::PathBuf;
use codex_common::CommonCli;
#[derive(Parser, Debug)]
#[command(version)]
pub struct Cli {
#[clap(flatten)]
pub common: CommonCli,
/// Optional user prompt to start the session.
#[arg(value_name = "PROMPT", value_hint = clap::ValueHint::Other)]
pub prompt: Option<String>,
/// Optional image(s) to attach to the initial prompt.
#[arg(long = "image", short = 'i', value_name = "FILE", value_delimiter = ',', num_args = 1..)]
pub images: Vec<PathBuf>,
// Internal controls set by the top-level `codex resume` subcommand.
// These are not exposed as user flags on the base `codex` command.
#[clap(skip)]
@@ -28,59 +26,14 @@ pub struct Cli {
#[clap(skip)]
pub resume_session_id: Option<String>,
/// Model the agent should use.
#[arg(long, short = 'm')]
pub model: Option<String>,
/// Convenience flag to select the local open source model provider. Equivalent to -c
/// model_provider=oss; verifies a local LM Studio or Ollama server is running.
#[arg(long = "oss", default_value_t = false)]
pub oss: bool,
/// Specify which local provider to use (lmstudio or ollama).
/// If not specified with --oss, will use config default or show selection.
#[arg(long = "local-provider")]
pub oss_provider: Option<String>,
/// Configuration profile from config.toml to specify default options.
#[arg(long = "profile", short = 'p')]
pub config_profile: Option<String>,
/// Select the sandbox policy to use when executing model-generated shell
/// commands.
#[arg(long = "sandbox", short = 's')]
pub sandbox_mode: Option<codex_common::SandboxModeCliArg>,
/// Configure when the model requires human approval before executing a command.
#[arg(long = "ask-for-approval", short = 'a')]
pub approval_policy: Option<ApprovalModeCliArg>,
/// Convenience alias for low-friction sandboxed automatic execution (-a on-request, --sandbox workspace-write).
#[arg(long = "full-auto", default_value_t = false)]
pub full_auto: bool,
/// Skip all confirmation prompts and execute commands without sandboxing.
/// EXTREMELY DANGEROUS. Intended solely for running in environments that are externally sandboxed.
#[arg(
long = "dangerously-bypass-approvals-and-sandbox",
alias = "yolo",
default_value_t = false,
conflicts_with_all = ["approval_policy", "full_auto"]
)]
pub dangerously_bypass_approvals_and_sandbox: bool,
/// Tell the agent to use the specified directory as its working root.
#[clap(long = "cd", short = 'C', value_name = "DIR")]
pub cwd: Option<PathBuf>,
/// Enable web search (off by default). When enabled, the native Responses `web_search` tool is available to the model (no percall approval).
#[arg(long = "search", default_value_t = false)]
pub web_search: bool,
/// Additional directories that should be writable alongside the primary workspace.
#[arg(long = "add-dir", value_name = "DIR", value_hint = ValueHint::DirPath)]
pub add_dir: Vec<PathBuf>,
#[clap(skip)]
pub config_overrides: CliConfigOverrides,
}

View File

@@ -102,19 +102,19 @@ pub async fn run_main(
mut cli: Cli,
codex_linux_sandbox_exe: Option<PathBuf>,
) -> std::io::Result<AppExitInfo> {
let (sandbox_mode, approval_policy) = if cli.full_auto {
let (sandbox_mode, approval_policy) = if cli.common.full_auto {
(
Some(SandboxMode::WorkspaceWrite),
Some(AskForApproval::OnRequest),
)
} else if cli.dangerously_bypass_approvals_and_sandbox {
} else if cli.common.dangerously_bypass_approvals_and_sandbox {
(
Some(SandboxMode::DangerFullAccess),
Some(AskForApproval::Never),
)
} else {
(
cli.sandbox_mode.map(Into::<SandboxMode>::into),
cli.common.sandbox_mode.map(Into::<SandboxMode>::into),
cli.approval_policy.map(Into::into),
)
};
@@ -161,11 +161,11 @@ pub async fn run_main(
}
};
let model_provider_override = if cli.oss {
let model_provider_override = if cli.common.oss {
let resolved = resolve_oss_provider(
cli.oss_provider.as_deref(),
cli.common.oss_provider.as_deref(),
&config_toml,
cli.config_profile.clone(),
cli.common.config_profile.clone(),
);
if let Some(provider) = resolved {
@@ -185,9 +185,9 @@ pub async fn run_main(
};
// When using `--oss`, let the bootstrapper pick the model based on selected provider
let model = if let Some(model) = &cli.model {
let model = if let Some(model) = &cli.common.model {
Some(model.clone())
} else if cli.oss {
} else if cli.common.oss {
// Use the provider from model_provider_override
model_provider_override
.as_ref()
@@ -198,8 +198,12 @@ pub async fn run_main(
};
// canonicalize the cwd
let cwd = cli.cwd.clone().map(|p| p.canonicalize().unwrap_or(p));
let additional_dirs = cli.add_dir.clone();
let cwd = cli
.common
.cwd
.clone()
.map(|p| p.canonicalize().unwrap_or(p));
let additional_dirs = cli.common.add_dir.clone();
let overrides = ConfigOverrides {
model,
@@ -208,13 +212,13 @@ pub async fn run_main(
sandbox_mode,
cwd,
model_provider: model_provider_override.clone(),
config_profile: cli.config_profile.clone(),
config_profile: cli.common.config_profile.clone(),
codex_linux_sandbox_exe,
base_instructions: None,
developer_instructions: None,
compact_prompt: None,
include_apply_patch_tool: None,
show_raw_agent_reasoning: cli.oss.then_some(true),
show_raw_agent_reasoning: cli.common.oss.then_some(true),
tools_web_search_request: None,
experimental_sandbox_command_assessment: None,
additional_writable_roots: additional_dirs,
@@ -222,7 +226,7 @@ pub async fn run_main(
let config = load_config_or_exit(cli_kv_overrides.clone(), overrides.clone()).await;
if let Some(warning) = add_dir_warning_message(&cli.add_dir, &config.sandbox_policy) {
if let Some(warning) = add_dir_warning_message(&cli.common.add_dir, &config.sandbox_policy) {
#[allow(clippy::print_stderr)]
{
eprintln!("Error adding directories: {warning}");
@@ -280,7 +284,7 @@ pub async fn run_main(
.with_target(false)
.with_filter(targets);
if cli.oss && model_provider_override.is_some() {
if cli.common.oss && model_provider_override.is_some() {
// We're in the oss section, so provider_id should be Some
// Let's handle None case gracefully though just in case
let provider_id = match model_provider_override.as_ref() {
@@ -508,7 +512,8 @@ async fn run_ratatui_app(
resume_picker::ResumeSelection::StartFresh
};
let Cli { prompt, images, .. } = cli;
let Cli { prompt, common, .. } = cli;
let images = common.images;
let app_result = App::run(
&mut tui,