mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
## Why #29683 exposes managed defaults for new-thread model settings through `configRequirements/read` without applying them server-wide. The TUI is an app-server client, so it should explicitly consume those defaults when it creates a fresh thread. This lets plain `codex` start on the managed model while preserving the existing ability to change model settings within the thread. ## What changed - Read `requirements.models.newThread` during TUI app-server bootstrap. - Apply the managed model, reasoning effort, and service tier to the initial fresh thread and subsequent `/new` or `/clear` threads. - Keep explicit launch overrides above the managed defaults. - Normalize the managed `fast` service tier to the `priority` request value. - Leave resumed and forked threads unchanged. The application logic lives in a small TUI-only module; app-server `thread/start` behavior remains unchanged for other clients. ## User experience - Plain `codex` starts with the managed new-thread settings. - A user can still change settings with `/model` or the existing service-tier controls. - Starting another fresh thread reapplies the managed defaults. - Explicit launch choices such as `codex -m <model>` continue to win. ## Validation - `just test -p codex-tui managed_new_thread_defaults` - `just fix -p codex-tui` Depends on #29683.
52 lines
2.2 KiB
Rust
52 lines
2.2 KiB
Rust
use crate::legacy_core::config::Config;
|
|
use crate::legacy_core::config::ConfigOverrides;
|
|
use codex_app_server_protocol::NewThreadModelDefaults;
|
|
use codex_protocol::config_types::ServiceTier;
|
|
use toml::Value as TomlValue;
|
|
|
|
pub(crate) fn apply_managed_new_thread_defaults(
|
|
config: &mut Config,
|
|
defaults: Option<&NewThreadModelDefaults>,
|
|
cli_kv_overrides: &[(String, TomlValue)],
|
|
harness_overrides: &ConfigOverrides,
|
|
) {
|
|
let Some(defaults) = defaults else {
|
|
return;
|
|
};
|
|
// Managed values are defaults rather than enforcement. Preserve explicit launch choices from
|
|
// dedicated flags such as `-m` (`harness_overrides`) and generic `-c key=value` settings
|
|
// (`cli_kv_overrides`), then fill only the fields that were not selected for this invocation.
|
|
// Model and reasoning effort are a compatibility-sensitive pair, so an explicit override of
|
|
// either opts out of both managed values. For example, `codex -m gpt-5.4` keeps that model and
|
|
// its existing/default effort, while `-c model_reasoning_effort=low` does not switch to the
|
|
// managed model. Service tier remains independent and is resolved against the selected model
|
|
// before the thread starts.
|
|
let has_cli_override = |key: &str| cli_kv_overrides.iter().any(|(path, _value)| path == key);
|
|
let has_explicit_model_settings = harness_overrides.model.is_some()
|
|
|| has_cli_override("model")
|
|
|| has_cli_override("model_reasoning_effort");
|
|
|
|
if !has_explicit_model_settings && let Some(model) = defaults.model.as_ref() {
|
|
config.model = Some(model.clone());
|
|
}
|
|
if !has_explicit_model_settings
|
|
&& let Some(reasoning_effort) = defaults.model_reasoning_effort.as_ref()
|
|
{
|
|
config.model_reasoning_effort = Some(reasoning_effort.clone());
|
|
}
|
|
if harness_overrides.service_tier.is_none()
|
|
&& !has_cli_override("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()),
|
|
);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "managed_new_thread_defaults_tests.rs"]
|
|
mod tests;
|