diff --git a/codex-rs/model-provider-info/src/lib.rs b/codex-rs/model-provider-info/src/lib.rs index 65e2e4cbf7..3fb3e87a2a 100644 --- a/codex-rs/model-provider-info/src/lib.rs +++ b/codex-rs/model-provider-info/src/lib.rs @@ -45,6 +45,7 @@ pub const AMAZON_BEDROCK_RUNTIME_PROVIDER_ID: &str = "amazon-bedrock-runtime"; pub const AMAZON_BEDROCK_GPT_5_5_MODEL_ID: &str = "openai.gpt-5.5"; pub const AMAZON_BEDROCK_GPT_5_4_MODEL_ID: &str = "openai.gpt-5.4"; pub const AMAZON_BEDROCK_GPT_5_6_SOL_MODEL_ID: &str = "openai.gpt-5.6-sol"; +pub const AMAZON_BEDROCK_GPT_6_ASTRA_MODEL_ID: &str = "openai.gpt-6-astra"; pub const AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID: &str = "openai.gpt-5.6-terra"; pub const AMAZON_BEDROCK_GPT_5_6_LUNA_MODEL_ID: &str = "openai.gpt-5.6-luna"; pub const AMAZON_BEDROCK_RUNTIME_GLOBAL_GPT_5_6_TERRA_MODEL_ID: &str = diff --git a/codex-rs/model-provider/src/amazon_bedrock/catalog.rs b/codex-rs/model-provider/src/amazon_bedrock/catalog.rs index 9230f31611..ff2a49307b 100644 --- a/codex-rs/model-provider/src/amazon_bedrock/catalog.rs +++ b/codex-rs/model-provider/src/amazon_bedrock/catalog.rs @@ -3,6 +3,7 @@ use codex_model_provider_info::AMAZON_BEDROCK_GPT_5_5_MODEL_ID; use codex_model_provider_info::AMAZON_BEDROCK_GPT_5_6_LUNA_MODEL_ID; use codex_model_provider_info::AMAZON_BEDROCK_GPT_5_6_SOL_MODEL_ID; use codex_model_provider_info::AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID; +use codex_model_provider_info::AMAZON_BEDROCK_GPT_6_ASTRA_MODEL_ID; use codex_models_manager::bundled_models_response; use codex_protocol::openai_models::ModelInfo; use codex_protocol::openai_models::ModelVisibility; @@ -15,41 +16,48 @@ const GPT_5_BEDROCK_CONTEXT_WINDOW: i64 = 272_000; const GPT_5_6_SOL_OPENAI_MODEL_ID: &str = "gpt-5.6-sol"; const GPT_5_6_TERRA_OPENAI_MODEL_ID: &str = "gpt-5.6-terra"; const GPT_5_6_LUNA_OPENAI_MODEL_ID: &str = "gpt-5.6-luna"; +const GPT_6_ASTRA_OPENAI_MODEL_ID: &str = "gpt-6-astra"; const GPT_5_5_OPENAI_MODEL_ID: &str = "gpt-5.5"; const GPT_5_4_OPENAI_MODEL_ID: &str = "gpt-5.4"; pub(crate) fn static_model_catalog() -> ModelsResponse { normalize_bedrock_catalog(ModelsResponse { models: vec![ - gpt_5_6_bedrock_model( - GPT_5_6_SOL_OPENAI_MODEL_ID, + bedrock_model( + bundled_openai_model(GPT_5_6_SOL_OPENAI_MODEL_ID), AMAZON_BEDROCK_GPT_5_6_SOL_MODEL_ID, "GPT-5.6 Sol", /*priority*/ 0, ), - gpt_5_6_bedrock_model( - GPT_5_6_TERRA_OPENAI_MODEL_ID, - AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID, - "GPT-5.6 Terra", + bedrock_model( + bundled_openai_model(GPT_6_ASTRA_OPENAI_MODEL_ID), + AMAZON_BEDROCK_GPT_6_ASTRA_MODEL_ID, + "GPT-6-Astra", /*priority*/ 1, ), - gpt_5_6_bedrock_model( - GPT_5_6_LUNA_OPENAI_MODEL_ID, + bedrock_model( + bundled_openai_model(GPT_5_6_TERRA_OPENAI_MODEL_ID), + AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID, + "GPT-5.6 Terra", + /*priority*/ 2, + ), + bedrock_model( + bundled_openai_model(GPT_5_6_LUNA_OPENAI_MODEL_ID), AMAZON_BEDROCK_GPT_5_6_LUNA_MODEL_ID, "GPT-5.6 Luna", - /*priority*/ 2, + /*priority*/ 3, ), gpt_5_bedrock_model( GPT_5_5_OPENAI_MODEL_ID, AMAZON_BEDROCK_GPT_5_5_MODEL_ID, "GPT-5.5", - /*priority*/ 3, + /*priority*/ 4, ), gpt_5_bedrock_model( GPT_5_4_OPENAI_MODEL_ID, AMAZON_BEDROCK_GPT_5_4_MODEL_ID, "GPT-5.4", - /*priority*/ 4, + /*priority*/ 5, ), ], }) @@ -87,13 +95,12 @@ fn gpt_5_bedrock_model( model } -fn gpt_5_6_bedrock_model( - openai_slug: &str, +fn bedrock_model( + mut model: ModelInfo, bedrock_slug: &str, display_name: &str, priority: i32, ) -> ModelInfo { - let mut model = bundled_openai_model(openai_slug); model.slug = bedrock_slug.to_string(); model.display_name = display_name.to_string(); model.priority = priority; @@ -136,6 +143,7 @@ mod tests { .collect::>(), vec![ AMAZON_BEDROCK_GPT_5_6_SOL_MODEL_ID, + AMAZON_BEDROCK_GPT_6_ASTRA_MODEL_ID, AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID, AMAZON_BEDROCK_GPT_5_6_LUNA_MODEL_ID, AMAZON_BEDROCK_GPT_5_5_MODEL_ID, @@ -166,6 +174,12 @@ mod tests { Some(872_000), WebSearchToolType::Text, ), + ( + AMAZON_BEDROCK_GPT_6_ASTRA_MODEL_ID, + Some(GPT_5_BEDROCK_CONTEXT_WINDOW), + Some(872_000), + WebSearchToolType::Text, + ), ( AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID, Some(GPT_5_BEDROCK_CONTEXT_WINDOW), @@ -233,30 +247,35 @@ mod tests { } #[test] - fn gpt_5_6_bedrock_models_use_bundled_metadata_with_bedrock_overrides() { + fn bedrock_models_preserve_source_metadata_with_supported_capabilities() { let catalog = static_model_catalog(); - for (openai_slug, slug, display_name, priority) in [ + for (mut expected, slug, display_name, priority) in [ ( - GPT_5_6_SOL_OPENAI_MODEL_ID, + bundled_openai_model(GPT_5_6_SOL_OPENAI_MODEL_ID), AMAZON_BEDROCK_GPT_5_6_SOL_MODEL_ID, "GPT-5.6 Sol", 0, ), ( - GPT_5_6_TERRA_OPENAI_MODEL_ID, + bundled_openai_model(GPT_5_6_TERRA_OPENAI_MODEL_ID), AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID, "GPT-5.6 Terra", - 1, - ), - ( - GPT_5_6_LUNA_OPENAI_MODEL_ID, - AMAZON_BEDROCK_GPT_5_6_LUNA_MODEL_ID, - "GPT-5.6 Luna", 2, ), + ( + bundled_openai_model(GPT_5_6_LUNA_OPENAI_MODEL_ID), + AMAZON_BEDROCK_GPT_5_6_LUNA_MODEL_ID, + "GPT-5.6 Luna", + 3, + ), + ( + bundled_openai_model(GPT_6_ASTRA_OPENAI_MODEL_ID), + AMAZON_BEDROCK_GPT_6_ASTRA_MODEL_ID, + "GPT-6-Astra", + 1, + ), ] { - let mut expected = bundled_openai_model(openai_slug); expected.slug = slug.to_string(); expected.display_name = display_name.to_string(); expected.priority = priority; diff --git a/codex-rs/model-provider/src/amazon_bedrock/runtime_catalog.rs b/codex-rs/model-provider/src/amazon_bedrock/runtime_catalog.rs index 3d01b2c671..b442f7b19a 100644 --- a/codex-rs/model-provider/src/amazon_bedrock/runtime_catalog.rs +++ b/codex-rs/model-provider/src/amazon_bedrock/runtime_catalog.rs @@ -1,6 +1,7 @@ use codex_model_provider_info::AMAZON_BEDROCK_GPT_5_6_LUNA_MODEL_ID; use codex_model_provider_info::AMAZON_BEDROCK_GPT_5_6_SOL_MODEL_ID; use codex_model_provider_info::AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID; +use codex_model_provider_info::AMAZON_BEDROCK_GPT_6_ASTRA_MODEL_ID; use codex_protocol::openai_models::ModelsResponse; use super::catalog::static_model_catalog; @@ -18,6 +19,7 @@ pub(super) fn static_runtime_model_catalog() -> ModelsResponse { AMAZON_BEDROCK_GPT_5_6_SOL_MODEL_ID | AMAZON_BEDROCK_GPT_5_6_TERRA_MODEL_ID | AMAZON_BEDROCK_GPT_5_6_LUNA_MODEL_ID + | AMAZON_BEDROCK_GPT_6_ASTRA_MODEL_ID ) }) .collect::>(); diff --git a/codex-rs/model-provider/src/amazon_bedrock/runtime_catalog_tests.rs b/codex-rs/model-provider/src/amazon_bedrock/runtime_catalog_tests.rs index 81c3989904..80d55f7d8e 100644 --- a/codex-rs/model-provider/src/amazon_bedrock/runtime_catalog_tests.rs +++ b/codex-rs/model-provider/src/amazon_bedrock/runtime_catalog_tests.rs @@ -19,18 +19,20 @@ fn runtime_catalog_includes_supported_cross_region_models_in_priority_order() { .collect::>(), vec![ ("global.openai.gpt-5.6-sol", "GPT-5.6 Sol (Global)", 0), - ("global.openai.gpt-5.6-terra", "GPT-5.6 Terra (Global)", 1), - ("global.openai.gpt-5.6-luna", "GPT-5.6 Luna (Global)", 2), - ("us.openai.gpt-5.6-sol", "GPT-5.6 Sol (US cross-region)", 3), + ("global.openai.gpt-6-astra", "GPT-6-Astra (Global)", 1), + ("global.openai.gpt-5.6-terra", "GPT-5.6 Terra (Global)", 2), + ("global.openai.gpt-5.6-luna", "GPT-5.6 Luna (Global)", 3), + ("us.openai.gpt-5.6-sol", "GPT-5.6 Sol (US cross-region)", 4), + ("us.openai.gpt-6-astra", "GPT-6-Astra (US cross-region)", 5), ( "us.openai.gpt-5.6-terra", "GPT-5.6 Terra (US cross-region)", - 4, + 6, ), ( "us.openai.gpt-5.6-luna", "GPT-5.6 Luna (US cross-region)", - 5 + 7 ), ] ); @@ -58,6 +60,12 @@ fn runtime_catalog_disables_web_search_without_overriding_review_models() { false, Some(MultiAgentVersion::V1), ), + ( + "global.openai.gpt-6-astra", + None, + false, + Some(MultiAgentVersion::V1), + ), ( "global.openai.gpt-5.6-terra", None, @@ -76,6 +84,12 @@ fn runtime_catalog_disables_web_search_without_overriding_review_models() { false, Some(MultiAgentVersion::V1), ), + ( + "us.openai.gpt-6-astra", + None, + false, + Some(MultiAgentVersion::V1), + ), ( "us.openai.gpt-5.6-terra", None, diff --git a/codex-rs/model-provider/src/provider.rs b/codex-rs/model-provider/src/provider.rs index 198cd63731..027850b788 100644 --- a/codex-rs/model-provider/src/provider.rs +++ b/codex-rs/model-provider/src/provider.rs @@ -1063,20 +1063,22 @@ mod tests { ) .await; assert_eq!(uncached_catalog, catalog); - let model_info = manager - .get_model_info( - "openai.gpt-5.6-sol", - &ModelsManagerConfig { - model_context_window: Some(1_000_000), - ..Default::default() - }, - ) - .await; - let mut expected_model_info = manager - .get_model_info("openai.gpt-5.6-sol", &ModelsManagerConfig::default()) - .await; - expected_model_info.context_window = Some(872_000); - assert_eq!(model_info, expected_model_info); + for slug in ["openai.gpt-5.6-sol", "openai.gpt-6-astra"] { + let model_info = manager + .get_model_info( + slug, + &ModelsManagerConfig { + model_context_window: Some(1_000_000), + ..Default::default() + }, + ) + .await; + let mut expected_model_info = manager + .get_model_info(slug, &ModelsManagerConfig::default()) + .await; + expected_model_info.context_window = Some(872_000); + assert_eq!(model_info, expected_model_info); + } let models = catalog .models @@ -1088,6 +1090,7 @@ mod tests { models, vec![ ("openai.gpt-5.6-sol", "GPT-5.6 Sol"), + ("openai.gpt-6-astra", "GPT-6-Astra"), ("openai.gpt-5.6-terra", "GPT-5.6 Terra"), ("openai.gpt-5.6-luna", "GPT-5.6 Luna"), ("openai.gpt-5.5", "GPT-5.5"), @@ -1108,6 +1111,7 @@ mod tests { .collect::>(), vec![ "openai.gpt-5.6-sol", + "openai.gpt-6-astra", "openai.gpt-5.6-terra", "openai.gpt-5.6-luna", "openai.gpt-5.5", diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_mantle_astra_reasoning.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_mantle_astra_reasoning.snap new file mode 100644 index 0000000000..ea473fbada --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_mantle_astra_reasoning.snap @@ -0,0 +1,13 @@ +--- +source: tui/src/chatwidget/tests/bedrock_catalog_tests.rs +expression: "render_bottom_popup(&chat, 100)" +--- + Select Reasoning Level for openai.gpt-6-astra + +› 1. Low (default) Fast responses with lighter reasoning + 2. Medium Balances speed and reasoning depth for everyday tasks + 3. High Greater reasoning depth for complex problems + 4. Extra high Extra high reasoning depth for complex problems + 5. More reasoning… Max consumes usage limits faster + + Press enter to confirm or esc to go back diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_mantle_models.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_mantle_models.snap new file mode 100644 index 0000000000..d39fedf0f4 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_mantle_models.snap @@ -0,0 +1,16 @@ +--- +source: tui/src/chatwidget/tests/bedrock_catalog_tests.rs +expression: "render_bottom_popup(&chat, 100)" +--- + Select Model and Effort + Access legacy models by running codex -m or in your config.toml + +› 1. openai.gpt-5.6-sol (current) Latest frontier agentic coding model. + 2. openai.gpt-6-astra Our most capable model for complex, demanding work. + 3. openai.gpt-5.6-terra Balanced agentic coding model for everyday work. + 4. openai.gpt-5.6-luna Fast and affordable agentic coding model. + 5. openai.gpt-5.5 Frontier model for complex coding, research, and real-world + work. + 6. openai.gpt-5.4 Strong model for everyday coding. + + Press enter to confirm or esc to go back diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_runtime_astra_reasoning.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_runtime_astra_reasoning.snap new file mode 100644 index 0000000000..d25285d3e1 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_runtime_astra_reasoning.snap @@ -0,0 +1,13 @@ +--- +source: tui/src/chatwidget/tests/bedrock_catalog_tests.rs +expression: "render_bottom_popup(&chat, 100)" +--- + Select Reasoning Level for global.openai.gpt-6-astra + +› 1. Low (default) Fast responses with lighter reasoning + 2. Medium Balances speed and reasoning depth for everyday tasks + 3. High Greater reasoning depth for complex problems + 4. Extra high Extra high reasoning depth for complex problems + 5. More reasoning… Max consumes usage limits faster + + Press enter to confirm or esc to go back diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_runtime_models.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_runtime_models.snap new file mode 100644 index 0000000000..d0d082629a --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__bedrock_runtime_models.snap @@ -0,0 +1,17 @@ +--- +source: tui/src/chatwidget/tests/bedrock_catalog_tests.rs +expression: "render_bottom_popup(&chat, 100)" +--- + Select Model and Effort + Access legacy models by running codex -m or in your config.toml + +› 1. global.openai.gpt-5.6-sol (current) Latest frontier agentic coding model. + 2. global.openai.gpt-6-astra Our most capable model for complex, demanding work. + 3. global.openai.gpt-5.6-terra Balanced agentic coding model for everyday work. + 4. global.openai.gpt-5.6-luna Fast and affordable agentic coding model. + 5. us.openai.gpt-5.6-sol Latest frontier agentic coding model. + 6. us.openai.gpt-6-astra Our most capable model for complex, demanding work. + 7. us.openai.gpt-5.6-terra Balanced agentic coding model for everyday work. + 8. us.openai.gpt-5.6-luna Fast and affordable agentic coding model. + + Press enter to confirm or esc to go back diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index dfc3f3c8c1..37827ac07c 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -234,6 +234,8 @@ mod app_server; mod approval_requests; #[path = "tests/backend_banners_tests.rs"] mod backend_banners_tests; +#[path = "tests/bedrock_catalog_tests.rs"] +mod bedrock_catalog_tests; #[path = "tests/collaboration_catalog_tests.rs"] mod collaboration_catalog_tests; #[path = "tests/compaction_tests.rs"] diff --git a/codex-rs/tui/src/chatwidget/tests/bedrock_catalog_tests.rs b/codex-rs/tui/src/chatwidget/tests/bedrock_catalog_tests.rs new file mode 100644 index 0000000000..698f42e891 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/tests/bedrock_catalog_tests.rs @@ -0,0 +1,53 @@ +//! Renders the provider catalog and Astra reasoning choices without changing the default model. + +use super::*; +use codex_http_client::HttpClientFactory; +use codex_http_client::OutboundProxyPolicy; +use codex_model_provider::create_model_provider; +use codex_model_provider_info::ModelProviderInfo; +use codex_models_manager::manager::RefreshStrategy; + +#[tokio::test] +async fn bedrock_astra_model_and_reasoning_pickers() { + for (name, provider_info, default_model, astra_model) in [ + ( + "mantle", + ModelProviderInfo::create_amazon_bedrock_provider(/*aws*/ None), + "openai.gpt-5.6-sol", + "openai.gpt-6-astra", + ), + ( + "runtime", + ModelProviderInfo::create_amazon_bedrock_runtime_provider(/*aws*/ None), + "global.openai.gpt-5.6-sol", + "global.openai.gpt-6-astra", + ), + ] { + let presets = create_model_provider(provider_info, /*auth_manager*/ None) + .models_manager_without_cache(/*config_model_catalog*/ None) + .list_models( + RefreshStrategy::Offline, + HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault), + ) + .await; + let astra = presets + .iter() + .find(|model| model.model == astra_model) + .expect("Astra preset") + .clone(); + let (mut chat, _events, _ops) = make_chatwidget_manual(Some(default_model)).await; + chat.thread_id = Some(ThreadId::new()); + chat.model_catalog = Arc::new(ModelCatalog::new(presets)); + chat.open_model_popup(); + assert_chatwidget_snapshot!( + format!("bedrock_{name}_models"), + render_bottom_popup(&chat, /*width*/ 100) + ); + chat.handle_key_event(KeyEvent::from(KeyCode::Esc)); + chat.open_reasoning_popup(astra); + assert_chatwidget_snapshot!( + format!("bedrock_{name}_astra_reasoning"), + render_bottom_popup(&chat, /*width*/ 100) + ); + } +}