Stop applying managed defaults during thread start

This commit is contained in:
hefuc-oai
2026-06-25 22:52:38 +00:00
parent 09f52a37d6
commit 0f3877f5b3
3 changed files with 2 additions and 201 deletions
@@ -3,7 +3,6 @@ use crate::error_code::method_not_found;
use codex_app_server_protocol::SelectedCapabilityRoot;
use codex_extension_api::ExtensionDataInit;
use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::config_types::ServiceTier;
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS;
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE;
@@ -1045,26 +1044,6 @@ impl ThreadRequestProcessor {
) -> Result<(), JSONRPCErrorError> {
let thread_start_started_at = std::time::Instant::now();
let requested_cwd = typesafe_overrides.cwd.clone();
let current_cli_overrides = config_manager.current_cli_overrides();
let has_cli_override = |key: &str| {
current_cli_overrides
.iter()
.any(|(path, _value)| path == key)
};
let has_explicit_model = has_cli_override("model")
|| typesafe_overrides.model.is_some()
|| config_overrides
.as_ref()
.is_some_and(|overrides| overrides.contains_key("model"));
let has_explicit_reasoning_effort = has_cli_override("model_reasoning_effort")
|| config_overrides
.as_ref()
.is_some_and(|overrides| overrides.contains_key("model_reasoning_effort"));
let has_explicit_service_tier = has_cli_override("service_tier")
|| typesafe_overrides.service_tier.is_some()
|| config_overrides
.as_ref()
.is_some_and(|overrides| overrides.contains_key("service_tier"));
let mut config = config_manager
.load_with_overrides(config_overrides.clone(), typesafe_overrides.clone())
.await
@@ -1089,6 +1068,7 @@ impl ThreadRequestProcessor {
let trust_target = resolve_root_git_project_for_trust(LOCAL_FS.as_ref(), &config.cwd)
.await
.unwrap_or_else(|| config.cwd.clone());
let current_cli_overrides = config_manager.current_cli_overrides();
let cli_overrides_with_trust;
let cli_overrides_for_reload = if let Err(err) =
codex_core::config::set_project_trust_level(
@@ -1134,31 +1114,6 @@ impl ThreadRequestProcessor {
.map_err(|err| config_load_error(&err))?;
}
if let Some(defaults) = config
.config_layer_stack
.requirements_toml()
.models
.as_ref()
.and_then(|models| models.new_thread.as_ref())
{
if !has_explicit_model && let Some(model) = defaults.model.as_ref() {
config.model = Some(model.clone());
}
if !has_explicit_reasoning_effort
&& let Some(reasoning_effort) = defaults.model_reasoning_effort.as_ref()
{
config.model_reasoning_effort = Some(reasoning_effort.clone());
}
if !has_explicit_service_tier && let Some(service_tier) = defaults.service_tier.as_ref()
{
config.service_tier = Some(
ServiceTier::from_request_value(service_tier)
.map(|tier| tier.request_value().to_string())
.unwrap_or_else(|| service_tier.clone()),
);
}
}
let environments = environments.unwrap_or_else(|| {
listener_task_context
.thread_manager
@@ -160,13 +160,6 @@ impl TestAppServer {
/// URL-based configuration, this helper rejects a `codex_home` containing
/// that file.
pub async fn new_with_auto_env(codex_home: &Path) -> anyhow::Result<Self> {
Self::new_with_auto_env_and_args(codex_home, &[]).await
}
pub async fn new_with_auto_env_and_args(
codex_home: &Path,
args: &[&str],
) -> anyhow::Result<Self> {
let environments_toml = codex_home.join("environments.toml");
ensure!(
!environments_toml
@@ -189,10 +182,7 @@ impl TestAppServer {
(CODEX_EXEC_SERVER_NOISE_AUTH_TOKEN_ENV_VAR, None),
(CODEX_EXEC_SERVER_NOISE_CHATGPT_ACCOUNT_ID_ENV_VAR, None),
];
let mut all_args = vec![DISABLE_PLUGIN_STARTUP_TASKS_ARG];
all_args.extend_from_slice(args);
let mut app_server =
Self::new_with_env_and_args(codex_home, &env_overrides, &all_args).await?;
let mut app_server = Self::new_with_env(codex_home, &env_overrides).await?;
app_server.auto_env = Some(auto_env);
Ok(app_server)
}
@@ -27,7 +27,6 @@ use codex_app_server_protocol::UserInput as V2UserInput;
use codex_config::loader::project_trust_key;
use codex_config::types::AuthCredentialsStoreMode;
use codex_core::config::set_project_trust_level;
use codex_core::test_support::all_model_presets;
use codex_exec_server::LOCAL_FS;
use codex_git_utils::resolve_root_git_project_for_trust;
use codex_login::REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR;
@@ -37,7 +36,6 @@ use codex_protocol::openai_models::ReasoningEffort;
use pretty_assertions::assert_eq;
use serde_json::Value;
use serde_json::json;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use tempfile::TempDir;
@@ -201,117 +199,6 @@ async fn thread_start_creates_thread_and_emits_started() -> Result<()> {
Ok(())
}
#[tokio::test]
async fn thread_start_treats_managed_new_thread_model_settings_as_defaults() -> Result<()> {
let server = create_mock_responses_server_repeating_assistant("Done").await;
let codex_home = TempDir::new()?;
let managed_model =
create_config_with_managed_new_thread_defaults(codex_home.path(), &server.uri())?;
let mut mcp = TestAppServer::new_with_auto_env(codex_home.path()).await?;
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
let default_request_id = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams::default())
.await?;
let default_response: JSONRPCResponse = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_response_message(RequestId::Integer(default_request_id)),
)
.await??;
let default_response: ThreadStartResponse = to_response(default_response)?;
assert_eq!(
(
default_response.model.as_str(),
default_response.reasoning_effort,
default_response.service_tier.as_deref(),
),
(
managed_model.as_str(),
Some(ReasoningEffort::Medium),
Some("priority"),
)
);
let explicit_request_id = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("gpt-5.2".to_string()),
service_tier: Some(Some(SERVICE_TIER_DEFAULT_REQUEST_VALUE.to_string())),
config: Some(HashMap::from([(
"model_reasoning_effort".to_string(),
json!("low"),
)])),
..Default::default()
})
.await?;
let explicit_response: JSONRPCResponse = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_response_message(RequestId::Integer(explicit_request_id)),
)
.await??;
let explicit_response: ThreadStartResponse = to_response(explicit_response)?;
assert_eq!(
(
explicit_response.model.as_str(),
explicit_response.reasoning_effort,
explicit_response.service_tier.as_deref(),
),
(
"gpt-5.2",
Some(ReasoningEffort::Low),
Some(SERVICE_TIER_DEFAULT_REQUEST_VALUE),
)
);
Ok(())
}
#[tokio::test]
async fn thread_start_process_cli_overrides_managed_new_thread_defaults() -> Result<()> {
let server = create_mock_responses_server_repeating_assistant("Done").await;
let codex_home = TempDir::new()?;
create_config_with_managed_new_thread_defaults(codex_home.path(), &server.uri())?;
let mut mcp = TestAppServer::new_with_auto_env_and_args(
codex_home.path(),
&[
"-c",
"model=gpt-5.2",
"-c",
"model_reasoning_effort=low",
"-c",
"service_tier=default",
],
)
.await?;
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
let request_id = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams::default())
.await?;
let response: JSONRPCResponse = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_response_message(RequestId::Integer(request_id)),
)
.await??;
let response: ThreadStartResponse = to_response(response)?;
assert_eq!(
(
response.model.as_str(),
response.reasoning_effort,
response.service_tier.as_deref(),
),
(
"gpt-5.2",
Some(ReasoningEffort::Low),
Some(SERVICE_TIER_DEFAULT_REQUEST_VALUE),
)
);
Ok(())
}
#[tokio::test]
async fn thread_start_accepts_absolute_runtime_workspace_roots() -> Result<()> {
let server = create_mock_responses_server_repeating_assistant("Done").await;
@@ -1300,37 +1187,6 @@ model_reasoning_effort = "high"
Ok(())
}
fn create_config_with_managed_new_thread_defaults(
codex_home: &Path,
server_uri: &str,
) -> Result<String> {
create_config_toml_without_approval_policy(codex_home, server_uri)?;
let managed_model = all_model_presets()
.iter()
.find(|preset| {
preset.id != "gpt-5.2"
&& preset
.service_tiers
.iter()
.any(|tier| tier.id == "priority")
})
.context("expected a model with the fast service tier")?
.id
.clone();
std::fs::write(
codex_home.join("requirements.toml"),
format!(
r#"
[models.new_thread]
model = "{managed_model}"
model_reasoning_effort = "medium"
service_tier = "fast"
"#
),
)?;
Ok(managed_model)
}
fn create_config_toml_without_approval_policy(
codex_home: &Path,
server_uri: &str,