mirror of
https://github.com/openai/codex.git
synced 2026-11-05 08:28:29 +00:00
config: remove legacy profile v1 resolution (#24051)
## Why [#23883](https://github.com/openai/codex/pull/23883) moved user-facing `--profile` selection onto profile v2, and [#23886](https://github.com/openai/codex/pull/23886) removed the old CLI `config_profile` override path. Core still had a second legacy path: `profile = "..."` could select `[profiles.*]` values while runtime config was built. Keeping that resolver alive preserves the old precedence model and profile-carrying surfaces even though profile selection now points at `$CODEX_HOME/<name>.config.toml`. ## What - Reject legacy top-level `profile = "..."` config while loading runtime config, with an error that points callers at `--profile <name>` and `<name>.config.toml` in the [core load path](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/mod.rs#L2524-L2531). - Remove the remaining profile-v1 merge points from runtime config resolution, including features, permissions, model/provider selection, web search, Windows sandbox settings, TUI settings, role reloads, and OSS provider lookup. - Drop the leftover profile override surface from [`ConfigOverrides`](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/mod.rs#L2118-L2148) and from the MCP server `codex` tool schema. - Prune profile-precedence tests that only exercised the removed resolver and replace them with rejection coverage for the legacy selector. ## Testing - Not run in this metadata pass. - Added [`legacy_profile_selection_is_rejected`](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/config_tests.rs#L7942-L7965) coverage for the new runtime guard.
This commit is contained in:
1 parent
ed80e5f558
commit
fd72e99384
10 files changed
+110
-1766
No files matched your search
@@ -979,48 +979,6 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn explicit_permission_profile_overrides_active_profile_sandbox_mode()
|
|
||||||
-> anyhow::Result<()> {
|
|
||||||
let codex_home = TempDir::new()?;
|
|
||||||
std::fs::write(
|
|
||||||
codex_home.path().join("config.toml"),
|
|
||||||
"profile = \"legacy\"\n\
|
|
||||||
\n\
|
|
||||||
[profiles.legacy]\n\
|
|
||||||
sandbox_mode = \"danger-full-access\"\n",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let config = load_debug_sandbox_config_with_codex_home(
|
|
||||||
Vec::new(),
|
|
||||||
/*codex_linux_sandbox_exe*/ None,
|
|
||||||
DebugSandboxConfigOptions {
|
|
||||||
permissions_profile: Some(":workspace".to_string()),
|
|
||||||
cwd: None,
|
|
||||||
managed_requirements_mode: ManagedRequirementsMode::Ignore,
|
|
||||||
},
|
|
||||||
Some(codex_home.path().to_path_buf()),
|
|
||||||
/*strict_config*/ false,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let actual = config
|
|
||||||
.permissions
|
|
||||||
.permission_profile()
|
|
||||||
.file_system_sandbox_policy();
|
|
||||||
let expected = codex_protocol::models::PermissionProfile::workspace_write()
|
|
||||||
.file_system_sandbox_policy();
|
|
||||||
assert!(
|
|
||||||
expected
|
|
||||||
.entries
|
|
||||||
.iter()
|
|
||||||
.all(|entry| actual.entries.contains(entry)),
|
|
||||||
"explicit workspace profile should preserve the built-in workspace rules"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn debug_sandbox_honors_explicit_named_permission_profile() -> anyhow::Result<()> {
|
async fn debug_sandbox_honors_explicit_named_permission_profile() -> anyhow::Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
|
|||||||
@@ -71,14 +71,12 @@ async fn apply_role_to_config_inner(
|
|||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let (preserve_current_profile, preserve_current_provider) =
|
let preserve_current_provider = role_layer_toml.get("model_provider").is_none();
|
||||||
preservation_policy(config, &role_layer_toml);
|
|
||||||
let preserve_current_service_tier = role_layer_toml.get("service_tier").is_none();
|
let preserve_current_service_tier = role_layer_toml.get("service_tier").is_none();
|
||||||
|
|
||||||
*config = reload::build_next_config(
|
*config = reload::build_next_config(
|
||||||
config,
|
config,
|
||||||
role_layer_toml,
|
role_layer_toml,
|
||||||
preserve_current_profile,
|
|
||||||
preserve_current_provider,
|
preserve_current_provider,
|
||||||
preserve_current_service_tier,
|
preserve_current_service_tier,
|
||||||
)
|
)
|
||||||
@@ -130,48 +128,19 @@ pub(crate) fn resolve_role_config<'a>(
|
|||||||
.or_else(|| built_in::configs().get(role_name))
|
.or_else(|| built_in::configs().get(role_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preservation_policy(config: &Config, role_layer_toml: &TomlValue) -> (bool, bool) {
|
|
||||||
let role_selects_provider = role_layer_toml.get("model_provider").is_some();
|
|
||||||
let role_selects_profile = role_layer_toml.get("profile").is_some();
|
|
||||||
let role_updates_active_profile_provider = config
|
|
||||||
.active_profile
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|active_profile| {
|
|
||||||
role_layer_toml
|
|
||||||
.get("profiles")
|
|
||||||
.and_then(TomlValue::as_table)
|
|
||||||
.and_then(|profiles| profiles.get(active_profile))
|
|
||||||
.and_then(TomlValue::as_table)
|
|
||||||
.map(|profile| profile.contains_key("model_provider"))
|
|
||||||
})
|
|
||||||
.unwrap_or(false);
|
|
||||||
let preserve_current_profile = !role_selects_provider && !role_selects_profile;
|
|
||||||
let preserve_current_provider =
|
|
||||||
preserve_current_profile && !role_updates_active_profile_provider;
|
|
||||||
(preserve_current_profile, preserve_current_provider)
|
|
||||||
}
|
|
||||||
|
|
||||||
mod reload {
|
mod reload {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub(super) async fn build_next_config(
|
pub(super) async fn build_next_config(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
role_layer_toml: TomlValue,
|
role_layer_toml: TomlValue,
|
||||||
preserve_current_profile: bool,
|
|
||||||
preserve_current_provider: bool,
|
preserve_current_provider: bool,
|
||||||
preserve_current_service_tier: bool,
|
preserve_current_service_tier: bool,
|
||||||
) -> anyhow::Result<Config> {
|
) -> anyhow::Result<Config> {
|
||||||
let active_profile_name = preserve_current_profile
|
let config_layer_stack = build_config_layer_stack(config, &role_layer_toml)?;
|
||||||
.then_some(config.active_profile.as_deref())
|
let merged_config = deserialize_effective_config(config, &config_layer_stack)?;
|
||||||
.flatten();
|
|
||||||
let config_layer_stack =
|
|
||||||
build_config_layer_stack(config, &role_layer_toml, active_profile_name)?;
|
|
||||||
let mut merged_config = deserialize_effective_config(config, &config_layer_stack)?;
|
|
||||||
if preserve_current_profile {
|
|
||||||
merged_config.profile = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut next_config = Config::load_config_with_layer_stack(
|
let next_config = Config::load_config_with_layer_stack(
|
||||||
LOCAL_FS.as_ref(),
|
LOCAL_FS.as_ref(),
|
||||||
merged_config,
|
merged_config,
|
||||||
reload_overrides(
|
reload_overrides(
|
||||||
@@ -183,23 +152,14 @@ mod reload {
|
|||||||
config_layer_stack,
|
config_layer_stack,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if preserve_current_profile {
|
|
||||||
next_config.active_profile = config.active_profile.clone();
|
|
||||||
}
|
|
||||||
Ok(next_config)
|
Ok(next_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_config_layer_stack(
|
fn build_config_layer_stack(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
role_layer_toml: &TomlValue,
|
role_layer_toml: &TomlValue,
|
||||||
active_profile_name: Option<&str>,
|
|
||||||
) -> anyhow::Result<ConfigLayerStack> {
|
) -> anyhow::Result<ConfigLayerStack> {
|
||||||
let mut layers = existing_layers(config);
|
let mut layers = existing_layers(config);
|
||||||
if let Some(resolved_profile_layer) =
|
|
||||||
resolved_profile_layer(config, &layers, role_layer_toml, active_profile_name)?
|
|
||||||
{
|
|
||||||
insert_layer(&mut layers, resolved_profile_layer);
|
|
||||||
}
|
|
||||||
insert_layer(&mut layers, role_layer(role_layer_toml.clone()));
|
insert_layer(&mut layers, role_layer(role_layer_toml.clone()));
|
||||||
Ok(ConfigLayerStack::new(
|
Ok(ConfigLayerStack::new(
|
||||||
layers,
|
layers,
|
||||||
@@ -208,34 +168,6 @@ mod reload {
|
|||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolved_profile_layer(
|
|
||||||
config: &Config,
|
|
||||||
existing_layers: &[ConfigLayerEntry],
|
|
||||||
role_layer_toml: &TomlValue,
|
|
||||||
active_profile_name: Option<&str>,
|
|
||||||
) -> anyhow::Result<Option<ConfigLayerEntry>> {
|
|
||||||
let Some(active_profile_name) = active_profile_name else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut layers = existing_layers.to_vec();
|
|
||||||
insert_layer(&mut layers, role_layer(role_layer_toml.clone()));
|
|
||||||
let merged_config = deserialize_effective_config(
|
|
||||||
config,
|
|
||||||
&ConfigLayerStack::new(
|
|
||||||
layers,
|
|
||||||
config.config_layer_stack.requirements().clone(),
|
|
||||||
config.config_layer_stack.requirements_toml().clone(),
|
|
||||||
)?,
|
|
||||||
)?;
|
|
||||||
let resolved_profile =
|
|
||||||
merged_config.get_config_profile(Some(active_profile_name.to_string()))?;
|
|
||||||
Ok(Some(ConfigLayerEntry::new(
|
|
||||||
ConfigLayerSource::SessionFlags,
|
|
||||||
TomlValue::try_from(resolved_profile)?,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_effective_config(
|
fn deserialize_effective_config(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
config_layer_stack: &ConfigLayerStack,
|
config_layer_stack: &ConfigLayerStack,
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::SkillsManager;
|
use crate::SkillsManager;
|
||||||
use crate::config::CONFIG_TOML_FILE;
|
|
||||||
use crate::config::ConfigBuilder;
|
use crate::config::ConfigBuilder;
|
||||||
use crate::skills_load_input_from_config;
|
use crate::skills_load_input_from_config;
|
||||||
use codex_config::ConfigLayerStackOrdering;
|
use codex_config::ConfigLayerStackOrdering;
|
||||||
use codex_core_plugins::PluginsManager;
|
use codex_core_plugins::PluginsManager;
|
||||||
use codex_protocol::config_types::ReasoningSummary;
|
|
||||||
use codex_protocol::config_types::ServiceTier;
|
use codex_protocol::config_types::ServiceTier;
|
||||||
use codex_protocol::config_types::Verbosity;
|
|
||||||
use codex_protocol::openai_models::ReasoningEffort;
|
use codex_protocol::openai_models::ReasoningEffort;
|
||||||
use codex_utils_absolute_path::test_support::PathExt;
|
use codex_utils_absolute_path::test_support::PathExt;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
@@ -275,301 +272,6 @@ async fn apply_role_preserves_existing_service_tier_without_override() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn apply_role_preserves_active_profile_and_model_provider() {
|
|
||||||
let home = TempDir::new().expect("create temp dir");
|
|
||||||
tokio::fs::write(
|
|
||||||
home.path().join(CONFIG_TOML_FILE),
|
|
||||||
r#"
|
|
||||||
[model_providers.test-provider]
|
|
||||||
name = "Test Provider"
|
|
||||||
base_url = "https://example.com/v1"
|
|
||||||
env_key = "TEST_PROVIDER_API_KEY"
|
|
||||||
wire_api = "responses"
|
|
||||||
|
|
||||||
[profiles.test-profile]
|
|
||||||
model_provider = "test-provider"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("write config.toml");
|
|
||||||
let mut config = ConfigBuilder::default()
|
|
||||||
.codex_home(home.path().to_path_buf())
|
|
||||||
.harness_overrides(ConfigOverrides {
|
|
||||||
config_profile: Some("test-profile".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.fallback_cwd(Some(home.path().to_path_buf()))
|
|
||||||
.build()
|
|
||||||
.await
|
|
||||||
.expect("load config");
|
|
||||||
let role_path = write_role_config(
|
|
||||||
&home,
|
|
||||||
"empty-role.toml",
|
|
||||||
"developer_instructions = \"Stay focused\"",
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
config.agent_roles.insert(
|
|
||||||
"custom".to_string(),
|
|
||||||
AgentRoleConfig {
|
|
||||||
description: None,
|
|
||||||
config_file: Some(role_path),
|
|
||||||
nickname_candidates: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
apply_role_to_config(&mut config, Some("custom"))
|
|
||||||
.await
|
|
||||||
.expect("custom role should apply");
|
|
||||||
|
|
||||||
assert_eq!(config.active_profile.as_deref(), Some("test-profile"));
|
|
||||||
assert_eq!(config.model_provider_id, "test-provider");
|
|
||||||
assert_eq!(config.model_provider.name, "Test Provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn apply_role_top_level_profile_settings_override_preserved_profile() {
|
|
||||||
let home = TempDir::new().expect("create temp dir");
|
|
||||||
tokio::fs::write(
|
|
||||||
home.path().join(CONFIG_TOML_FILE),
|
|
||||||
r#"
|
|
||||||
[profiles.base-profile]
|
|
||||||
model = "profile-model"
|
|
||||||
model_reasoning_effort = "low"
|
|
||||||
model_reasoning_summary = "concise"
|
|
||||||
model_verbosity = "low"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("write config.toml");
|
|
||||||
let mut config = ConfigBuilder::default()
|
|
||||||
.codex_home(home.path().to_path_buf())
|
|
||||||
.harness_overrides(ConfigOverrides {
|
|
||||||
config_profile: Some("base-profile".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.fallback_cwd(Some(home.path().to_path_buf()))
|
|
||||||
.build()
|
|
||||||
.await
|
|
||||||
.expect("load config");
|
|
||||||
let role_path = write_role_config(
|
|
||||||
&home,
|
|
||||||
"top-level-profile-settings-role.toml",
|
|
||||||
r#"developer_instructions = "Stay focused"
|
|
||||||
model = "role-model"
|
|
||||||
model_reasoning_effort = "high"
|
|
||||||
model_reasoning_summary = "detailed"
|
|
||||||
model_verbosity = "high"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
config.agent_roles.insert(
|
|
||||||
"custom".to_string(),
|
|
||||||
AgentRoleConfig {
|
|
||||||
description: None,
|
|
||||||
config_file: Some(role_path),
|
|
||||||
nickname_candidates: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
apply_role_to_config(&mut config, Some("custom"))
|
|
||||||
.await
|
|
||||||
.expect("custom role should apply");
|
|
||||||
|
|
||||||
assert_eq!(config.active_profile.as_deref(), Some("base-profile"));
|
|
||||||
assert_eq!(config.model.as_deref(), Some("role-model"));
|
|
||||||
assert_eq!(config.model_reasoning_effort, Some(ReasoningEffort::High));
|
|
||||||
assert_eq!(
|
|
||||||
config.model_reasoning_summary,
|
|
||||||
Some(ReasoningSummary::Detailed)
|
|
||||||
);
|
|
||||||
assert_eq!(config.model_verbosity, Some(Verbosity::High));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn apply_role_uses_role_profile_instead_of_current_profile() {
|
|
||||||
let home = TempDir::new().expect("create temp dir");
|
|
||||||
tokio::fs::write(
|
|
||||||
home.path().join(CONFIG_TOML_FILE),
|
|
||||||
r#"
|
|
||||||
[model_providers.base-provider]
|
|
||||||
name = "Base Provider"
|
|
||||||
base_url = "https://base.example.com/v1"
|
|
||||||
env_key = "BASE_PROVIDER_API_KEY"
|
|
||||||
wire_api = "responses"
|
|
||||||
|
|
||||||
[model_providers.role-provider]
|
|
||||||
name = "Role Provider"
|
|
||||||
base_url = "https://role.example.com/v1"
|
|
||||||
env_key = "ROLE_PROVIDER_API_KEY"
|
|
||||||
wire_api = "responses"
|
|
||||||
|
|
||||||
[profiles.base-profile]
|
|
||||||
model_provider = "base-provider"
|
|
||||||
|
|
||||||
[profiles.role-profile]
|
|
||||||
model_provider = "role-provider"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("write config.toml");
|
|
||||||
let mut config = ConfigBuilder::default()
|
|
||||||
.codex_home(home.path().to_path_buf())
|
|
||||||
.harness_overrides(ConfigOverrides {
|
|
||||||
config_profile: Some("base-profile".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.fallback_cwd(Some(home.path().to_path_buf()))
|
|
||||||
.build()
|
|
||||||
.await
|
|
||||||
.expect("load config");
|
|
||||||
let role_path = write_role_config(
|
|
||||||
&home,
|
|
||||||
"profile-role.toml",
|
|
||||||
"developer_instructions = \"Stay focused\"\nprofile = \"role-profile\"",
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
config.agent_roles.insert(
|
|
||||||
"custom".to_string(),
|
|
||||||
AgentRoleConfig {
|
|
||||||
description: None,
|
|
||||||
config_file: Some(role_path),
|
|
||||||
nickname_candidates: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
apply_role_to_config(&mut config, Some("custom"))
|
|
||||||
.await
|
|
||||||
.expect("custom role should apply");
|
|
||||||
|
|
||||||
assert_eq!(config.active_profile.as_deref(), Some("role-profile"));
|
|
||||||
assert_eq!(config.model_provider_id, "role-provider");
|
|
||||||
assert_eq!(config.model_provider.name, "Role Provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn apply_role_uses_role_model_provider_instead_of_current_profile_provider() {
|
|
||||||
let home = TempDir::new().expect("create temp dir");
|
|
||||||
tokio::fs::write(
|
|
||||||
home.path().join(CONFIG_TOML_FILE),
|
|
||||||
r#"
|
|
||||||
[model_providers.base-provider]
|
|
||||||
name = "Base Provider"
|
|
||||||
base_url = "https://base.example.com/v1"
|
|
||||||
env_key = "BASE_PROVIDER_API_KEY"
|
|
||||||
wire_api = "responses"
|
|
||||||
|
|
||||||
[model_providers.role-provider]
|
|
||||||
name = "Role Provider"
|
|
||||||
base_url = "https://role.example.com/v1"
|
|
||||||
env_key = "ROLE_PROVIDER_API_KEY"
|
|
||||||
wire_api = "responses"
|
|
||||||
|
|
||||||
[profiles.base-profile]
|
|
||||||
model_provider = "base-provider"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("write config.toml");
|
|
||||||
let mut config = ConfigBuilder::default()
|
|
||||||
.codex_home(home.path().to_path_buf())
|
|
||||||
.harness_overrides(ConfigOverrides {
|
|
||||||
config_profile: Some("base-profile".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.fallback_cwd(Some(home.path().to_path_buf()))
|
|
||||||
.build()
|
|
||||||
.await
|
|
||||||
.expect("load config");
|
|
||||||
let role_path = write_role_config(
|
|
||||||
&home,
|
|
||||||
"provider-role.toml",
|
|
||||||
"developer_instructions = \"Stay focused\"\nmodel_provider = \"role-provider\"",
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
config.agent_roles.insert(
|
|
||||||
"custom".to_string(),
|
|
||||||
AgentRoleConfig {
|
|
||||||
description: None,
|
|
||||||
config_file: Some(role_path),
|
|
||||||
nickname_candidates: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
apply_role_to_config(&mut config, Some("custom"))
|
|
||||||
.await
|
|
||||||
.expect("custom role should apply");
|
|
||||||
|
|
||||||
assert_eq!(config.active_profile, None);
|
|
||||||
assert_eq!(config.model_provider_id, "role-provider");
|
|
||||||
assert_eq!(config.model_provider.name, "Role Provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn apply_role_uses_active_profile_model_provider_update() {
|
|
||||||
let home = TempDir::new().expect("create temp dir");
|
|
||||||
tokio::fs::write(
|
|
||||||
home.path().join(CONFIG_TOML_FILE),
|
|
||||||
r#"
|
|
||||||
[model_providers.base-provider]
|
|
||||||
name = "Base Provider"
|
|
||||||
base_url = "https://base.example.com/v1"
|
|
||||||
env_key = "BASE_PROVIDER_API_KEY"
|
|
||||||
wire_api = "responses"
|
|
||||||
|
|
||||||
[model_providers.role-provider]
|
|
||||||
name = "Role Provider"
|
|
||||||
base_url = "https://role.example.com/v1"
|
|
||||||
env_key = "ROLE_PROVIDER_API_KEY"
|
|
||||||
wire_api = "responses"
|
|
||||||
|
|
||||||
[profiles.base-profile]
|
|
||||||
model_provider = "base-provider"
|
|
||||||
model_reasoning_effort = "low"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("write config.toml");
|
|
||||||
let mut config = ConfigBuilder::default()
|
|
||||||
.codex_home(home.path().to_path_buf())
|
|
||||||
.harness_overrides(ConfigOverrides {
|
|
||||||
config_profile: Some("base-profile".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.fallback_cwd(Some(home.path().to_path_buf()))
|
|
||||||
.build()
|
|
||||||
.await
|
|
||||||
.expect("load config");
|
|
||||||
let role_path = write_role_config(
|
|
||||||
&home,
|
|
||||||
"profile-edit-role.toml",
|
|
||||||
r#"developer_instructions = "Stay focused"
|
|
||||||
|
|
||||||
[profiles.base-profile]
|
|
||||||
model_provider = "role-provider"
|
|
||||||
model_reasoning_effort = "high"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
config.agent_roles.insert(
|
|
||||||
"custom".to_string(),
|
|
||||||
AgentRoleConfig {
|
|
||||||
description: None,
|
|
||||||
config_file: Some(role_path),
|
|
||||||
nickname_candidates: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
apply_role_to_config(&mut config, Some("custom"))
|
|
||||||
.await
|
|
||||||
.expect("custom role should apply");
|
|
||||||
|
|
||||||
assert_eq!(config.active_profile.as_deref(), Some("base-profile"));
|
|
||||||
assert_eq!(config.model_provider_id, "role-provider");
|
|
||||||
assert_eq!(config.model_provider.name, "Role Provider");
|
|
||||||
assert_eq!(config.model_reasoning_effort, Some(ReasoningEffort::High));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
async fn apply_role_does_not_materialize_default_sandbox_workspace_write_fields() {
|
async fn apply_role_does_not_materialize_default_sandbox_workspace_write_fields() {
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
+61
-179
@@ -34,7 +34,6 @@ use codex_config::config_toml::validate_model_providers;
|
|||||||
use codex_config::loader::load_config_layers_state;
|
use codex_config::loader::load_config_layers_state;
|
||||||
use codex_config::loader::project_trust_key;
|
use codex_config::loader::project_trust_key;
|
||||||
use codex_config::permissions_toml::PermissionsToml;
|
use codex_config::permissions_toml::PermissionsToml;
|
||||||
use codex_config::profile_toml::ConfigProfile;
|
|
||||||
use codex_config::sandbox_mode_requirement_for_permission_profile;
|
use codex_config::sandbox_mode_requirement_for_permission_profile;
|
||||||
use codex_config::types::ApprovalsReviewer;
|
use codex_config::types::ApprovalsReviewer;
|
||||||
use codex_config::types::AuthCredentialsStoreMode;
|
use codex_config::types::AuthCredentialsStoreMode;
|
||||||
@@ -2033,7 +2032,6 @@ fn resolve_permission_config_syntax(
|
|||||||
config_layer_stack: &ConfigLayerStack,
|
config_layer_stack: &ConfigLayerStack,
|
||||||
cfg: &ConfigToml,
|
cfg: &ConfigToml,
|
||||||
sandbox_mode_override: Option<SandboxMode>,
|
sandbox_mode_override: Option<SandboxMode>,
|
||||||
profile_sandbox_mode: Option<SandboxMode>,
|
|
||||||
) -> Option<PermissionConfigSyntax> {
|
) -> Option<PermissionConfigSyntax> {
|
||||||
if sandbox_mode_override.is_some() {
|
if sandbox_mode_override.is_some() {
|
||||||
return Some(PermissionConfigSyntax::Legacy);
|
return Some(PermissionConfigSyntax::Legacy);
|
||||||
@@ -2058,10 +2056,6 @@ fn resolve_permission_config_syntax(
|
|||||||
return Some(PermissionConfigSyntax::Profiles);
|
return Some(PermissionConfigSyntax::Profiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if profile_sandbox_mode.is_some() {
|
|
||||||
return Some(PermissionConfigSyntax::Legacy);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut selection = None;
|
let mut selection = None;
|
||||||
for layer in config_layer_stack.get_layers(
|
for layer in config_layer_stack.get_layers(
|
||||||
ConfigLayerStackOrdering::LowestPrecedenceFirst,
|
ConfigLayerStackOrdering::LowestPrecedenceFirst,
|
||||||
@@ -2134,7 +2128,6 @@ pub struct ConfigOverrides {
|
|||||||
pub default_permissions: Option<String>,
|
pub default_permissions: Option<String>,
|
||||||
pub model_provider: Option<String>,
|
pub model_provider: Option<String>,
|
||||||
pub service_tier: Option<Option<String>>,
|
pub service_tier: Option<Option<String>>,
|
||||||
pub config_profile: Option<String>,
|
|
||||||
pub codex_self_exe: Option<PathBuf>,
|
pub codex_self_exe: Option<PathBuf>,
|
||||||
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||||
pub main_execve_wrapper_exe: Option<PathBuf>,
|
pub main_execve_wrapper_exe: Option<PathBuf>,
|
||||||
@@ -2159,41 +2152,23 @@ fn dedupe_absolute_paths(paths: &mut Vec<AbsolutePathBuf>) {
|
|||||||
paths.retain(|path| seen.insert(path.clone()));
|
paths.retain(|path| seen.insert(path.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves the OSS provider from CLI override, profile config, or global config.
|
/// Resolves the OSS provider from CLI override or global config.
|
||||||
/// Returns `None` if no provider is configured at any level.
|
/// Returns `None` if no provider is configured at any level.
|
||||||
pub fn resolve_oss_provider(
|
pub fn resolve_oss_provider(
|
||||||
explicit_provider: Option<&str>,
|
explicit_provider: Option<&str>,
|
||||||
config_toml: &ConfigToml,
|
config_toml: &ConfigToml,
|
||||||
config_profile: Option<String>,
|
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
if let Some(provider) = explicit_provider {
|
if let Some(provider) = explicit_provider {
|
||||||
// Explicit provider specified (e.g., via --local-provider)
|
// Explicit provider specified (e.g., via --local-provider)
|
||||||
Some(provider.to_string())
|
Some(provider.to_string())
|
||||||
} else {
|
} else {
|
||||||
// Check profile config first, then global config
|
config_toml.oss_provider.clone()
|
||||||
let profile = config_toml.get_config_profile(config_profile).ok();
|
|
||||||
if let Some(profile) = &profile {
|
|
||||||
// Check if profile has an oss provider
|
|
||||||
if let Some(profile_oss_provider) = &profile.oss_provider {
|
|
||||||
Some(profile_oss_provider.clone())
|
|
||||||
}
|
|
||||||
// If not then check if the toml has an oss provider
|
|
||||||
else {
|
|
||||||
config_toml.oss_provider.clone()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
config_toml.oss_provider.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve the web search mode from explicit config and feature flags.
|
/// Resolve the web search mode from explicit config and feature flags.
|
||||||
fn resolve_web_search_mode(
|
fn resolve_web_search_mode(config_toml: &ConfigToml, features: &Features) -> Option<WebSearchMode> {
|
||||||
config_toml: &ConfigToml,
|
if let Some(mode) = config_toml.web_search {
|
||||||
config_profile: &ConfigProfile,
|
|
||||||
features: &Features,
|
|
||||||
) -> Option<WebSearchMode> {
|
|
||||||
if let Some(mode) = config_profile.web_search.or(config_toml.web_search) {
|
|
||||||
return Some(mode);
|
return Some(mode);
|
||||||
}
|
}
|
||||||
if features.enabled(Feature::WebSearchCached) {
|
if features.enabled(Feature::WebSearchCached) {
|
||||||
@@ -2205,82 +2180,55 @@ fn resolve_web_search_mode(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_web_search_config(
|
fn resolve_web_search_config(config_toml: &ConfigToml) -> Option<WebSearchConfig> {
|
||||||
config_toml: &ConfigToml,
|
config_toml
|
||||||
config_profile: &ConfigProfile,
|
|
||||||
) -> Option<WebSearchConfig> {
|
|
||||||
let base = config_toml
|
|
||||||
.tools
|
.tools
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|tools| tools.web_search.as_ref());
|
.and_then(|tools| tools.web_search.as_ref())
|
||||||
let profile = config_profile
|
.cloned()
|
||||||
.tools
|
.map(Into::into)
|
||||||
.as_ref()
|
|
||||||
.and_then(|tools| tools.web_search.as_ref());
|
|
||||||
|
|
||||||
match (base, profile) {
|
|
||||||
(None, None) => None,
|
|
||||||
(Some(base), None) => Some(base.clone().into()),
|
|
||||||
(None, Some(profile)) => Some(profile.clone().into()),
|
|
||||||
(Some(base), Some(profile)) => Some(base.merge(profile).into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_multi_agent_v2_config(
|
fn resolve_multi_agent_v2_config(config_toml: &ConfigToml) -> MultiAgentV2Config {
|
||||||
config_toml: &ConfigToml,
|
|
||||||
config_profile: &ConfigProfile,
|
|
||||||
) -> MultiAgentV2Config {
|
|
||||||
let base = multi_agent_v2_toml_config(config_toml.features.as_ref());
|
let base = multi_agent_v2_toml_config(config_toml.features.as_ref());
|
||||||
let profile = multi_agent_v2_toml_config(config_profile.features.as_ref());
|
|
||||||
let default = MultiAgentV2Config::default();
|
let default = MultiAgentV2Config::default();
|
||||||
|
|
||||||
let max_concurrent_threads_per_session = profile
|
let max_concurrent_threads_per_session = base
|
||||||
.and_then(|config| config.max_concurrent_threads_per_session)
|
.and_then(|config| config.max_concurrent_threads_per_session)
|
||||||
.or_else(|| base.and_then(|config| config.max_concurrent_threads_per_session))
|
|
||||||
.unwrap_or(default.max_concurrent_threads_per_session);
|
.unwrap_or(default.max_concurrent_threads_per_session);
|
||||||
let min_wait_timeout_ms = profile
|
let min_wait_timeout_ms = base
|
||||||
.and_then(|config| config.min_wait_timeout_ms)
|
.and_then(|config| config.min_wait_timeout_ms)
|
||||||
.or_else(|| base.and_then(|config| config.min_wait_timeout_ms))
|
|
||||||
.unwrap_or(default.min_wait_timeout_ms);
|
.unwrap_or(default.min_wait_timeout_ms);
|
||||||
let max_wait_timeout_ms = profile
|
let max_wait_timeout_ms = base
|
||||||
.and_then(|config| config.max_wait_timeout_ms)
|
.and_then(|config| config.max_wait_timeout_ms)
|
||||||
.or_else(|| base.and_then(|config| config.max_wait_timeout_ms))
|
|
||||||
.unwrap_or(default.max_wait_timeout_ms);
|
.unwrap_or(default.max_wait_timeout_ms);
|
||||||
let default_wait_timeout_ms = profile
|
let default_wait_timeout_ms = base
|
||||||
.and_then(|config| config.default_wait_timeout_ms)
|
.and_then(|config| config.default_wait_timeout_ms)
|
||||||
.or_else(|| base.and_then(|config| config.default_wait_timeout_ms))
|
|
||||||
.unwrap_or(default.default_wait_timeout_ms);
|
.unwrap_or(default.default_wait_timeout_ms);
|
||||||
let usage_hint_enabled = profile
|
let usage_hint_enabled = base
|
||||||
.and_then(|config| config.usage_hint_enabled)
|
.and_then(|config| config.usage_hint_enabled)
|
||||||
.or_else(|| base.and_then(|config| config.usage_hint_enabled))
|
|
||||||
.unwrap_or(default.usage_hint_enabled);
|
.unwrap_or(default.usage_hint_enabled);
|
||||||
let usage_hint_text = profile
|
let usage_hint_text = base
|
||||||
.and_then(|config| config.usage_hint_text.as_ref())
|
.and_then(|config| config.usage_hint_text.as_ref())
|
||||||
.or_else(|| base.and_then(|config| config.usage_hint_text.as_ref()))
|
|
||||||
.cloned()
|
.cloned()
|
||||||
.or(default.usage_hint_text);
|
.or(default.usage_hint_text);
|
||||||
let root_agent_usage_hint_text = profile
|
let root_agent_usage_hint_text = base
|
||||||
.and_then(|config| config.root_agent_usage_hint_text.as_ref())
|
.and_then(|config| config.root_agent_usage_hint_text.as_ref())
|
||||||
.or_else(|| base.and_then(|config| config.root_agent_usage_hint_text.as_ref()))
|
|
||||||
.cloned()
|
.cloned()
|
||||||
.or(default.root_agent_usage_hint_text);
|
.or(default.root_agent_usage_hint_text);
|
||||||
let subagent_usage_hint_text = profile
|
let subagent_usage_hint_text = base
|
||||||
.and_then(|config| config.subagent_usage_hint_text.as_ref())
|
.and_then(|config| config.subagent_usage_hint_text.as_ref())
|
||||||
.or_else(|| base.and_then(|config| config.subagent_usage_hint_text.as_ref()))
|
|
||||||
.cloned()
|
.cloned()
|
||||||
.or(default.subagent_usage_hint_text);
|
.or(default.subagent_usage_hint_text);
|
||||||
let tool_namespace = profile
|
let tool_namespace = base
|
||||||
.and_then(|config| config.tool_namespace.as_ref())
|
.and_then(|config| config.tool_namespace.as_ref())
|
||||||
.or_else(|| base.and_then(|config| config.tool_namespace.as_ref()))
|
|
||||||
.cloned()
|
.cloned()
|
||||||
.or(default.tool_namespace);
|
.or(default.tool_namespace);
|
||||||
let hide_spawn_agent_metadata = profile
|
let hide_spawn_agent_metadata = base
|
||||||
.and_then(|config| config.hide_spawn_agent_metadata)
|
.and_then(|config| config.hide_spawn_agent_metadata)
|
||||||
.or_else(|| base.and_then(|config| config.hide_spawn_agent_metadata))
|
|
||||||
.unwrap_or(default.hide_spawn_agent_metadata);
|
.unwrap_or(default.hide_spawn_agent_metadata);
|
||||||
let non_code_mode_only = profile
|
let non_code_mode_only = base
|
||||||
.and_then(|config| config.non_code_mode_only)
|
.and_then(|config| config.non_code_mode_only)
|
||||||
.or_else(|| base.and_then(|config| config.non_code_mode_only))
|
|
||||||
.unwrap_or(default.non_code_mode_only);
|
.unwrap_or(default.non_code_mode_only);
|
||||||
|
|
||||||
MultiAgentV2Config {
|
MultiAgentV2Config {
|
||||||
@@ -2531,7 +2479,6 @@ impl Config {
|
|||||||
default_permissions: default_permissions_override,
|
default_permissions: default_permissions_override,
|
||||||
model_provider,
|
model_provider,
|
||||||
service_tier: service_tier_override,
|
service_tier: service_tier_override,
|
||||||
config_profile: config_profile_key,
|
|
||||||
codex_self_exe,
|
codex_self_exe,
|
||||||
codex_linux_sandbox_exe,
|
codex_linux_sandbox_exe,
|
||||||
main_execve_wrapper_exe,
|
main_execve_wrapper_exe,
|
||||||
@@ -2574,24 +2521,15 @@ impl Config {
|
|||||||
"`permission_profile` and `default_permissions` overrides cannot both be set",
|
"`permission_profile` and `default_permissions` overrides cannot both be set",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if let Some(profile) = cfg.profile.as_deref() {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::InvalidData,
|
||||||
|
format!(
|
||||||
|
"legacy `profile = \"{profile}\"` config is no longer supported; use `--profile {profile}` with `{profile}.config.toml` instead"
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let active_profile_name = config_profile_key
|
|
||||||
.as_ref()
|
|
||||||
.or(cfg.profile.as_ref())
|
|
||||||
.cloned();
|
|
||||||
let config_profile = match active_profile_name.as_ref() {
|
|
||||||
Some(key) => cfg
|
|
||||||
.profiles
|
|
||||||
.get(key)
|
|
||||||
.ok_or_else(|| {
|
|
||||||
std::io::Error::new(
|
|
||||||
std::io::ErrorKind::NotFound,
|
|
||||||
format!("config profile `{key}` not found"),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.clone(),
|
|
||||||
None => ConfigProfile::default(),
|
|
||||||
};
|
|
||||||
let tool_suggest = resolve_tool_suggest_config(&cfg, &config_layer_stack);
|
let tool_suggest = resolve_tool_suggest_config(&cfg, &config_layer_stack);
|
||||||
let feature_overrides = FeatureOverrides {
|
let feature_overrides = FeatureOverrides {
|
||||||
web_search_request: override_tools_web_search_request,
|
web_search_request: override_tools_web_search_request,
|
||||||
@@ -2603,9 +2541,7 @@ impl Config {
|
|||||||
experimental_use_unified_exec_tool: cfg.experimental_use_unified_exec_tool,
|
experimental_use_unified_exec_tool: cfg.experimental_use_unified_exec_tool,
|
||||||
},
|
},
|
||||||
FeatureConfigSource {
|
FeatureConfigSource {
|
||||||
features: config_profile.features.as_ref(),
|
..Default::default()
|
||||||
experimental_use_unified_exec_tool: config_profile
|
|
||||||
.experimental_use_unified_exec_tool,
|
|
||||||
},
|
},
|
||||||
feature_overrides,
|
feature_overrides,
|
||||||
);
|
);
|
||||||
@@ -2615,9 +2551,8 @@ impl Config {
|
|||||||
&mut startup_warnings,
|
&mut startup_warnings,
|
||||||
)?;
|
)?;
|
||||||
let enable_network_proxy = features.enabled(Feature::NetworkProxy);
|
let enable_network_proxy = features.enabled(Feature::NetworkProxy);
|
||||||
let windows_sandbox_mode = resolve_windows_sandbox_mode(&cfg, &config_profile);
|
let windows_sandbox_mode = resolve_windows_sandbox_mode(&cfg);
|
||||||
let windows_sandbox_private_desktop =
|
let windows_sandbox_private_desktop = resolve_windows_sandbox_private_desktop(&cfg);
|
||||||
resolve_windows_sandbox_private_desktop(&cfg, &config_profile);
|
|
||||||
let resolved_cwd = AbsolutePathBuf::try_from(normalize_for_native_workdir({
|
let resolved_cwd = AbsolutePathBuf::try_from(normalize_for_native_workdir({
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
@@ -2651,7 +2586,6 @@ impl Config {
|
|||||||
&config_layer_stack,
|
&config_layer_stack,
|
||||||
&cfg,
|
&cfg,
|
||||||
sandbox_mode,
|
sandbox_mode,
|
||||||
config_profile.sandbox_mode,
|
|
||||||
);
|
);
|
||||||
let requirements_toml = config_layer_stack.requirements_toml();
|
let requirements_toml = config_layer_stack.requirements_toml();
|
||||||
let effective_permission_selection = resolve_effective_permission_selection(
|
let effective_permission_selection = resolve_effective_permission_selection(
|
||||||
@@ -2908,7 +2842,7 @@ impl Config {
|
|||||||
let mut permission_profile = cfg
|
let mut permission_profile = cfg
|
||||||
.derive_permission_profile(
|
.derive_permission_profile(
|
||||||
sandbox_mode,
|
sandbox_mode,
|
||||||
config_profile.sandbox_mode,
|
/*profile_sandbox_mode*/ None,
|
||||||
windows_sandbox_level,
|
windows_sandbox_level,
|
||||||
Some(&active_project),
|
Some(&active_project),
|
||||||
Some(&constrained_permission_profile),
|
Some(&constrained_permission_profile),
|
||||||
@@ -2965,20 +2899,11 @@ impl Config {
|
|||||||
network_proxy,
|
network_proxy,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let Some(network_proxy) = network_proxy_toml_config(config_profile.features.as_ref())
|
|
||||||
{
|
|
||||||
apply_network_proxy_feature_config(
|
|
||||||
&mut configured_network_proxy_config,
|
|
||||||
network_proxy,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
configured_network_proxy_config.network.enabled = true;
|
configured_network_proxy_config.network.enabled = true;
|
||||||
}
|
}
|
||||||
let approval_policy_was_explicit = approval_policy_override.is_some()
|
let approval_policy_was_explicit =
|
||||||
|| config_profile.approval_policy.is_some()
|
approval_policy_override.is_some() || cfg.approval_policy.is_some();
|
||||||
|| cfg.approval_policy.is_some();
|
|
||||||
let mut approval_policy = approval_policy_override
|
let mut approval_policy = approval_policy_override
|
||||||
.or(config_profile.approval_policy)
|
|
||||||
.or(cfg.approval_policy)
|
.or(cfg.approval_policy)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
if active_project.is_trusted() {
|
if active_project.is_trusted() {
|
||||||
@@ -2998,11 +2923,9 @@ impl Config {
|
|||||||
);
|
);
|
||||||
approval_policy = constrained_approval_policy.value();
|
approval_policy = constrained_approval_policy.value();
|
||||||
}
|
}
|
||||||
let approvals_reviewer_was_explicit = approvals_reviewer_override.is_some()
|
let approvals_reviewer_was_explicit =
|
||||||
|| config_profile.approvals_reviewer.is_some()
|
approvals_reviewer_override.is_some() || cfg.approvals_reviewer.is_some();
|
||||||
|| cfg.approvals_reviewer.is_some();
|
|
||||||
let mut approvals_reviewer = approvals_reviewer_override
|
let mut approvals_reviewer = approvals_reviewer_override
|
||||||
.or(config_profile.approvals_reviewer)
|
|
||||||
.or(cfg.approvals_reviewer)
|
.or(cfg.approvals_reviewer)
|
||||||
.unwrap_or(ApprovalsReviewer::User);
|
.unwrap_or(ApprovalsReviewer::User);
|
||||||
if !approvals_reviewer_was_explicit
|
if !approvals_reviewer_was_explicit
|
||||||
@@ -3014,16 +2937,13 @@ impl Config {
|
|||||||
);
|
);
|
||||||
approvals_reviewer = constrained_approvals_reviewer.value();
|
approvals_reviewer = constrained_approvals_reviewer.value();
|
||||||
}
|
}
|
||||||
let web_search_mode = resolve_web_search_mode(&cfg, &config_profile, &features)
|
let web_search_mode =
|
||||||
.unwrap_or(WebSearchMode::Cached);
|
resolve_web_search_mode(&cfg, &features).unwrap_or(WebSearchMode::Cached);
|
||||||
let web_search_config = resolve_web_search_config(&cfg, &config_profile);
|
let web_search_config = resolve_web_search_config(&cfg);
|
||||||
let multi_agent_v2 = resolve_multi_agent_v2_config(&cfg, &config_profile);
|
let multi_agent_v2 = resolve_multi_agent_v2_config(&cfg);
|
||||||
let apps_mcp_path_override = if features.enabled(Feature::AppsMcpPathOverride) {
|
let apps_mcp_path_override = if features.enabled(Feature::AppsMcpPathOverride) {
|
||||||
let base = apps_mcp_path_override_toml_config(cfg.features.as_ref());
|
let base = apps_mcp_path_override_toml_config(cfg.features.as_ref());
|
||||||
let profile = apps_mcp_path_override_toml_config(config_profile.features.as_ref());
|
base.and_then(|config| config.path.as_ref())
|
||||||
profile
|
|
||||||
.and_then(|config| config.path.as_ref())
|
|
||||||
.or_else(|| base.and_then(|config| config.path.as_ref()))
|
|
||||||
.cloned()
|
.cloned()
|
||||||
.or_else(|| Some("/ps/mcp".to_string()))
|
.or_else(|| Some("/ps/mcp".to_string()))
|
||||||
} else {
|
} else {
|
||||||
@@ -3045,7 +2965,6 @@ impl Config {
|
|||||||
.map_err(|message| std::io::Error::new(std::io::ErrorKind::InvalidData, message))?;
|
.map_err(|message| std::io::Error::new(std::io::ErrorKind::InvalidData, message))?;
|
||||||
|
|
||||||
let model_provider_id = model_provider
|
let model_provider_id = model_provider
|
||||||
.or(config_profile.model_provider)
|
|
||||||
.or(cfg.model_provider)
|
.or(cfg.model_provider)
|
||||||
.unwrap_or_else(|| "openai".to_string());
|
.unwrap_or_else(|| "openai".to_string());
|
||||||
let model_provider = model_providers
|
let model_provider = model_providers
|
||||||
@@ -3207,12 +3126,12 @@ impl Config {
|
|||||||
|
|
||||||
let forced_login_method = cfg.forced_login_method;
|
let forced_login_method = cfg.forced_login_method;
|
||||||
|
|
||||||
let model = model.or(config_profile.model).or(cfg.model);
|
let model = model.or(cfg.model);
|
||||||
let notices = cfg.notice.unwrap_or_default();
|
let notices = cfg.notice.unwrap_or_default();
|
||||||
let service_tier = match service_tier_override {
|
let service_tier = match service_tier_override {
|
||||||
Some(Some(service_tier)) => Some(service_tier),
|
Some(Some(service_tier)) => Some(service_tier),
|
||||||
Some(None) => Some(SERVICE_TIER_DEFAULT_REQUEST_VALUE.to_string()),
|
Some(None) => Some(SERVICE_TIER_DEFAULT_REQUEST_VALUE.to_string()),
|
||||||
None => config_profile.service_tier.or(cfg.service_tier),
|
None => cfg.service_tier,
|
||||||
};
|
};
|
||||||
let service_tier = service_tier.and_then(|service_tier| {
|
let service_tier = service_tier.and_then(|service_tier| {
|
||||||
match ServiceTier::from_request_value(&service_tier) {
|
match ServiceTier::from_request_value(&service_tier) {
|
||||||
@@ -3236,10 +3155,7 @@ impl Config {
|
|||||||
// Load base instructions override from a file if specified. If the
|
// Load base instructions override from a file if specified. If the
|
||||||
// path is relative, resolve it against the effective cwd so the
|
// path is relative, resolve it against the effective cwd so the
|
||||||
// behaviour matches other path-like config values.
|
// behaviour matches other path-like config values.
|
||||||
let model_instructions_path = config_profile
|
let model_instructions_path = cfg.model_instructions_file.as_ref();
|
||||||
.model_instructions_file
|
|
||||||
.as_ref()
|
|
||||||
.or(cfg.model_instructions_file.as_ref());
|
|
||||||
let file_base_instructions = Self::try_read_non_empty_file(
|
let file_base_instructions = Self::try_read_non_empty_file(
|
||||||
fs,
|
fs,
|
||||||
model_instructions_path,
|
model_instructions_path,
|
||||||
@@ -3250,27 +3166,16 @@ impl Config {
|
|||||||
.or(file_base_instructions)
|
.or(file_base_instructions)
|
||||||
.or(cfg.instructions.clone());
|
.or(cfg.instructions.clone());
|
||||||
let developer_instructions = developer_instructions.or(cfg.developer_instructions);
|
let developer_instructions = developer_instructions.or(cfg.developer_instructions);
|
||||||
let include_permissions_instructions = config_profile
|
let include_permissions_instructions = cfg.include_permissions_instructions.unwrap_or(true);
|
||||||
.include_permissions_instructions
|
let include_apps_instructions = cfg.include_apps_instructions.unwrap_or(true);
|
||||||
.or(cfg.include_permissions_instructions)
|
let include_collaboration_mode_instructions =
|
||||||
.unwrap_or(true);
|
cfg.include_collaboration_mode_instructions.unwrap_or(true);
|
||||||
let include_apps_instructions = config_profile
|
|
||||||
.include_apps_instructions
|
|
||||||
.or(cfg.include_apps_instructions)
|
|
||||||
.unwrap_or(true);
|
|
||||||
let include_collaboration_mode_instructions = config_profile
|
|
||||||
.include_collaboration_mode_instructions
|
|
||||||
.or(cfg.include_collaboration_mode_instructions)
|
|
||||||
.unwrap_or(true);
|
|
||||||
let include_skill_instructions = cfg
|
let include_skill_instructions = cfg
|
||||||
.skills
|
.skills
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|skills| skills.include_instructions)
|
.and_then(|skills| skills.include_instructions)
|
||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
let include_environment_context = config_profile
|
let include_environment_context = cfg.include_environment_context.unwrap_or(true);
|
||||||
.include_environment_context
|
|
||||||
.or(cfg.include_environment_context)
|
|
||||||
.unwrap_or(true);
|
|
||||||
let guardian_policy_config =
|
let guardian_policy_config =
|
||||||
guardian_policy_config_from_requirements(config_layer_stack.requirements_toml())
|
guardian_policy_config_from_requirements(config_layer_stack.requirements_toml())
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
@@ -3281,7 +3186,6 @@ impl Config {
|
|||||||
))
|
))
|
||||||
});
|
});
|
||||||
let personality = personality
|
let personality = personality
|
||||||
.or(config_profile.personality)
|
|
||||||
.or(cfg.personality)
|
.or(cfg.personality)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
features
|
features
|
||||||
@@ -3289,10 +3193,7 @@ impl Config {
|
|||||||
.then_some(Personality::Pragmatic)
|
.then_some(Personality::Pragmatic)
|
||||||
});
|
});
|
||||||
|
|
||||||
let experimental_compact_prompt_path = config_profile
|
let experimental_compact_prompt_path = cfg.experimental_compact_prompt_file.as_ref();
|
||||||
.experimental_compact_prompt_file
|
|
||||||
.as_ref()
|
|
||||||
.or(cfg.experimental_compact_prompt_file.as_ref());
|
|
||||||
let file_compact_prompt = Self::try_read_non_empty_file(
|
let file_compact_prompt = Self::try_read_non_empty_file(
|
||||||
fs,
|
fs,
|
||||||
experimental_compact_prompt_path,
|
experimental_compact_prompt_path,
|
||||||
@@ -3300,19 +3201,12 @@ impl Config {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let compact_prompt = compact_prompt.or(file_compact_prompt);
|
let compact_prompt = compact_prompt.or(file_compact_prompt);
|
||||||
let zsh_path = zsh_path_override
|
let zsh_path = zsh_path_override.or(cfg.zsh_path.map(Into::into));
|
||||||
.or(config_profile.zsh_path.map(Into::into))
|
|
||||||
.or(cfg.zsh_path.map(Into::into));
|
|
||||||
|
|
||||||
let review_model = override_review_model.or(cfg.review_model);
|
let review_model = override_review_model.or(cfg.review_model);
|
||||||
|
|
||||||
let check_for_update_on_startup = cfg.check_for_update_on_startup.unwrap_or(true);
|
let check_for_update_on_startup = cfg.check_for_update_on_startup.unwrap_or(true);
|
||||||
let model_catalog = load_model_catalog(
|
let model_catalog = load_model_catalog(cfg.model_catalog_json.clone())?;
|
||||||
config_profile
|
|
||||||
.model_catalog_json
|
|
||||||
.clone()
|
|
||||||
.or(cfg.model_catalog_json.clone()),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let log_dir = cfg
|
let log_dir = cfg
|
||||||
.log_dir
|
.log_dir
|
||||||
@@ -3558,21 +3452,14 @@ impl Config {
|
|||||||
.or(show_raw_agent_reasoning)
|
.or(show_raw_agent_reasoning)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
guardian_policy_config,
|
guardian_policy_config,
|
||||||
model_reasoning_effort: config_profile
|
model_reasoning_effort: cfg.model_reasoning_effort,
|
||||||
.model_reasoning_effort
|
plan_mode_reasoning_effort: cfg.plan_mode_reasoning_effort,
|
||||||
.or(cfg.model_reasoning_effort),
|
model_reasoning_summary: cfg.model_reasoning_summary,
|
||||||
plan_mode_reasoning_effort: config_profile
|
|
||||||
.plan_mode_reasoning_effort
|
|
||||||
.or(cfg.plan_mode_reasoning_effort),
|
|
||||||
model_reasoning_summary: config_profile
|
|
||||||
.model_reasoning_summary
|
|
||||||
.or(cfg.model_reasoning_summary),
|
|
||||||
model_supports_reasoning_summaries: cfg.model_supports_reasoning_summaries,
|
model_supports_reasoning_summaries: cfg.model_supports_reasoning_summaries,
|
||||||
model_catalog,
|
model_catalog,
|
||||||
model_verbosity: config_profile.model_verbosity.or(cfg.model_verbosity),
|
model_verbosity: cfg.model_verbosity,
|
||||||
chatgpt_base_url: config_profile
|
chatgpt_base_url: cfg
|
||||||
.chatgpt_base_url
|
.chatgpt_base_url
|
||||||
.or(cfg.chatgpt_base_url)
|
|
||||||
.unwrap_or("https://chatgpt.com/backend-api/".to_string()),
|
.unwrap_or("https://chatgpt.com/backend-api/".to_string()),
|
||||||
apps_mcp_path_override,
|
apps_mcp_path_override,
|
||||||
apps_mcp_product_sku: cfg.apps_mcp_product_sku.clone(),
|
apps_mcp_product_sku: cfg.apps_mcp_product_sku.clone(),
|
||||||
@@ -3612,16 +3499,12 @@ impl Config {
|
|||||||
suppress_unstable_features_warning: cfg
|
suppress_unstable_features_warning: cfg
|
||||||
.suppress_unstable_features_warning
|
.suppress_unstable_features_warning
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
active_profile: active_profile_name,
|
active_profile: None,
|
||||||
active_project,
|
active_project,
|
||||||
notices,
|
notices,
|
||||||
check_for_update_on_startup,
|
check_for_update_on_startup,
|
||||||
disable_paste_burst: cfg.disable_paste_burst.unwrap_or(false),
|
disable_paste_burst: cfg.disable_paste_burst.unwrap_or(false),
|
||||||
analytics_enabled: config_profile
|
analytics_enabled: cfg.analytics.as_ref().and_then(|a| a.enabled),
|
||||||
.analytics
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|a| a.enabled)
|
|
||||||
.or(cfg.analytics.as_ref().and_then(|a| a.enabled)),
|
|
||||||
feedback_enabled: cfg
|
feedback_enabled: cfg
|
||||||
.feedback
|
.feedback
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -3669,11 +3552,10 @@ impl Config {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|t| t.pet_anchor)
|
.map(|t| t.pet_anchor)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
tui_session_picker_view: config_profile
|
tui_session_picker_view: cfg
|
||||||
.tui
|
.tui
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|t| t.session_picker_view)
|
.and_then(|t| t.session_picker_view)
|
||||||
.or_else(|| cfg.tui.as_ref().and_then(|t| t.session_picker_view))
|
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
terminal_resize_reflow,
|
terminal_resize_reflow,
|
||||||
tui_keymap: cfg
|
tui_keymap: cfg
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::config::edit::ConfigEditsBuilder;
|
use crate::config::edit::ConfigEditsBuilder;
|
||||||
use codex_config::config_toml::ConfigToml;
|
use codex_config::config_toml::ConfigToml;
|
||||||
use codex_config::profile_toml::ConfigProfile;
|
|
||||||
use codex_config::types::WindowsSandboxModeToml;
|
use codex_config::types::WindowsSandboxModeToml;
|
||||||
use codex_features::Feature;
|
use codex_features::Feature;
|
||||||
use codex_features::Features;
|
use codex_features::Features;
|
||||||
@@ -56,47 +55,20 @@ pub fn windows_sandbox_level_from_features(features: &Features) -> WindowsSandbo
|
|||||||
WindowsSandboxLevel::from_features(features)
|
WindowsSandboxLevel::from_features(features)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_windows_sandbox_mode(
|
pub fn resolve_windows_sandbox_mode(cfg: &ConfigToml) -> Option<WindowsSandboxModeToml> {
|
||||||
cfg: &ConfigToml,
|
cfg.windows
|
||||||
profile: &ConfigProfile,
|
|
||||||
) -> Option<WindowsSandboxModeToml> {
|
|
||||||
if let Some(mode) = legacy_windows_sandbox_mode(profile.features.as_ref()) {
|
|
||||||
return Some(mode);
|
|
||||||
}
|
|
||||||
if legacy_windows_sandbox_keys_present(profile.features.as_ref()) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
profile
|
|
||||||
.windows
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|windows| windows.sandbox)
|
.and_then(|windows| windows.sandbox)
|
||||||
.or_else(|| cfg.windows.as_ref().and_then(|windows| windows.sandbox))
|
|
||||||
.or_else(|| legacy_windows_sandbox_mode(cfg.features.as_ref()))
|
.or_else(|| legacy_windows_sandbox_mode(cfg.features.as_ref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_windows_sandbox_private_desktop(cfg: &ConfigToml, profile: &ConfigProfile) -> bool {
|
pub fn resolve_windows_sandbox_private_desktop(cfg: &ConfigToml) -> bool {
|
||||||
profile
|
cfg.windows
|
||||||
.windows
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|windows| windows.sandbox_private_desktop)
|
.and_then(|windows| windows.sandbox_private_desktop)
|
||||||
.or_else(|| {
|
|
||||||
cfg.windows
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|windows| windows.sandbox_private_desktop)
|
|
||||||
})
|
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn legacy_windows_sandbox_keys_present(features: Option<&FeaturesToml>) -> bool {
|
|
||||||
let Some(entries) = features.map(FeaturesToml::entries) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
entries.contains_key(Feature::WindowsSandboxElevated.key())
|
|
||||||
|| entries.contains_key(Feature::WindowsSandbox.key())
|
|
||||||
|| entries.contains_key("enable_experimental_windows_sandbox")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn legacy_windows_sandbox_mode(
|
pub fn legacy_windows_sandbox_mode(
|
||||||
features: Option<&FeaturesToml>,
|
features: Option<&FeaturesToml>,
|
||||||
) -> Option<WindowsSandboxModeToml> {
|
) -> Option<WindowsSandboxModeToml> {
|
||||||
|
|||||||
@@ -78,29 +78,6 @@ fn legacy_mode_supports_alias_key() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn resolve_windows_sandbox_mode_prefers_profile_windows() {
|
|
||||||
let cfg = ConfigToml {
|
|
||||||
windows: Some(WindowsToml {
|
|
||||||
sandbox: Some(WindowsSandboxModeToml::Unelevated),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let profile = ConfigProfile {
|
|
||||||
windows: Some(WindowsToml {
|
|
||||||
sandbox: Some(WindowsSandboxModeToml::Elevated),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
resolve_windows_sandbox_mode(&cfg, &profile),
|
|
||||||
Some(WindowsSandboxModeToml::Elevated)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_windows_sandbox_mode_falls_back_to_legacy_keys() {
|
fn resolve_windows_sandbox_mode_falls_back_to_legacy_keys() {
|
||||||
let mut entries = BTreeMap::new();
|
let mut entries = BTreeMap::new();
|
||||||
@@ -114,61 +91,15 @@ fn resolve_windows_sandbox_mode_falls_back_to_legacy_keys() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve_windows_sandbox_mode(&cfg, &ConfigProfile::default()),
|
resolve_windows_sandbox_mode(&cfg),
|
||||||
Some(WindowsSandboxModeToml::Unelevated)
|
Some(WindowsSandboxModeToml::Unelevated)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn resolve_windows_sandbox_mode_profile_legacy_false_blocks_top_level_legacy_true() {
|
|
||||||
let mut profile_entries = BTreeMap::new();
|
|
||||||
profile_entries.insert(
|
|
||||||
"experimental_windows_sandbox".to_string(),
|
|
||||||
/*value*/ false,
|
|
||||||
);
|
|
||||||
let profile = ConfigProfile {
|
|
||||||
features: Some(FeaturesToml::from(profile_entries)),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut cfg_entries = BTreeMap::new();
|
|
||||||
cfg_entries.insert(
|
|
||||||
"experimental_windows_sandbox".to_string(),
|
|
||||||
/*value*/ true,
|
|
||||||
);
|
|
||||||
let cfg = ConfigToml {
|
|
||||||
features: Some(FeaturesToml::from(cfg_entries)),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(resolve_windows_sandbox_mode(&cfg, &profile), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn resolve_windows_sandbox_private_desktop_prefers_profile_windows() {
|
|
||||||
let cfg = ConfigToml {
|
|
||||||
windows: Some(WindowsToml {
|
|
||||||
sandbox: Some(WindowsSandboxModeToml::Unelevated),
|
|
||||||
sandbox_private_desktop: Some(false),
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let profile = ConfigProfile {
|
|
||||||
windows: Some(WindowsToml {
|
|
||||||
sandbox: Some(WindowsSandboxModeToml::Elevated),
|
|
||||||
sandbox_private_desktop: Some(true),
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert!(resolve_windows_sandbox_private_desktop(&cfg, &profile));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_windows_sandbox_private_desktop_defaults_to_true() {
|
fn resolve_windows_sandbox_private_desktop_defaults_to_true() {
|
||||||
assert!(resolve_windows_sandbox_private_desktop(
|
assert!(resolve_windows_sandbox_private_desktop(
|
||||||
&ConfigToml::default(),
|
&ConfigToml::default()
|
||||||
&ConfigProfile::default()
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,8 +113,5 @@ fn resolve_windows_sandbox_private_desktop_respects_explicit_cfg_value() {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(!resolve_windows_sandbox_private_desktop(
|
assert!(!resolve_windows_sandbox_private_desktop(&cfg));
|
||||||
&cfg,
|
|
||||||
&ConfigProfile::default()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
@@ -375,11 +375,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
|
|||||||
let run_cloud_requirements = cloud_requirements.clone();
|
let run_cloud_requirements = cloud_requirements.clone();
|
||||||
|
|
||||||
let model_provider = if oss {
|
let model_provider = if oss {
|
||||||
let resolved = resolve_oss_provider(
|
let resolved = resolve_oss_provider(oss_provider.as_deref(), &config_toml);
|
||||||
oss_provider.as_deref(),
|
|
||||||
&config_toml,
|
|
||||||
/*config_profile*/ None,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(provider) = resolved {
|
if let Some(provider) = resolved {
|
||||||
Some(provider)
|
Some(provider)
|
||||||
@@ -418,7 +414,6 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
|
|||||||
workspace_roots: None,
|
workspace_roots: None,
|
||||||
model_provider: model_provider.clone(),
|
model_provider: model_provider.clone(),
|
||||||
service_tier: None,
|
service_tier: None,
|
||||||
config_profile: None,
|
|
||||||
codex_self_exe: arg0_paths.codex_self_exe.clone(),
|
codex_self_exe: arg0_paths.codex_self_exe.clone(),
|
||||||
codex_linux_sandbox_exe: arg0_paths.codex_linux_sandbox_exe.clone(),
|
codex_linux_sandbox_exe: arg0_paths.codex_linux_sandbox_exe.clone(),
|
||||||
main_execve_wrapper_exe: arg0_paths.main_execve_wrapper_exe.clone(),
|
main_execve_wrapper_exe: arg0_paths.main_execve_wrapper_exe.clone(),
|
||||||
|
|||||||
@@ -29,10 +29,6 @@ pub struct CodexToolCallParam {
|
|||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub model: Option<String>,
|
pub model: Option<String>,
|
||||||
|
|
||||||
/// Configuration profile from config.toml to specify default options.
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub profile: Option<String>,
|
|
||||||
|
|
||||||
/// Working directory for the session. If relative, it is resolved against
|
/// Working directory for the session. If relative, it is resolved against
|
||||||
/// the server process's current working directory.
|
/// the server process's current working directory.
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
@@ -160,7 +156,6 @@ impl CodexToolCallParam {
|
|||||||
let Self {
|
let Self {
|
||||||
prompt,
|
prompt,
|
||||||
model,
|
model,
|
||||||
profile,
|
|
||||||
cwd,
|
cwd,
|
||||||
approval_policy,
|
approval_policy,
|
||||||
sandbox,
|
sandbox,
|
||||||
@@ -173,7 +168,6 @@ impl CodexToolCallParam {
|
|||||||
// Build the `ConfigOverrides` recognized by codex-core.
|
// Build the `ConfigOverrides` recognized by codex-core.
|
||||||
let overrides = ConfigOverrides {
|
let overrides = ConfigOverrides {
|
||||||
model,
|
model,
|
||||||
config_profile: profile,
|
|
||||||
cwd: cwd.map(PathBuf::from),
|
cwd: cwd.map(PathBuf::from),
|
||||||
approval_policy: approval_policy.map(Into::into),
|
approval_policy: approval_policy.map(Into::into),
|
||||||
sandbox_mode: sandbox.map(Into::into),
|
sandbox_mode: sandbox.map(Into::into),
|
||||||
@@ -345,10 +339,6 @@ mod tests {
|
|||||||
"description": "Optional override for the model name (e.g. 'gpt-5.2', 'gpt-5.2-codex').",
|
"description": "Optional override for the model name (e.g. 'gpt-5.2', 'gpt-5.2-codex').",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"profile": {
|
|
||||||
"description": "Configuration profile from config.toml to specify default options.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"description": "The *initial user prompt* to start the Codex conversation.",
|
"description": "The *initial user prompt* to start the Codex conversation.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|||||||
@@ -994,11 +994,7 @@ pub async fn run_main(
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
let model_provider_override = if cli.oss {
|
let model_provider_override = if cli.oss {
|
||||||
let resolved = resolve_oss_provider(
|
let resolved = resolve_oss_provider(cli.oss_provider.as_deref(), &config_toml);
|
||||||
cli.oss_provider.as_deref(),
|
|
||||||
&config_toml,
|
|
||||||
/*config_profile*/ None,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(provider) = resolved {
|
if let Some(provider) = resolved {
|
||||||
Some(provider)
|
Some(provider)
|
||||||
|
|||||||
Reference in new issue
Block a user