feat: add support for -c/--config to override individual config items (#1137)

This PR introduces support for `-c`/`--config` so users can override
individual config values on the command line using `--config
name=value`. Example:

```
codex --config model=o4-mini
```

Making it possible to set arbitrary config values on the command line
results in a more flexible configuration scheme and makes it easier to
provide single-line examples that can be copy-pasted from documentation.

Effectively, it means there are four levels of configuration for some
values:

- Default value (e.g., `model` currently defaults to `o4-mini`)
- Value in `config.toml` (e.g., user could override the default to be
`model = "o3"` in their `config.toml`)
- Specifying `-c` or `--config` to override `model` (e.g., user can
include `-c model=o3` in their list of args to Codex)
- If available, a config-specific flag can be used, which takes
precedence over `-c` (e.g., user can specify `--model o3` in their list
of args to Codex)

Now that it is possible to specify anything that could be configured in
`config.toml` on the command line using `-c`, we do not need to have a
custom flag for every possible config option (which can clutter the
output of `--help`). To that end, as part of this PR, we drop support
for the `--disable-response-storage` flag, as users can now specify `-c
disable_response_storage=true` to get the equivalent functionality.

Under the hood, this works by loading the `config.toml` into a
`toml::Value`. Then for each `key=value`, we create a small synthetic
TOML file with `value` so that we can run the TOML parser to get the
equivalent `toml::Value`. We then parse `key` to determine the point in
the original `toml::Value` to do the insert/replace. Once all of the
overrides from `-c` args have been applied, the `toml::Value` is
deserialized into a `ConfigToml` and then the `ConfigOverrides` are
applied, as before.
This commit is contained in:
Michael Bolin
2025-05-27 23:11:44 -07:00
committed by GitHub
parent eba0e32909
commit d60f350cf8
20 changed files with 522 additions and 98 deletions

View File

@@ -1,15 +1,16 @@
//! Configuration object accepted by the `codex` MCP tool-call.
use std::path::PathBuf;
use codex_core::protocol::AskForApproval;
use codex_core::protocol::SandboxPolicy;
use mcp_types::Tool;
use mcp_types::ToolInputSchema;
use schemars::JsonSchema;
use schemars::r#gen::SchemaSettings;
use serde::Deserialize;
use std::collections::HashMap;
use std::path::PathBuf;
use codex_core::protocol::AskForApproval;
use codex_core::protocol::SandboxPolicy;
use crate::json_to_toml::json_to_toml;
/// Client-supplied configuration for a `codex` tool-call.
#[derive(Debug, Clone, Deserialize, JsonSchema)]
@@ -41,12 +42,10 @@ pub(crate) struct CodexToolCallParam {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sandbox_permissions: Option<Vec<CodexToolCallSandboxPermission>>,
/// Disable server-side response storage.
/// Individual config settings that will override what is in
/// CODEX_HOME/config.toml.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub disable_response_storage: Option<bool>,
// Custom system instructions.
// #[serde(default, skip_serializing_if = "Option::is_none")]
// pub instructions: Option<String>,
pub config: Option<HashMap<String, serde_json::Value>>,
}
// Create custom enums for use with `CodexToolCallApprovalPolicy` where we
@@ -155,7 +154,7 @@ impl CodexToolCallParam {
cwd,
approval_policy,
sandbox_permissions,
disable_response_storage,
config: cli_overrides,
} = self;
let sandbox_policy = sandbox_permissions.map(|perms| {
SandboxPolicy::from(perms.into_iter().map(Into::into).collect::<Vec<_>>())
@@ -168,12 +167,17 @@ impl CodexToolCallParam {
cwd: cwd.map(PathBuf::from),
approval_policy: approval_policy.map(Into::into),
sandbox_policy,
disable_response_storage,
model_provider: None,
codex_linux_sandbox_exe,
};
let cfg = codex_core::config::Config::load_with_overrides(overrides)?;
let cli_overrides = cli_overrides
.unwrap_or_default()
.into_iter()
.map(|(k, v)| (k, json_to_toml(v)))
.collect();
let cfg = codex_core::config::Config::load_with_cli_overrides(cli_overrides, overrides)?;
Ok((prompt, cfg))
}
@@ -216,14 +220,15 @@ mod tests {
],
"type": "string"
},
"config": {
"description": "Individual config settings that will override what is in CODEX_HOME/config.toml.",
"additionalProperties": true,
"type": "object"
},
"cwd": {
"description": "Working directory for the session. If relative, it is resolved against the server process's current working directory.",
"type": "string"
},
"disable-response-storage": {
"description": "Disable server-side response storage.",
"type": "boolean"
},
"model": {
"description": "Optional override for the model name (e.g. \"o3\", \"o4-mini\")",
"type": "string"