feat: update default (#4076)

Changes:
- Default model and docs now use gpt-5-codex. 
- Disables the GPT-5 Codex NUX by default.
- Keeps presets available for API key users.
This commit is contained in:
Thibault Sottiaux
2025-09-22 20:10:52 -07:00
committed by GitHub
parent c415827ac2
commit c93e77b68b
14 changed files with 136 additions and 52 deletions

View File

@@ -37,7 +37,7 @@ use toml_edit::DocumentMut;
use toml_edit::Item as TomlItem;
use toml_edit::Table as TomlTable;
const OPENAI_DEFAULT_MODEL: &str = "gpt-5";
const OPENAI_DEFAULT_MODEL: &str = "gpt-5-codex";
const OPENAI_DEFAULT_REVIEW_MODEL: &str = "gpt-5-codex";
pub const GPT_5_CODEX_MEDIUM_MODEL: &str = "gpt-5-codex";
@@ -54,7 +54,7 @@ pub struct Config {
/// Optional override of model selection.
pub model: String,
/// Model used specifically for review sessions. Defaults to "gpt-5".
/// Model used specifically for review sessions. Defaults to "gpt-5-codex".
pub review_model: String,
pub model_family: ModelFamily,
@@ -1366,7 +1366,7 @@ startup_timeout_ms = 2500
tokio::fs::write(
&config_path,
r#"
model = "gpt-5"
model = "gpt-5-codex"
model_reasoning_effort = "medium"
[profiles.dev]
@@ -1441,7 +1441,7 @@ model = "gpt-4"
model_reasoning_effort = "medium"
[profiles.prod]
model = "gpt-5"
model = "gpt-5-codex"
"#,
)
.await?;
@@ -1472,7 +1472,7 @@ model = "gpt-5"
.profiles
.get("prod")
.and_then(|profile| profile.model.as_deref()),
Some("gpt-5"),
Some("gpt-5-codex"),
);
Ok(())

View File

@@ -228,7 +228,7 @@ mod tests {
codex_home,
None,
&[
(&[CONFIG_KEY_MODEL], "gpt-5"),
(&[CONFIG_KEY_MODEL], "gpt-5-codex"),
(&[CONFIG_KEY_EFFORT], "high"),
],
)
@@ -236,7 +236,7 @@ mod tests {
.expect("persist");
let contents = read_config(codex_home).await;
let expected = r#"model = "gpt-5"
let expected = r#"model = "gpt-5-codex"
model_reasoning_effort = "high"
"#;
assert_eq!(contents, expected);
@@ -348,7 +348,7 @@ model_reasoning_effort = "high"
&[
(&["a", "b", "c"], "v"),
(&["x"], "y"),
(&["profiles", "p1", CONFIG_KEY_MODEL], "gpt-5"),
(&["profiles", "p1", CONFIG_KEY_MODEL], "gpt-5-codex"),
],
)
.await
@@ -361,7 +361,7 @@ model_reasoning_effort = "high"
c = "v"
[profiles.p1]
model = "gpt-5"
model = "gpt-5-codex"
"#;
assert_eq!(contents, expected);
}
@@ -454,7 +454,7 @@ existing = "keep"
codex_home,
None,
&[
(&[CONFIG_KEY_MODEL], "gpt-5"),
(&[CONFIG_KEY_MODEL], "gpt-5-codex"),
(&[CONFIG_KEY_EFFORT], "minimal"),
],
)
@@ -466,7 +466,7 @@ existing = "keep"
# should be preserved
existing = "keep"
model = "gpt-5"
model = "gpt-5-codex"
model_reasoning_effort = "minimal"
"#;
assert_eq!(contents, expected);
@@ -524,7 +524,7 @@ model = "o3"
let codex_home = tmpdir.path();
// Seed with a model value only
let seed = "model = \"gpt-5\"\n";
let seed = "model = \"gpt-5-codex\"\n";
tokio::fs::write(codex_home.join(CONFIG_TOML_FILE), seed)
.await
.expect("seed write");
@@ -535,7 +535,7 @@ model = "o3"
.expect("persist");
let contents = read_config(codex_home).await;
let expected = r#"model = "gpt-5"
let expected = r#"model = "gpt-5-codex"
model_reasoning_effort = "high"
"#;
assert_eq!(contents, expected);
@@ -579,7 +579,7 @@ model = "o4-mini"
// No active profile key; we'll target an explicit override
let seed = r#"[profiles.team]
model = "gpt-5"
model = "gpt-5-codex"
"#;
tokio::fs::write(codex_home.join(CONFIG_TOML_FILE), seed)
.await
@@ -595,7 +595,7 @@ model = "gpt-5"
let contents = read_config(codex_home).await;
let expected = r#"[profiles.team]
model = "gpt-5"
model = "gpt-5-codex"
model_reasoning_effort = "minimal"
"#;
assert_eq!(contents, expected);
@@ -611,7 +611,7 @@ model_reasoning_effort = "minimal"
codex_home,
None,
&[
(&[CONFIG_KEY_MODEL], Some("gpt-5")),
(&[CONFIG_KEY_MODEL], Some("gpt-5-codex")),
(&[CONFIG_KEY_EFFORT], None),
],
)
@@ -619,7 +619,7 @@ model_reasoning_effort = "minimal"
.expect("persist");
let contents = read_config(codex_home).await;
let expected = "model = \"gpt-5\"\n";
let expected = "model = \"gpt-5-codex\"\n";
assert_eq!(contents, expected);
}
@@ -670,7 +670,7 @@ model = "o3"
let tmpdir = tempdir().expect("tmp");
let codex_home = tmpdir.path();
let seed = r#"model = "gpt-5"
let seed = r#"model = "gpt-5-codex"
model_reasoning_effort = "medium"
"#;
tokio::fs::write(codex_home.join(CONFIG_TOML_FILE), seed)

