From 48ba4bada24a7ca82606f9fb8cfef6324c80d60f Mon Sep 17 00:00:00 2001 From: Ibrahim Khan <2005ibrahimkhan@gmail.com> Date: Wed, 15 Jul 2026 09:31:19 -0700 Subject: [PATCH] bedrock: Add GPT-5.6 Sol, Terra, and Luna Mantle models (#61008) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective - Adds the three GPT-5.6 models (Sol, Terra, and Luna) that OpenAI now serves through AWS Bedrock's `bedrock-mantle` endpoint, so they can be selected as built-in models under the Amazon Bedrock provider. - Follows up on the native Bedrock Mantle support added in #60480. - Addresses the feature request in https://github.com/zed-industries/zed/discussions/61003. ## Solution - Adds `Gpt5_6Sol`, `Gpt5_6Terra`, and `Gpt5_6Luna` variants to `MantleModel` in `crates/bedrock/src/models.rs`, with per-model `id`/`request_id`/`display_name` and shared capability arms. - All three are Responses-API, `bedrock-mantle`-only models, so they reuse the existing Mantle request/response plumbing, region gating, bearer-token auth, and model-picker wiring (`MantleModel::iter()`) with no other changes required. - Metadata mirrors the AWS Bedrock model cards ([Sol](https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-openai-gpt-56-sol.html), [Terra](https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-openai-gpt-56-terra.html), [Luna](https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-openai-gpt-56-luna.html)): 272K context window, image input, tool and thinking support, and `openai.gpt-5.6-{sol,terra,luna}` request IDs. - Updates the Amazon Bedrock section of "Use a Gateway" to mention the GPT-5.6 family. ## Testing - `cargo test -p bedrock` — adds `test_gpt_5_6_mantle_model_metadata` and extends `test_builtin_mantle_models_use_responses_protocol`; all pass. - `cargo test -p language_models mantle` — the consumer crate compiles and all Mantle tests pass. - `./script/clippy -p bedrock` passes with no new warnings; docs pass `prettier --check`. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments — N/A, no unsafe code - [x] The content adheres to Zed's UI standards — N/A, no UI change - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Added GPT-5.6 Sol, Terra, and Luna models to the Amazon Bedrock provider via the `bedrock-mantle` endpoint. --------- Co-authored-by: Anant Goel --- crates/bedrock/src/models.rs | 130 +++++++++++++++++- .../language_models/src/provider/bedrock.rs | 15 ++ crates/settings_content/src/language_model.rs | 2 +- docs/src/ai/use-a-gateway.md | 2 +- 4 files changed, 140 insertions(+), 9 deletions(-) diff --git a/crates/bedrock/src/models.rs b/crates/bedrock/src/models.rs index cd035be819..9b8a259640 100644 --- a/crates/bedrock/src/models.rs +++ b/crates/bedrock/src/models.rs @@ -834,6 +834,12 @@ pub enum MantleProtocol { #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, EnumIter)] pub enum MantleModel { + #[serde(rename = "gpt-5.6-sol")] + Gpt5_6Sol, + #[serde(rename = "gpt-5.6-terra")] + Gpt5_6Terra, + #[serde(rename = "gpt-5.6-luna")] + Gpt5_6Luna, #[serde(rename = "gpt-5.5")] Gpt5_5, #[serde(rename = "gpt-5.4")] @@ -857,6 +863,9 @@ impl MantleModel { /// The model id Zed uses internally (also used as the `name` in settings). pub fn id(&self) -> &str { match self { + Self::Gpt5_6Sol => "gpt-5.6-sol", + Self::Gpt5_6Terra => "gpt-5.6-terra", + Self::Gpt5_6Luna => "gpt-5.6-luna", Self::Gpt5_5 => "gpt-5.5", Self::Gpt5_4 => "gpt-5.4", Self::Grok4_3 => "grok-4.3", @@ -867,6 +876,9 @@ impl MantleModel { /// The model id as expected in Bedrock Mantle request bodies, e.g. `openai.gpt-5.5`. pub fn request_id(&self) -> &str { match self { + Self::Gpt5_6Sol => "openai.gpt-5.6-sol", + Self::Gpt5_6Terra => "openai.gpt-5.6-terra", + Self::Gpt5_6Luna => "openai.gpt-5.6-luna", Self::Gpt5_5 => "openai.gpt-5.5", Self::Gpt5_4 => "openai.gpt-5.4", Self::Grok4_3 => "xai.grok-4.3", @@ -876,6 +888,9 @@ impl MantleModel { pub fn display_name(&self) -> &str { match self { + Self::Gpt5_6Sol => "GPT-5.6 Sol", + Self::Gpt5_6Terra => "GPT-5.6 Terra", + Self::Gpt5_6Luna => "GPT-5.6 Luna", Self::Gpt5_5 => "GPT-5.5", Self::Gpt5_4 => "GPT-5.4", Self::Grok4_3 => "Grok 4.3", @@ -888,14 +903,23 @@ impl MantleModel { /// Which OpenAI-compatible API this model must be called through. pub fn protocol(&self) -> MantleProtocol { match self { - Self::Gpt5_5 | Self::Gpt5_4 | Self::Grok4_3 => MantleProtocol::Responses, + Self::Gpt5_6Sol + | Self::Gpt5_6Terra + | Self::Gpt5_6Luna + | Self::Gpt5_5 + | Self::Gpt5_4 + | Self::Grok4_3 => MantleProtocol::Responses, Self::Custom { protocol, .. } => *protocol, } } pub fn max_token_count(&self) -> u64 { match self { - Self::Gpt5_5 | Self::Gpt5_4 => 272_000, + Self::Gpt5_6Sol + | Self::Gpt5_6Terra + | Self::Gpt5_6Luna + | Self::Gpt5_5 + | Self::Gpt5_4 => 272_000, Self::Grok4_3 => 1_000_000, Self::Custom { max_tokens, .. } => *max_tokens, } @@ -903,8 +927,12 @@ impl MantleModel { pub fn max_output_tokens(&self) -> u64 { match self { - // AWS doesn't document a hard cap for GPT-5.5/5.4 on Mantle. - Self::Gpt5_5 | Self::Gpt5_4 => 128_000, + // AWS doesn't document a hard cap for the GPT-5.x models on Mantle. + Self::Gpt5_6Sol + | Self::Gpt5_6Terra + | Self::Gpt5_6Luna + | Self::Gpt5_5 + | Self::Gpt5_4 => 128_000, Self::Grok4_3 => 131_072, Self::Custom { max_output_tokens, .. @@ -914,14 +942,24 @@ impl MantleModel { pub fn supports_tools(&self) -> bool { match self { - Self::Gpt5_5 | Self::Gpt5_4 | Self::Grok4_3 => true, + Self::Gpt5_6Sol + | Self::Gpt5_6Terra + | Self::Gpt5_6Luna + | Self::Gpt5_5 + | Self::Gpt5_4 + | Self::Grok4_3 => true, Self::Custom { supports_tools, .. } => *supports_tools, } } pub fn supports_images(&self) -> bool { match self { - Self::Gpt5_5 | Self::Gpt5_4 | Self::Grok4_3 => true, + Self::Gpt5_6Sol + | Self::Gpt5_6Terra + | Self::Gpt5_6Luna + | Self::Gpt5_5 + | Self::Gpt5_4 + | Self::Grok4_3 => true, Self::Custom { supports_images, .. } => *supports_images, @@ -930,7 +968,12 @@ impl MantleModel { pub fn supports_thinking(&self) -> bool { match self { - Self::Gpt5_5 | Self::Gpt5_4 | Self::Grok4_3 => true, + Self::Gpt5_6Sol + | Self::Gpt5_6Terra + | Self::Gpt5_6Luna + | Self::Gpt5_5 + | Self::Gpt5_4 + | Self::Grok4_3 => true, Self::Custom { supports_thinking, .. } => *supports_thinking, @@ -944,11 +987,84 @@ mod tests { #[test] fn test_builtin_mantle_models_use_responses_protocol() { + assert_eq!(MantleModel::Gpt5_6Sol.protocol(), MantleProtocol::Responses); + assert_eq!( + MantleModel::Gpt5_6Terra.protocol(), + MantleProtocol::Responses + ); + assert_eq!( + MantleModel::Gpt5_6Luna.protocol(), + MantleProtocol::Responses + ); assert_eq!(MantleModel::Gpt5_5.protocol(), MantleProtocol::Responses); assert_eq!(MantleModel::Gpt5_4.protocol(), MantleProtocol::Responses); assert_eq!(MantleModel::Grok4_3.protocol(), MantleProtocol::Responses); } + #[test] + fn test_gpt_5_6_mantle_model_metadata() { + // Values mirror the AWS Bedrock model cards for GPT-5.6 Sol/Terra/Luna, + // which are served only through the `bedrock-mantle` Responses API. + for (model, id, request_id, display_name) in [ + ( + MantleModel::Gpt5_6Sol, + "gpt-5.6-sol", + "openai.gpt-5.6-sol", + "GPT-5.6 Sol", + ), + ( + MantleModel::Gpt5_6Terra, + "gpt-5.6-terra", + "openai.gpt-5.6-terra", + "GPT-5.6 Terra", + ), + ( + MantleModel::Gpt5_6Luna, + "gpt-5.6-luna", + "openai.gpt-5.6-luna", + "GPT-5.6 Luna", + ), + ] { + assert_eq!(model.id(), id); + assert_eq!(model.request_id(), request_id); + assert_eq!(model.display_name(), display_name); + assert_eq!(model.max_token_count(), 272_000); + assert!(model.supports_tools()); + assert!(model.supports_images()); + assert!(model.supports_thinking()); + } + } + + #[test] + fn test_builtin_mantle_models_have_unique_ids_and_sane_token_limits() { + use std::collections::HashSet; + use strum::IntoEnumIterator; + + let mut ids = HashSet::new(); + let mut request_ids = HashSet::new(); + for model in + MantleModel::iter().filter(|model| !matches!(model, MantleModel::Custom { .. })) + { + assert!( + ids.insert(model.id().to_string()), + "duplicate MantleModel id: {}", + model.id() + ); + assert!( + request_ids.insert(model.request_id().to_string()), + "duplicate MantleModel request_id: {}", + model.request_id() + ); + assert!( + model.max_output_tokens() <= model.max_token_count(), + "{} has max_output_tokens ({}) greater than max_token_count ({})", + model.id(), + model.max_output_tokens(), + model.max_token_count() + ); + } + } + #[test] fn test_us_region_inference_ids() -> anyhow::Result<()> { assert_eq!( diff --git a/crates/language_models/src/provider/bedrock.rs b/crates/language_models/src/provider/bedrock.rs index f0902dd9cb..b686a3d11f 100644 --- a/crates/language_models/src/provider/bedrock.rs +++ b/crates/language_models/src/provider/bedrock.rs @@ -2606,9 +2606,24 @@ mod tests { #[test] fn test_builtin_mantle_models_support_thinking() { + assert!(MantleModel::Gpt5_6Sol.supports_thinking()); + assert!(MantleModel::Gpt5_6Terra.supports_thinking()); + assert!(MantleModel::Gpt5_6Luna.supports_thinking()); assert!(MantleModel::Gpt5_5.supports_thinking()); assert!(MantleModel::Gpt5_4.supports_thinking()); assert!(MantleModel::Grok4_3.supports_thinking()); + assert_eq!( + mantle_default_reasoning_effort(&MantleModel::Gpt5_6Sol), + Some(ReasoningEffort::Medium) + ); + assert_eq!( + mantle_default_reasoning_effort(&MantleModel::Gpt5_6Terra), + Some(ReasoningEffort::Medium) + ); + assert_eq!( + mantle_default_reasoning_effort(&MantleModel::Gpt5_6Luna), + Some(ReasoningEffort::Medium) + ); assert_eq!( mantle_default_reasoning_effort(&MantleModel::Gpt5_5), Some(ReasoningEffort::Medium) diff --git a/crates/settings_content/src/language_model.rs b/crates/settings_content/src/language_model.rs index 4203bc232a..735c3d20e1 100644 --- a/crates/settings_content/src/language_model.rs +++ b/crates/settings_content/src/language_model.rs @@ -118,7 +118,7 @@ pub struct AmazonBedrockSettingsContent { pub available_models: Option>, /// Custom models served through the `bedrock-mantle` endpoint's /// OpenAI-compatible APIs, in addition to the built-in Mantle models - /// (GPT-5.5, GPT-5.4, Grok 4.3). + /// (GPT-5.6 Sol, GPT-5.6 Terra, GPT-5.6 Luna, GPT-5.5, GPT-5.4, Grok 4.3). pub mantle_available_models: Option>, pub custom_headers: Option>, pub endpoint_url: Option, diff --git a/docs/src/ai/use-a-gateway.md b/docs/src/ai/use-a-gateway.md index 6cd1a7a614..b1e05dcb8d 100644 --- a/docs/src/ai/use-a-gateway.md +++ b/docs/src/ai/use-a-gateway.md @@ -215,7 +215,7 @@ Some AWS environments require a guardrail on every Bedrock API call. Add `guardr ### Bedrock Mantle Models {#bedrock-mantle-models} -Some models, such as GPT-5.5, GPT-5.4, and Grok 4.3, aren't available through Bedrock's Converse API and are only reachable through `bedrock-mantle`, AWS's OpenAI-compatible inference endpoint. Zed routes these models through `bedrock-mantle` automatically; they appear alongside the rest of the Bedrock models in the model picker once you're authenticated, with no extra configuration required. +Some models, such as the GPT-5.6 family (Sol, Terra, and Luna), GPT-5.5, GPT-5.4, and Grok 4.3, aren't available through Bedrock's Converse API and are only reachable through `bedrock-mantle`, AWS's OpenAI-compatible inference endpoint. Zed routes these models through `bedrock-mantle` automatically; they appear alongside the rest of the Bedrock models in the model picker once you're authenticated, with no extra configuration required. Mantle models require IAM permissions for the `bedrock-mantle` endpoint (for example via the `AmazonBedrockMantleInferenceAccess` managed policy) in addition to whatever permissions your existing Bedrock credentials already have, and `bedrock-mantle` is only available in [some AWS Regions](https://docs.aws.amazon.com/bedrock/latest/userguide/bedrock-mantle.html#regions). Zed surfaces an error naming the current Region and the supported ones if you try to use a Mantle model outside of them.