Update models.json (#21818)

Automated update of models.json.

---------

Co-authored-by: aibrahim-oai <219906144+aibrahim-oai@users.noreply.github.com>
Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
Co-authored-by: Sayan Sisodiya <sayan@openai.com>
This commit is contained in:
github-actions[bot]
2026-07-08 16:24:12 -07:00
committed by GitHub
co-authored by aibrahim-oai Ahmed Ibrahim Sayan Sisodiya
parent 3eb56537eb
commit b780738014
32 changed files with 236 additions and 283 deletions
@@ -640,7 +640,7 @@ async fn thread_resume_tracks_thread_initialized_analytics() -> Result<()> {
&thread.id,
&thread.session_id,
"codex_work_desktop",
"gpt-5.3-codex",
"gpt-5.4",
"resumed",
"user",
);
@@ -2143,7 +2143,7 @@ async fn thread_resume_prefers_persisted_git_metadata_for_local_threads() -> Res
&config_toml,
format!(
r#"
model = "gpt-5.3-codex"
model = "gpt-5.4"
approval_policy = "never"
sandbox_mode = "read-only"
@@ -3972,7 +3972,7 @@ async fn thread_resume_accepts_personality_override() -> Result<()> {
let start_id = primary
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("gpt-5.3-codex".to_string()),
model: Some("gpt-5.4".to_string()),
..Default::default()
})
.await?;
@@ -4014,7 +4014,7 @@ async fn thread_resume_accepts_personality_override() -> Result<()> {
let resume_id = secondary
.send_thread_resume_request(ThreadResumeParams {
thread_id: thread.id,
model: Some("gpt-5.3-codex".to_string()),
model: Some("gpt-5.4".to_string()),
personality: Some(Personality::Friendly),
..Default::default()
})
@@ -4077,7 +4077,7 @@ fn create_config_toml(codex_home: &std::path::Path, server_uri: &str) -> std::io
config_toml,
format!(
r#"
model = "gpt-5.3-codex"
model = "gpt-5.4"
approval_policy = "never"
sandbox_mode = "read-only"
@@ -4107,7 +4107,7 @@ fn create_config_toml_with_chatgpt_base_url(
config_toml,
format!(
r#"
model = "gpt-5.3-codex"
model = "gpt-5.4"
approval_policy = "never"
sandbox_mode = "read-only"
chatgpt_base_url = "{chatgpt_base_url}"
@@ -4137,7 +4137,7 @@ fn create_config_toml_with_required_broken_mcp(
config_toml,
format!(
r#"
model = "gpt-5.3-codex"
model = "gpt-5.4"
approval_policy = "never"
sandbox_mode = "read-only"
@@ -1579,7 +1579,7 @@ async fn turn_start_accepts_collaboration_mode_override_v2() -> Result<()> {
let thread_req = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("gpt-5.3-codex".to_string()),
model: Some("gpt-5.4".to_string()),
..Default::default()
})
.await?;
@@ -1668,7 +1668,7 @@ async fn turn_start_uses_thread_feature_overrides_for_request_user_input_tool_de
let thread_req = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("gpt-5.3-codex".to_string()),
model: Some("gpt-5.4".to_string()),
config: Some(HashMap::from([(
"features.default_mode_request_user_input".to_string(),
json!(true),
@@ -2138,7 +2138,7 @@ async fn turn_start_uses_migrated_pragmatic_personality_without_override_v2() ->
let thread_req = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("gpt-5.3-codex".to_string()),
model: Some("gpt-5.4".to_string()),
..Default::default()
})
.await?;
@@ -3535,7 +3535,7 @@ async fn turn_start_emits_spawn_agent_item_with_model_metadata_v2() -> Result<()
let thread_req = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("gpt-5.3-codex".to_string()),
model: Some("gpt-5.4".to_string()),
..Default::default()
})
.await?;
@@ -3756,7 +3756,7 @@ async fn direct_input_to_multi_agent_v2_subagent_is_rejected() -> Result<()> {
let thread_req = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("gpt-5.3-codex".to_string()),
model: Some("gpt-5.4".to_string()),
..Default::default()
})
.await?;
@@ -3937,7 +3937,7 @@ config_file = "./custom-role.toml"
let thread_req = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("gpt-5.3-codex".to_string()),
model: Some("gpt-5.4".to_string()),
..Default::default()
})
.await?;
+1 -1
View File
@@ -1254,7 +1254,7 @@ async fn get_base_instructions_no_user_content() {
expects_apply_patch_description: false,
},
InstructionsTestCase {
slug: "gpt-5.3-codex",
slug: "gpt-5.5",
expects_apply_patch_description: false,
},
InstructionsTestCase {
@@ -548,7 +548,7 @@ async fn spawn_agent_service_tier_override_validates_the_effective_child_model()
"spawn_agent",
function_payload(json!({
"message": "inspect this repo",
"model": "gpt-5.3-codex",
"model": "gpt-5.4-mini",
"service_tier": ServiceTier::Fast.request_value()
})),
))
@@ -559,7 +559,7 @@ async fn spawn_agent_service_tier_override_validates_the_effective_child_model()
assert_eq!(
err,
FunctionCallError::RespondToModel(
"Service tier `priority` is not supported for model `gpt-5.3-codex`. Supported service tiers: none"
"Service tier `priority` is not supported for model `gpt-5.4-mini`. Supported service tiers: none"
.to_string()
)
);
@@ -637,7 +637,7 @@ async fn spawn_agent_service_tier_inheritance_preserves_supported_or_configured_
"spawn_agent",
function_payload(json!({
"message": "inspect this repo",
"model": "gpt-5.3-codex"
"model": "gpt-5.4-mini"
})),
))
.await
+2 -2
View File
@@ -36,7 +36,7 @@ async fn websocket_model_switch_to_responses_lite_omits_top_level_tools() -> Res
.with_model_info_override("gpt-5.4", |model_info| {
model_info.use_responses_lite = true;
})
.with_model("gpt-5.3-codex");
.with_model("gpt-5.2");
let test = builder.build_with_websocket_server(&server).await?;
test.submit_turn("non-lite turn").await?;
@@ -72,7 +72,7 @@ async fn websocket_model_switch_to_responses_lite_omits_top_level_tools() -> Res
.expect("missing lite turn request")
.body_json();
assert_eq!(non_lite_turn["model"].as_str(), Some("gpt-5.3-codex"));
assert_eq!(non_lite_turn["model"].as_str(), Some("gpt-5.2"));
assert_eq!(lite_turn["model"].as_str(), Some("gpt-5.4"));
assert!(
non_lite_turn
@@ -62,7 +62,7 @@ use tempfile::TempDir;
use tracing::Instrument;
use tracing_test::traced_test;
const MODEL: &str = "gpt-5.3-codex";
const MODEL: &str = "gpt-5.4";
const OPENAI_BETA_HEADER: &str = "OpenAI-Beta";
const USER_AGENT_HEADER: &str = "user-agent";
const WS_V2_BETA_HEADER_VALUE: &str = "responses_websockets=2026-02-06";
+3 -3
View File
@@ -2880,7 +2880,7 @@ async fn code_mode_resizes_explicit_original_image() -> Result<()> {
&server,
"use exec to return a large original-detail image",
&code,
"gpt-5.3-codex",
"gpt-5.4",
|_| {},
)
.await?;
@@ -2950,7 +2950,7 @@ async fn code_mode_can_use_view_image_result_with_image_helper() -> Result<()> {
let server = responses::start_mock_server().await;
let mut builder = test_codex()
.with_model("gpt-5.3-codex")
.with_model("gpt-5.4")
.with_config(move |config| {
let _ = config.features.enable(Feature::CodeMode);
});
@@ -3044,7 +3044,7 @@ image(imageItem);
&server,
"use exec to call the rmcp image scenario tool and emit its image output",
code,
"gpt-5.3-codex",
"gpt-5.4",
)
.await?;
+8 -8
View File
@@ -2108,7 +2108,7 @@ async fn pre_sampling_compact_runs_on_switch_to_smaller_context_model() {
skip_if_no_network!();
let server = MockServer::start().await;
let previous_model = "gpt-5.3-codex";
let previous_model = "gpt-5.4";
let next_model = "gpt-5.2";
let models_mock = mount_models_once(
@@ -2210,7 +2210,7 @@ async fn pre_sampling_compact_runs_when_comp_hash_changes() {
skip_if_no_network!();
let server = MockServer::start().await;
let previous_model = "gpt-5.3-codex";
let previous_model = "gpt-5.4";
let next_model = "gpt-5.2";
let models_mock = mount_models_once(
@@ -2731,7 +2731,7 @@ async fn pre_sampling_compact_skips_when_either_comp_hash_is_missing() {
let server = MockServer::start().await;
let model_without_hash = "gpt-5.4";
let model_with_hash = "gpt-5.3-codex";
let model_with_hash = "gpt-5.5";
let next_model_without_hash = "gpt-5.2";
let models_mock = mount_models_once(
@@ -2840,7 +2840,7 @@ async fn body_after_prefix_model_switch_budget_compacts_with_next_model() {
skip_if_no_network!();
let server = MockServer::start().await;
let previous_model = "gpt-5.3-codex";
let previous_model = "gpt-5.4";
let next_model = "gpt-5.2";
let models_mock = mount_models_once(
@@ -2934,7 +2934,7 @@ async fn pre_sampling_compact_runs_after_resume_and_switch_to_smaller_model() {
skip_if_no_network!();
let server = MockServer::start().await;
let previous_model = "gpt-5.3-codex";
let previous_model = "gpt-5.4";
let next_model = "gpt-5.2";
let models_mock = mount_models_once(
@@ -3055,7 +3055,7 @@ async fn pre_sampling_compact_recovers_comp_hash_after_resume() {
skip_if_no_network!();
let server = MockServer::start().await;
let previous_model = "gpt-5.3-codex";
let previous_model = "gpt-5.4";
let next_model = "gpt-5.2";
let models_mock = mount_models_once(
@@ -3186,7 +3186,7 @@ async fn pre_sampling_compact_skips_missing_comp_hash_after_resume() {
skip_if_no_network!();
let server = MockServer::start().await;
let previous_model = "gpt-5.3-codex";
let previous_model = "gpt-5.4";
let next_model = "gpt-5.2";
let models_mock = mount_models_once(
@@ -4747,7 +4747,7 @@ async fn snapshot_request_shape_pre_turn_compaction_strips_incoming_model_switch
let server = start_mock_server().await;
let previous_model = "gpt-5.4";
let next_model = "gpt-5.3-codex";
let next_model = "gpt-5.2";
let request_log = mount_sse_sequence(
&server,
+1 -1
View File
@@ -3451,7 +3451,7 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_strips_incoming_model
skip_if_no_network!(Ok(()));
let previous_model = "gpt-5.4";
let next_model = "gpt-5.3-codex";
let next_model = "gpt-5.2";
let harness = TestCodexHarness::with_builder(
test_codex()
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
+7 -9
View File
@@ -155,7 +155,7 @@ async fn model_change_appends_model_instructions_developer_message() -> Result<(
)
.await;
let mut builder = test_codex().with_model("gpt-5.3-codex");
let mut builder = test_codex().with_model("gpt-5.2");
let test = builder.build(&server).await?;
let next_model = "gpt-5.4";
@@ -220,14 +220,12 @@ async fn model_and_personality_change_only_appends_model_instructions() -> Resul
)
.await;
let mut builder = test_codex()
.with_model("gpt-5.3-codex")
.with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
});
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
});
let test = builder.build(&server).await?;
let next_model = "exp-codex-personality";
@@ -100,15 +100,13 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> {
)
.await;
let mut builder = test_codex()
.with_model("gpt-5.3-codex")
.with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
config.personality = Some(Personality::Pragmatic);
});
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
config.personality = Some(Personality::Pragmatic);
});
let test = builder.build(&server).await?;
let preturn_context_diff_cwd = test.cwd_path().join(PRETURN_CONTEXT_DIFF_CWD);
fs::create_dir_all(&preturn_context_diff_cwd)?;
@@ -224,7 +222,7 @@ async fn snapshot_model_visible_layout_cwd_change_does_not_refresh_agents() -> R
)
.await;
let mut builder = test_codex().with_model("gpt-5.3-codex");
let mut builder = test_codex().with_model("gpt-5.4");
let test = builder.build(&server).await?;
let cwd_one = test.cwd_path().join("agents_one");
let cwd_two = test.cwd_path().join("agents_two");
@@ -385,7 +383,7 @@ async fn snapshot_model_visible_layout_resume_with_personality_change() -> Resul
.await;
let mut resume_builder = test_codex().with_config(|config| {
config.model = Some("gpt-5.3-codex".to_string());
config.model = Some("gpt-5.4".to_string());
config
.features
.enable(Feature::Personality)
@@ -500,7 +498,7 @@ async fn snapshot_model_visible_layout_resume_override_matches_rollout_model() -
.await;
let mut resume_builder = test_codex().with_config(|config| {
config.model = Some("gpt-5.3-codex".to_string());
config.model = Some("gpt-5.4".to_string());
});
let resumed = resume_builder.resume(&server, home, rollout_path).await?;
let resume_override_cwd = resumed.cwd_path().join(PRETURN_CONTEXT_DIFF_CWD);
+29 -39
View File
@@ -116,8 +116,7 @@ async fn base_instructions_override_disables_personality_template() {
config.personality = Some(Personality::Friendly);
config.base_instructions = Some("override instructions".to_string());
let model_info =
codex_core::test_support::construct_model_info_offline("gpt-5.3-codex", &config);
let model_info = codex_core::test_support::construct_model_info_offline("gpt-5.4", &config);
assert_eq!(model_info.base_instructions, "override instructions");
assert_eq!(
@@ -132,14 +131,12 @@ async fn user_turn_personality_none_does_not_add_update_message() -> anyhow::Res
let server = start_mock_server().await;
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
let mut builder = test_codex()
.with_model("gpt-5.3-codex")
.with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
});
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
});
let test = builder.build(&server).await?;
test.codex
@@ -171,15 +168,13 @@ async fn config_personality_some_sets_instructions_template() -> anyhow::Result<
let server = start_mock_server().await;
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
let mut builder = test_codex()
.with_model("gpt-5.3-codex")
.with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
config.personality = Some(Personality::Friendly);
});
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
config.personality = Some(Personality::Friendly);
});
let test = builder.build(&server).await?;
test.codex
@@ -218,15 +213,13 @@ async fn config_personality_none_sends_no_personality() -> anyhow::Result<()> {
let server = start_mock_server().await;
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
let mut builder = test_codex()
.with_model("gpt-5.3-codex")
.with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
config.personality = Some(Personality::None);
});
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
config.personality = Some(Personality::None);
});
let test = builder.build(&server).await?;
test.codex
@@ -272,14 +265,12 @@ async fn default_personality_is_pragmatic_without_config_toml() -> anyhow::Resul
let server = start_mock_server().await;
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
let mut builder = test_codex()
.with_model("gpt-5.3-codex")
.with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
});
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
config
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
});
let test = builder.build(&server).await?;
test.codex
@@ -458,8 +449,7 @@ async fn instructions_uses_base_if_feature_disabled() -> anyhow::Result<()> {
.expect("test config should allow feature update");
config.personality = Some(Personality::Friendly);
let model_info =
codex_core::test_support::construct_model_info_offline("gpt-5.3-codex", &config);
let model_info = codex_core::test_support::construct_model_info_offline("gpt-5.4", &config);
assert_eq!(
model_info.get_model_instructions(config.personality),
model_info.base_instructions
@@ -739,7 +729,7 @@ async fn user_turn_personality_remote_model_template_includes_update_message() -
.features
.enable(Feature::Personality)
.expect("test config should allow feature update");
config.model = Some("gpt-5.3-codex".to_string());
config.model = Some("gpt-5.4".to_string());
});
let test = builder.build(&server).await?;
+2 -2
View File
@@ -299,7 +299,7 @@ async fn resume_switches_models_preserves_base_instructions() -> Result<()> {
.await;
let mut resume_builder = test_codex().with_config(|config| {
config.model = Some("gpt-5.3-codex".to_string());
config.model = Some("gpt-5.4".to_string());
});
let resumed = resume_builder.resume(&server, home, rollout_path).await?;
resumed
@@ -420,7 +420,7 @@ async fn resume_model_switch_is_not_duplicated_after_pre_turn_override() -> Resu
.await;
let mut resume_builder = test_codex().with_config(|config| {
config.model = Some("gpt-5.3-codex".to_string());
config.model = Some("gpt-5.5".to_string());
});
let resumed = resume_builder.resume(&server, home, rollout_path).await?;
core_test_support::submit_thread_settings(
+1 -1
View File
@@ -1563,7 +1563,7 @@ async fn stdio_image_responses_preserve_original_detail_metadata() -> anyhow::Re
let rmcp_test_server_bin = remote_aware_stdio_server_bin()?;
let fixture = test_codex()
.with_model("gpt-5.3-codex")
.with_model("gpt-5.4")
.with_config(move |config| {
insert_mcp_server(
config,
@@ -54,7 +54,7 @@ fn disabled_text_turn(test: &TestCodex, text: &str) -> Op {
collaboration_mode: Some(codex_protocol::config_types::CollaborationMode {
mode: codex_protocol::config_types::ModeKind::Default,
settings: codex_protocol::config_types::Settings {
model: REQUESTED_MODEL.to_string(),
model: test.session_configured.model.clone(),
reasoning_effort: test.config.model_reasoning_effort.clone(),
developer_instructions: None,
},
@@ -241,7 +241,11 @@ async fn openai_model_header_mismatch_only_emits_one_warning_per_turn() -> Resul
loop {
let event = wait_for_event(&test.codex, |_| true).await;
match event {
EventMsg::Warning(warning) if warning.message.contains(REQUESTED_MODEL) => {
EventMsg::Warning(warning)
if warning
.message
.contains("flagged for potentially high-risk cyber activity") =>
{
warning_count += 1;
}
EventMsg::TurnComplete(_) => break,
@@ -307,7 +311,7 @@ async fn model_verification_emits_structured_event_without_reroute_or_warning()
]));
let _mock = mount_response_once(&server, response).await;
let mut builder = test_codex().with_model(REQUESTED_MODEL);
let mut builder = test_codex().with_model(SERVER_MODEL);
let test = builder.build(&server).await?;
test.codex
@@ -383,7 +387,7 @@ async fn model_verification_only_emits_once_per_turn() -> Result<()> {
]));
let _mock = mount_response_sequence(&server, vec![first_response, second_response]).await;
let mut builder = test_codex().with_model(REQUESTED_MODEL);
let mut builder = test_codex().with_model(SERVER_MODEL);
let test = builder.build(&server).await?;
test.codex
@@ -19,9 +19,8 @@ Scenario: Pre-turn compaction during model switch (without pre-sampling model-sw
## Local Post-Compaction History Layout
00:message/user:BEFORE_SWITCH_USER
01:message/user:<COMPACTION_SUMMARY>\nPRETURN_SWITCH_SUMMARY
02:message/developer[3]:
02:message/developer[2]:
[01] <model_switch>\nThe user was previously using a different model....
[02] <PERMISSIONS_INSTRUCTIONS>
[03] <personality_spec> The user has requested a new communication st...
03:message/user:<ENVIRONMENT_CONTEXT:cwd=<CWD>>
04:message/user:AFTER_SWITCH_USER
@@ -18,9 +18,8 @@ Scenario: Remote pre-turn compaction during model switch currently excludes inco
## Remote Post-Compaction History Layout
00:message/user:BEFORE_SWITCH_USER
01:compaction:encrypted=true
02:message/developer[3]:
02:message/developer[2]:
[01] <model_switch>\nThe user was previously using a different model....
[02] <PERMISSIONS_INSTRUCTIONS>
[03] <personality_spec> The user has requested a new communication st...
03:message/user:<ENVIRONMENT_CONTEXT:cwd=<CWD>>
04:message/user:AFTER_SWITCH_USER
@@ -55,7 +55,7 @@ const TURN_0_FORK_PROMPT: &str = "seed fork context";
const TURN_1_PROMPT: &str = "spawn a child and continue";
const TURN_2_NO_WAIT_PROMPT: &str = "follow up without wait";
const CHILD_PROMPT: &str = "child: do work";
const INHERITED_MODEL: &str = "gpt-5.3-codex";
const INHERITED_MODEL: &str = "gpt-5.2";
const INHERITED_REASONING_EFFORT: ReasoningEffort = ReasoningEffort::XHigh;
const REQUESTED_MODEL: &str = "gpt-5.4";
const REQUESTED_REASONING_EFFORT: ReasoningEffort = ReasoningEffort::Low;
+5 -5
View File
@@ -673,12 +673,12 @@ async fn view_image_routes_to_selected_remote_environment() -> anyhow::Result<()
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn view_image_tool_can_preserve_original_resolution_when_requested_on_gpt5_3_codex()
async fn view_image_tool_can_preserve_original_resolution_when_requested_on_gpt5_4()
-> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex().with_model("gpt-5.3-codex");
let mut builder = test_codex().with_model("gpt-5.4");
let test = builder.build_with_auto_env(&server).await?;
let TestCodex {
codex,
@@ -769,7 +769,7 @@ async fn view_image_tool_errors_clearly_for_unsupported_detail_values() -> anyho
skip_if_no_network!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex().with_model("gpt-5.3-codex");
let mut builder = test_codex().with_model("gpt-5.4");
let test = builder.build_with_auto_env(&server).await?;
let TestCodex {
codex,
@@ -847,7 +847,7 @@ async fn view_image_tool_treats_null_detail_as_omitted() -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex().with_model("gpt-5.3-codex");
let mut builder = test_codex().with_model("gpt-5.4");
let test = builder.build_with_auto_env(&server).await?;
let TestCodex {
codex,
@@ -1031,7 +1031,7 @@ async fn view_image_tool_does_not_force_original_resolution_with_capability_only
skip_if_no_network!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex().with_model("gpt-5.3-codex");
let mut builder = test_codex().with_model("gpt-5.4");
let test = builder.build_with_auto_env(&server).await?;
let TestCodex {
codex,
+2 -2
View File
@@ -241,7 +241,7 @@ location = { country = "US", city = "New York", timezone = "America/New_York" }
)
.expect("write config.toml");
let mut builder = test_codex().with_model("gpt-5.3-codex").with_home(home);
let mut builder = test_codex().with_model("gpt-5.2").with_home(home);
let test = builder
.build(&server)
.await
@@ -290,7 +290,7 @@ async fn indexed_web_search_mode_sets_indexed_access() {
std::fs::write(home.path().join("config.toml"), r#"web_search = "indexed""#)
.expect("write config.toml");
let mut builder = test_codex().with_model("gpt-5.3-codex").with_home(home);
let mut builder = test_codex().with_model("gpt-5.2").with_home(home);
let test = builder
.build(&server)
.await
File diff suppressed because one or more lines are too long
+7 -7
View File
@@ -42,19 +42,19 @@ async fn model_migration_prompt_only_shows_for_deprecated_models() {
let seen = BTreeMap::new();
assert!(should_show_model_migration_prompt(
"gpt-5.2",
"gpt-5.4",
"gpt-5.5",
&seen,
&all_model_presets()
));
assert!(should_show_model_migration_prompt(
"gpt-5.3-codex",
"gpt-5.4",
"gpt-5.5",
&seen,
&all_model_presets()
));
assert!(!should_show_model_migration_prompt(
"gpt-5.3-codex",
"gpt-5.3-codex",
"gpt-5.4",
"gpt-5.4",
&seen,
&all_model_presets()
));
@@ -342,13 +342,13 @@ async fn model_migration_prompt_shows_for_hidden_model() {
let mut available_models = all_model_presets();
let current = available_models
.iter_mut()
.find(|preset| preset.model == "gpt-5.3-codex")
.expect("gpt-5.3-codex preset present");
.find(|preset| preset.model == "gpt-5.2")
.expect("gpt-5.2 preset present");
current.show_in_picker = false;
let current = current.clone();
assert!(
!current.show_in_picker,
"expected gpt-5.3-codex to be hidden from picker for this test"
"expected gpt-5.2 to be hidden from picker for this test"
);
let upgrade = current.upgrade.as_ref().expect("upgrade configured");
@@ -1,12 +1,11 @@
---
source: tui/src/app/tests/model_catalog.rs
assertion_line: 289
expression: model_migration_copy_to_plain_text(&copy)
---
Introducing GPT-5.4
Introducing GPT-5.5
Codex just got an upgrade with GPT-5.4, our most capable model for professional work. It outperforms prior models while being more token efficient, with notable improvements on long-running tasks, tool calling, computer use, and frontend development.
GPT-5.5 is now available in Codex. It's our strongest agentic coding model yet, built to reason through large codebases, check assumptions with tools, and keep going until the work is done.
Learn more: https://openai.com/index/introducing-gpt-5-4
Learn more: https://openai.com/index/introducing-gpt-5-5/
You can always keep using GPT-5.3-Codex if you prefer.
You can always keep using GPT-5.4 if you prefer.
@@ -10,8 +10,7 @@ expression: popup
2. gpt-5.4 Strong model for everyday coding.
3. gpt-5.4-mini Small, fast, and cost-efficient model for simpler
coding tasks.
4. gpt-5.3-codex Coding-optimized model.
› 5. gpt-5.2 (current) Optimized for professional work and long-running
› 4. gpt-5.2 (current) Optimized for professional work and long-running
agents.
Press enter to confirm or esc to go back
@@ -6,4 +6,4 @@ expression: normalized_backend_snapshot(terminal.backend())
" "
"› Ask Codex to do anything "
" "
" gpt-5.3-codex high · Roadmap cleanup "
" gpt-5.2 high · Roadmap cleanup "
@@ -6,4 +6,4 @@ expression: normalized_backend_snapshot(terminal.backend())
" "
"› Ask Codex to do anything "
" "
" gpt-5.3-codex medium Plan mode (shift+tab to cycle) "
" gpt-5.2 medium Plan mode (shift+tab to cycle) "
@@ -42,7 +42,7 @@ fn configured_thread_session(thread_id: ThreadId) -> crate::session_state::Threa
forked_from_id: None,
fork_parent_title: None,
thread_name: None,
model: "gpt-5.3-codex".to_string(),
model: "gpt-5.2".to_string(),
model_provider_id: "openai".to_string(),
service_tier: None,
approval_policy: AskForApproval::Never,
@@ -311,7 +311,7 @@ async fn invalid_url_elicitation_is_declined() {
#[tokio::test]
async fn thread_settings_updated_updates_visible_state_without_transcript() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
set_fast_mode_test_catalog(&mut chat);
let thread_id = ThreadId::new();
chat.handle_thread_session(configured_thread_session(thread_id));
@@ -367,7 +367,7 @@ async fn thread_settings_updated_updates_visible_state_without_transcript() {
#[tokio::test]
async fn thread_settings_updated_preserves_default_settings_for_plan_mode() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
let thread_id = ThreadId::new();
let mut session = configured_thread_session(thread_id);
session.model = "gpt-default".to_string();
+1 -3
View File
@@ -297,9 +297,7 @@ pub(crate) fn set_fast_mode_test_catalog(chat: &mut ChatWidget) {
"gpt-5.4", /*priority*/ 0, /*supports_fast_mode*/ true,
),
test_model_info(
"gpt-5.3-codex",
/*priority*/ 1,
/*supports_fast_mode*/ false,
"gpt-5.2", /*priority*/ 1, /*supports_fast_mode*/ false,
),
],
}
@@ -1354,7 +1354,7 @@ async fn mode_switch_surfaces_model_change_notification_when_effective_model_cha
#[tokio::test]
async fn mode_switch_surfaces_reasoning_change_notification_when_model_stays_same() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true);
chat.set_reasoning_effort(Some(ReasoningEffortConfig::High));
@@ -1368,7 +1368,7 @@ async fn mode_switch_surfaces_reasoning_change_notification_when_model_stays_sam
.collect::<Vec<_>>()
.join("\n");
assert!(
plan_messages.contains("Model changed to gpt-5.3-codex medium for Plan mode."),
plan_messages.contains("Model changed to gpt-5.2 medium for Plan mode."),
"expected reasoning-change notice in Plan mode, got: {plan_messages:?}"
);
}
@@ -1614,10 +1614,10 @@ async fn collab_mode_applies_default_preset() {
#[tokio::test]
async fn user_turn_includes_personality_from_config() {
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await;
chat.set_feature_enabled(Feature::Personality, /*enabled*/ true);
chat.thread_id = Some(ThreadId::new());
chat.set_model("gpt-5.3-codex");
chat.set_model("gpt-5.4");
chat.set_personality(Personality::Friendly);
chat.bottom_pane
@@ -3089,7 +3089,7 @@ async fn model_selection_popup_snapshot() {
#[tokio::test]
async fn personality_selection_popup_snapshot() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await;
chat.thread_id = Some(ThreadId::new());
chat.open_personality_popup();
@@ -3150,8 +3150,8 @@ async fn model_picker_hides_show_in_picker_false_models_from_cache() {
#[tokio::test]
async fn server_overloaded_error_does_not_switch_models() {
let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
chat.set_model("gpt-5.3-codex");
let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
chat.set_model("gpt-5.2");
while rx.try_recv().is_ok() {}
while op_rx.try_recv().is_ok() {}
@@ -3164,7 +3164,7 @@ async fn server_overloaded_error_does_not_switch_models() {
while let Ok(event) = rx.try_recv() {
if let AppEvent::UpdateModel(model) = event {
assert_eq!(
model, "gpt-5.3-codex",
model, "gpt-5.2",
"did not expect model switch on server-overloaded error"
);
}
@@ -399,7 +399,7 @@ async fn queued_slash_menu_cancel_drains_next_input() {
#[tokio::test]
async fn queued_settings_selection_applies_before_next_input() {
let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
chat.thread_id = Some(ThreadId::new());
let mut preset = get_available_model(&chat, "gpt-5.4");
preset.supported_reasoning_efforts.truncate(1);
@@ -1203,7 +1203,7 @@ async fn slash_rename_without_existing_thread_name_starts_empty() {
#[tokio::test]
async fn usage_error_slash_command_is_available_from_local_recall() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
submit_composer_text(&mut chat, "/raw maybe");
@@ -2730,7 +2730,7 @@ async fn user_turn_carries_service_tier_after_fast_toggle() {
#[tokio::test]
async fn model_switch_recomputes_catalog_default_service_tier() {
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
chat.thread_id = Some(ThreadId::new());
set_chatgpt_auth(&mut chat);
set_fast_mode_test_catalog(&mut chat);
@@ -2753,7 +2753,7 @@ async fn model_switch_recomputes_catalog_default_service_tier() {
Some(ServiceTier::Fast.request_value())
);
chat.set_model("gpt-5.3-codex");
chat.set_model("gpt-5.2");
assert_eq!(chat.current_service_tier(), None);
chat.bottom_pane
@@ -1751,13 +1751,13 @@ async fn fast_status_indicator_requires_chatgpt_auth() {
#[tokio::test]
async fn fast_status_indicator_is_hidden_for_models_without_fast_support() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
set_fast_mode_test_catalog(&mut chat);
assert!(!get_available_model(&chat, "gpt-5.3-codex").supports_fast_mode());
assert!(!get_available_model(&chat, "gpt-5.2").supports_fast_mode());
chat.set_service_tier(Some(ServiceTier::Fast.request_value().to_string()));
set_chatgpt_auth(&mut chat);
set_fast_mode_test_catalog(&mut chat);
assert!(!get_available_model(&chat, "gpt-5.3-codex").supports_fast_mode());
assert!(!get_available_model(&chat, "gpt-5.2").supports_fast_mode());
assert!(!chat.should_show_fast_status(chat.current_model(), chat.current_service_tier(),));
}
@@ -2645,14 +2645,12 @@ async fn status_line_model_with_reasoning_includes_fast_for_fast_capable_models(
Some(format!("gpt-5.4 xhigh fast · Context 0% used · {test_cwd}"))
);
chat.set_model("gpt-5.3-codex");
chat.set_model("gpt-5.2");
chat.refresh_status_line();
assert_eq!(
status_line_text(&chat),
Some(format!(
"gpt-5.3-codex xhigh · Context 0% used · {test_cwd}"
))
Some(format!("gpt-5.2 xhigh · Context 0% used · {test_cwd}"))
);
}
@@ -2664,9 +2662,9 @@ async fn terminal_title_model_updates_on_model_change_without_manual_refresh() {
assert_eq!(chat.last_terminal_title, Some("gpt-5.4".to_string()));
chat.set_model("gpt-5.3-codex");
chat.set_model("gpt-5.2");
assert_eq!(chat.last_terminal_title, Some("gpt-5.3-codex".to_string()));
assert_eq!(chat.last_terminal_title, Some("gpt-5.2".to_string()));
}
#[tokio::test]
@@ -2686,7 +2684,7 @@ async fn status_line_and_terminal_title_reasoning_render_only_effort() {
#[tokio::test]
async fn status_line_reasoning_updates_on_mode_switch_without_manual_refresh() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true);
chat.config.tui_status_line = Some(vec!["reasoning".to_string()]);
chat.set_reasoning_effort(Some(ReasoningEffortConfig::High));
@@ -2702,33 +2700,24 @@ async fn status_line_reasoning_updates_on_mode_switch_without_manual_refresh() {
#[tokio::test]
async fn status_line_model_with_reasoning_updates_on_mode_switch_without_manual_refresh() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true);
chat.config.tui_status_line = Some(vec!["model-with-reasoning".to_string()]);
chat.set_reasoning_effort(Some(ReasoningEffortConfig::High));
assert_eq!(
status_line_text(&chat),
Some("gpt-5.3-codex high".to_string())
);
assert_eq!(status_line_text(&chat), Some("gpt-5.2 high".to_string()));
let plan_mask = collaboration_modes::plan_mask(chat.model_catalog.as_ref())
.expect("expected plan collaboration mode");
chat.set_collaboration_mask(plan_mask);
assert_eq!(
status_line_text(&chat),
Some("gpt-5.3-codex medium".to_string())
);
assert_eq!(status_line_text(&chat), Some("gpt-5.2 medium".to_string()));
let default_mask = collaboration_modes::default_mask(chat.model_catalog.as_ref())
.expect("expected default collaboration mode");
chat.set_collaboration_mask(default_mask);
assert_eq!(
status_line_text(&chat),
Some("gpt-5.3-codex high".to_string())
);
assert_eq!(status_line_text(&chat), Some("gpt-5.2 high".to_string()));
}
#[tokio::test]
@@ -2736,7 +2725,7 @@ async fn status_line_model_with_reasoning_plan_mode_footer_snapshot() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
chat.show_welcome_banner = false;
chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true);
chat.config.tui_status_line = Some(vec!["model-with-reasoning".to_string()]);
@@ -2763,7 +2752,7 @@ async fn renamed_thread_footer_title_snapshot() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
chat.show_welcome_banner = false;
chat.config.tui_status_line = Some(vec![
"model-with-reasoning".to_string(),