View File

@@ -7,14 +7,27 @@ use std::path::PathBuf;
pub(crate) const INTERNAL_STORAGE_FILE: &str = "internal_storage.json";
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InternalStorage {
#[serde(skip)]
storage_path: PathBuf,
#[serde(default)]
#[serde(default = "default_gpt_5_codex_model_prompt_seen")]
pub gpt_5_codex_model_prompt_seen: bool,
}
const fn default_gpt_5_codex_model_prompt_seen() -> bool {
true
}
impl Default for InternalStorage {
fn default() -> Self {
Self {
storage_path: PathBuf::new(),
gpt_5_codex_model_prompt_seen: default_gpt_5_codex_model_prompt_seen(),
}
}
}
// TODO(jif) generalise all the file writers and build proper async channel inserters.
impl InternalStorage {
pub fn load(codex_home: &Path) -> Self {

View File

@@ -822,7 +822,7 @@ async fn token_count_includes_rate_limits_snapshot() {
"reasoning_output_tokens": 0,
"total_tokens": 123
},
// Default model is gpt-5 in tests → 272000 context window
// Default model is gpt-5-codex in tests → 272000 context window
"model_context_window": 272000
},
"rate_limits": {

View File

@@ -133,7 +133,7 @@ async fn compact_resume_and_fork_preserve_model_history_view() {
.to_string();
let user_turn_1 = json!(
{
"model": "gpt-5",
"model": "gpt-5-codex",
"instructions": prompt,
"input": [
{
@@ -182,7 +182,7 @@ async fn compact_resume_and_fork_preserve_model_history_view() {
});
let compact_1 = json!(
{
"model": "gpt-5",
"model": "gpt-5-codex",
"instructions": "You have exceeded the maximum number of tokens, please stop coding and instead write a short memento message for the next agent. Your note should:
- Summarize what you finished and what still needs work. If there was a recent update_plan call, repeat its steps verbatim.
- List outstanding TODOs with file paths / line numbers so they're easy to find.
@@ -255,7 +255,7 @@ async fn compact_resume_and_fork_preserve_model_history_view() {
});
let user_turn_2_after_compact = json!(
{
"model": "gpt-5",
"model": "gpt-5-codex",
"instructions": prompt,
"input": [
{
@@ -320,7 +320,7 @@ SUMMARY_ONLY_CONTEXT"
});
let usert_turn_3_after_resume = json!(
{
"model": "gpt-5",
"model": "gpt-5-codex",
"instructions": prompt,
"input": [
{
@@ -405,7 +405,7 @@ SUMMARY_ONLY_CONTEXT"
});
let user_turn_3_after_fork = json!(
{
"model": "gpt-5",
"model": "gpt-5-codex",
"instructions": prompt,
"input": [
{

View File

@@ -184,6 +184,7 @@ async fn prompt_tools_are_consistent_across_requests() {
let conversation_manager =
ConversationManager::with_auth(CodexAuth::from_api_key("Test API Key"));
let expected_instructions = config.model_family.base_instructions.clone();
let codex = conversation_manager
.new_conversation(config)
.await
@@ -213,7 +214,6 @@ async fn prompt_tools_are_consistent_across_requests() {
let requests = server.received_requests().await.unwrap();
assert_eq!(requests.len(), 2, "expected two POST requests");
let expected_instructions: &str = include_str!("../../prompt.md");
// our internal implementation is responsible for keeping tools in sync
// with the OpenAI schema, so we just verify the tool presence here
let expected_tools_names: &[&str] = &["shell", "update_plan", "apply_patch", "view_image"];