Add Claude Opus 4.8 support (#57984)

<img width="627" height="752" alt="Screenshot 2026-05-28 at 1 20 22 PM"
src="https://github.com/user-attachments/assets/0a7825f0-73c5-49e9-b59a-83924a45de98"
/>

Adds Claude Opus 4.8 for BYOK providers, including Anthropic fast-mode
handling and Bedrock/OpenCode model definitions.

Closes AI-336

Release Notes:

- Added Claude Opus 4.8 BYOK support
This commit is contained in:
Richard Feldman 2026-05-28 13:45:54 -04:00 committed by GitHub
parent 3bb2f2a61d
commit a6b0ee9f36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 136 additions and 13 deletions

View file

@ -122,9 +122,6 @@ impl Model {
let mut supported_effort_levels = Vec::new();
if let Some(effort) = entry.capabilities.as_ref().and_then(|e| e.effort.as_ref()) {
// The `xhigh` effort level reported by the API has no
// corresponding `Effort` variant in the request enum, so it is
// intentionally dropped here.
for (level, supported) in [
(Effort::Low, effort.low.as_ref()),
(Effort::Medium, effort.medium.as_ref()),
@ -148,7 +145,10 @@ impl Model {
AnthropicModelMode::Default
};
let supports_speed = matches!(entry.id.as_str(), "claude-opus-4-6" | "claude-opus-4-7");
let supports_speed = matches!(
entry.id.as_str(),
"claude-opus-4-6" | "claude-opus-4-7" | "claude-opus-4-8"
);
let mut extra_beta_headers = Vec::new();
if supports_speed {
@ -1056,6 +1056,17 @@ mod tests {
assert_eq!(model.mode, AnthropicModelMode::Default);
}
#[test]
fn from_listed_enables_fast_mode_for_opus_4_8() {
let model = Model::from_listed(listed_entry(
"claude-opus-4-8",
ModelCapabilities::default(),
));
assert!(model.supports_speed);
assert_eq!(model.beta_headers().as_deref(), Some(FAST_MODE_BETA_HEADER));
}
#[test]
fn from_listed_collects_supported_effort_levels() {
let entry = listed_entry(

View file

@ -300,6 +300,7 @@ pub fn into_anthropic(
"low" => Some(crate::Effort::Low),
"medium" => Some(crate::Effort::Medium),
"high" => Some(crate::Effort::High),
"xhigh" => Some(crate::Effort::XHigh),
"max" => Some(crate::Effort::Max),
_ => None,
};
@ -705,6 +706,44 @@ mod tests {
));
}
#[test]
fn test_xhigh_effort_is_serialized_for_adaptive_thinking() {
let request = LanguageModelRequest {
messages: vec![LanguageModelRequestMessage {
role: Role::User,
content: vec![MessageContent::Text("Hi".to_string())],
cache: false,
reasoning_details: None,
}],
thread_id: None,
prompt_id: None,
intent: None,
stop: vec![],
temperature: None,
tools: vec![],
tool_choice: None,
thinking_allowed: true,
thinking_effort: Some("xhigh".into()),
speed: None,
};
let anthropic_request = into_anthropic(
request,
"claude-opus-4-8".to_string(),
1.0,
128_000,
AnthropicModelMode::AdaptiveThinking,
AnthropicPromptCacheMode::Automatic,
);
assert_eq!(
anthropic_request
.output_config
.and_then(|config| config.effort),
Some(crate::Effort::XHigh)
);
}
#[test]
fn test_no_cache_control_when_caching_disabled() {
let request = LanguageModelRequest {

View file

@ -8,6 +8,7 @@ pub enum BedrockAdaptiveThinkingEffort {
Medium,
#[default]
High,
XHigh,
Max,
}
@ -17,6 +18,7 @@ impl BedrockAdaptiveThinkingEffort {
Self::Low => "low",
Self::Medium => "medium",
Self::High => "high",
Self::XHigh => "xhigh",
Self::Max => "max",
}
}
@ -91,6 +93,13 @@ pub enum Model {
alias = "claude-opus-4-7-thinking-latest"
)]
ClaudeOpus4_7,
#[serde(
rename = "claude-opus-4-8",
alias = "claude-opus-4-8-latest",
alias = "claude-opus-4-8-thinking",
alias = "claude-opus-4-8-thinking-latest"
)]
ClaudeOpus4_8,
#[serde(
rename = "claude-sonnet-4-6",
alias = "claude-sonnet-4-6-latest",
@ -210,7 +219,9 @@ impl Model {
}
pub fn from_id(id: &str) -> anyhow::Result<Self> {
if id.starts_with("claude-opus-4-7") {
if id.starts_with("claude-opus-4-8") {
Ok(Self::ClaudeOpus4_8)
} else if id.starts_with("claude-opus-4-7") {
Ok(Self::ClaudeOpus4_7)
} else if id.starts_with("claude-opus-4-6") {
Ok(Self::ClaudeOpus4_6)
@ -240,6 +251,7 @@ impl Model {
Self::ClaudeOpus4_5 => "claude-opus-4-5",
Self::ClaudeOpus4_6 => "claude-opus-4-6",
Self::ClaudeOpus4_7 => "claude-opus-4-7",
Self::ClaudeOpus4_8 => "claude-opus-4-8",
Self::ClaudeSonnet4_6 => "claude-sonnet-4-6",
Self::Llama4Scout17B => "llama-4-scout-17b",
Self::Llama4Maverick17B => "llama-4-maverick-17b",
@ -290,6 +302,7 @@ impl Model {
Self::ClaudeOpus4_5 => "anthropic.claude-opus-4-5-20251101-v1:0",
Self::ClaudeOpus4_6 => "anthropic.claude-opus-4-6-v1",
Self::ClaudeOpus4_7 => "anthropic.claude-opus-4-7",
Self::ClaudeOpus4_8 => "anthropic.claude-opus-4-8",
Self::ClaudeSonnet4_6 => "anthropic.claude-sonnet-4-6",
Self::Llama4Scout17B => "meta.llama4-scout-17b-instruct-v1:0",
Self::Llama4Maverick17B => "meta.llama4-maverick-17b-instruct-v1:0",
@ -340,6 +353,7 @@ impl Model {
Self::ClaudeOpus4_5 => "Claude Opus 4.5",
Self::ClaudeOpus4_6 => "Claude Opus 4.6",
Self::ClaudeOpus4_7 => "Claude Opus 4.7",
Self::ClaudeOpus4_8 => "Claude Opus 4.8",
Self::ClaudeSonnet4_6 => "Claude Sonnet 4.6",
Self::Llama4Scout17B => "Llama 4 Scout 17B",
Self::Llama4Maverick17B => "Llama 4 Maverick 17B",
@ -391,6 +405,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6 => 1_000_000,
Self::ClaudeOpus4_1 => 200_000,
Self::Llama4Scout17B | Self::Llama4Maverick17B => 128_000,
@ -425,7 +440,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeSonnet4_6 => 64_000,
Self::ClaudeOpus4_1 => 32_000,
Self::ClaudeOpus4_6 | Self::ClaudeOpus4_7 => 128_000,
Self::ClaudeOpus4_6 | Self::ClaudeOpus4_7 | Self::ClaudeOpus4_8 => 128_000,
Self::Llama4Scout17B
| Self::Llama4Maverick17B
| Self::Gemma3_4B
@ -464,6 +479,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6 => 1.0,
Self::Custom {
default_temperature,
@ -482,6 +498,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6 => true,
Self::NovaLite | Self::NovaPro | Self::NovaPremier | Self::Nova2Lite => true,
Self::MistralLarge3 | Self::PixtralLarge | Self::MagistralSmall => true,
@ -513,6 +530,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6 => true,
Self::NovaLite | Self::NovaPro => true,
Self::PixtralLarge => true,
@ -531,6 +549,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6 => true,
Self::Custom {
cache_configuration,
@ -550,6 +569,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6
)
}
@ -557,10 +577,14 @@ impl Model {
pub fn supports_adaptive_thinking(&self) -> bool {
matches!(
self,
Self::ClaudeOpus4_6 | Self::ClaudeOpus4_7 | Self::ClaudeSonnet4_6
Self::ClaudeOpus4_6 | Self::ClaudeOpus4_7 | Self::ClaudeOpus4_8 | Self::ClaudeSonnet4_6
)
}
pub fn supports_xhigh_adaptive_thinking(&self) -> bool {
matches!(self, Self::ClaudeOpus4_8)
}
pub fn thinking_mode(&self) -> BedrockModelMode {
if self.supports_adaptive_thinking() {
BedrockModelMode::AdaptiveThinking {
@ -590,6 +614,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6
| Self::Nova2Lite
);
@ -650,6 +675,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6
| Self::Nova2Lite,
"global",
@ -667,6 +693,7 @@ impl Model {
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6
| Self::Llama4Scout17B
| Self::Llama4Maverick17B
@ -689,6 +716,7 @@ impl Model {
| Self::ClaudeSonnet4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6
| Self::NovaLite
| Self::NovaPro
@ -702,6 +730,7 @@ impl Model {
| Self::ClaudeSonnet4_5
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_8
| Self::ClaudeSonnet4_6,
"au",
) => Ok(format!("{}.{}", region_group, model_id)),
@ -779,6 +808,10 @@ mod tests {
Model::ClaudeOpus4_7.cross_region_inference_id("eu-west-1", false)?,
"eu.anthropic.claude-opus-4-7"
);
assert_eq!(
Model::ClaudeOpus4_8.cross_region_inference_id("eu-west-1", false)?,
"eu.anthropic.claude-opus-4-8"
);
Ok(())
}
@ -813,6 +846,10 @@ mod tests {
Model::ClaudeOpus4_7.cross_region_inference_id("ap-southeast-2", false)?,
"au.anthropic.claude-opus-4-7"
);
assert_eq!(
Model::ClaudeOpus4_8.cross_region_inference_id("ap-southeast-2", false)?,
"au.anthropic.claude-opus-4-8"
);
Ok(())
}
@ -877,6 +914,10 @@ mod tests {
Model::ClaudeOpus4_7.cross_region_inference_id("us-east-1", true)?,
"global.anthropic.claude-opus-4-7"
);
assert_eq!(
Model::ClaudeOpus4_8.cross_region_inference_id("us-east-1", true)?,
"global.anthropic.claude-opus-4-8"
);
assert_eq!(
Model::Nova2Lite.cross_region_inference_id("us-east-1", true)?,
"global.amazon.nova-2-lite-v1:0"
@ -978,6 +1019,9 @@ mod tests {
assert!(!Model::ClaudeSonnet4.supports_adaptive_thinking());
assert!(Model::ClaudeOpus4_6.supports_adaptive_thinking());
assert!(Model::ClaudeSonnet4_6.supports_adaptive_thinking());
assert!(!Model::ClaudeOpus4_7.supports_xhigh_adaptive_thinking());
assert!(Model::ClaudeOpus4_8.supports_xhigh_adaptive_thinking());
assert_eq!(BedrockAdaptiveThinkingEffort::XHigh.as_str(), "xhigh");
assert_eq!(
Model::ClaudeSonnet4.thinking_mode(),

View file

@ -670,12 +670,22 @@ impl LanguageModel for BedrockModel {
value: "high".into(),
is_default: true,
},
language_model::LanguageModelEffortLevel {
name: "XHigh".into(),
value: "xhigh".into(),
is_default: false,
},
language_model::LanguageModelEffortLevel {
name: "Max".into(),
value: "max".into(),
is_default: false,
},
]
.into_iter()
.filter(|effort_level| {
effort_level.value != "xhigh" || self.model.supports_xhigh_adaptive_thinking()
})
.collect()
} else {
Vec::new()
}
@ -1128,6 +1138,7 @@ pub fn into_bedrock(
"low" => Some(bedrock::BedrockAdaptiveThinkingEffort::Low),
"medium" => Some(bedrock::BedrockAdaptiveThinkingEffort::Medium),
"high" => Some(bedrock::BedrockAdaptiveThinkingEffort::High),
"xhigh" => Some(bedrock::BedrockAdaptiveThinkingEffort::XHigh),
"max" => Some(bedrock::BedrockAdaptiveThinkingEffort::Max),
_ => None,
})

View file

@ -49,7 +49,7 @@ fn reasoning_effort_display(effort: ReasoningEffort) -> (&'static str, &'static
ReasoningEffort::Low => ("Low", "low"),
ReasoningEffort::Medium => ("Medium", "medium"),
ReasoningEffort::High => ("High", "high"),
ReasoningEffort::XHigh => ("Max", "max"),
ReasoningEffort::XHigh => ("XHigh", "xhigh"),
}
}

View file

@ -56,6 +56,8 @@ impl OpenCodeSubscription {
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, EnumIter)]
pub enum Model {
// -- Anthropic protocol models --
#[serde(rename = "claude-opus-4-8")]
ClaudeOpus4_8,
#[serde(rename = "claude-opus-4-7")]
ClaudeOpus4_7,
#[serde(rename = "claude-opus-4-6")]
@ -219,6 +221,7 @@ impl Model {
pub fn id(&self) -> &str {
match self {
Self::ClaudeOpus4_8 => "claude-opus-4-8",
Self::ClaudeOpus4_7 => "claude-opus-4-7",
Self::ClaudeOpus4_6 => "claude-opus-4-6",
Self::ClaudeOpus4_5 => "claude-opus-4-5",
@ -273,6 +276,7 @@ impl Model {
pub fn display_name(&self) -> &str {
match self {
Self::ClaudeOpus4_8 => "Claude Opus 4.8",
Self::ClaudeOpus4_7 => "Claude Opus 4.7",
Self::ClaudeOpus4_6 => "Claude Opus 4.6",
Self::ClaudeOpus4_5 => "Claude Opus 4.5",
@ -339,7 +343,8 @@ impl Model {
}
}
Self::ClaudeOpus4_7
Self::ClaudeOpus4_8
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_1
@ -413,7 +418,7 @@ impl Model {
pub fn max_token_count(&self, subscription: OpenCodeSubscription) -> u64 {
match self {
// Anthropic models
Self::ClaudeOpus4_7 => 1_000_000,
Self::ClaudeOpus4_8 | Self::ClaudeOpus4_7 => 1_000_000,
Self::ClaudeOpus4_6 | Self::ClaudeSonnet4_6 => 1_000_000,
Self::ClaudeSonnet4_5 => 1_000_000,
Self::ClaudeOpus4_5 | Self::ClaudeHaiku4_5 => 200_000,
@ -464,7 +469,7 @@ impl Model {
pub fn max_output_tokens(&self, subscription: OpenCodeSubscription) -> Option<u64> {
match self {
// Anthropic models
Self::ClaudeOpus4_7 | Self::ClaudeOpus4_6 => Some(128_000),
Self::ClaudeOpus4_8 | Self::ClaudeOpus4_7 | Self::ClaudeOpus4_6 => Some(128_000),
Self::ClaudeOpus4_5
| Self::ClaudeSonnet4_6
| Self::ClaudeSonnet4_5
@ -531,7 +536,8 @@ impl Model {
pub fn supports_images(&self) -> bool {
match self {
// Anthropic models support images
Self::ClaudeOpus4_7
Self::ClaudeOpus4_8
| Self::ClaudeOpus4_7
| Self::ClaudeOpus4_6
| Self::ClaudeOpus4_5
| Self::ClaudeOpus4_1
@ -596,6 +602,13 @@ impl Model {
pub fn supported_reasoning_effort_levels(&self) -> Option<Vec<ReasoningEffort>> {
match self {
Self::ClaudeOpus4_8 => Some(vec![
ReasoningEffort::Low,
ReasoningEffort::Medium,
ReasoningEffort::High,
ReasoningEffort::XHigh,
]),
Self::MimoV2_5Pro | Self::MimoV2_5 => Some(vec![
ReasoningEffort::Low,
ReasoningEffort::Medium,

View file

@ -23,6 +23,10 @@ Zed's plans offer hosted versions of major LLMs with higher rate limits than dir
| | Anthropic | Output | $25.00 | $27.50 |
| | Anthropic | Input - Cache Write | $6.25 | $6.875 |
| | Anthropic | Input - Cache Read | $0.50 | $0.55 |
| Claude Opus 4.8 | Anthropic | Input | $5.00 | $5.50 |
| | Anthropic | Output | $25.00 | $27.50 |
| | Anthropic | Input - Cache Write | $6.25 | $6.875 |
| | Anthropic | Input - Cache Read | $0.50 | $0.55 |
| Claude Sonnet 4.5 | Anthropic | Input | $3.00 | $3.30 |
| | Anthropic | Output | $15.00 | $16.50 |
| | Anthropic | Input - Cache Write | $3.75 | $4.125 |
@ -81,7 +85,7 @@ Zed's plans offer hosted versions of major LLMs with higher rate limits than dir
As of February 19, 2026, Zed Pro serves newer model versions in place of the retired models below:
- Claude Opus 4.1 → Claude Opus 4.5, Claude Opus 4.6, or Claude Opus 4.7
- Claude Opus 4.1 → Claude Opus 4.5, Claude Opus 4.6, Claude Opus 4.7, or Claude Opus 4.8
- Claude Sonnet 4 → Claude Sonnet 4.5 or Claude Sonnet 4.6
- Claude Sonnet 3.7 (retired Feb 19) → Claude Sonnet 4.5 or Claude Sonnet 4.6
- GPT-5.1 and GPT-5 → GPT-5.2 or GPT-5.2-Codex
@ -106,6 +110,7 @@ A context window is the maximum span of text and code an LLM can consider at onc
| Claude Opus 4.5 | Anthropic | 200k |
| Claude Opus 4.6 | Anthropic | 1M |
| Claude Opus 4.7 | Anthropic | 1M |
| Claude Opus 4.8 | Anthropic | 1M |
| Claude Sonnet 4.5 | Anthropic | 200k |
| Claude Sonnet 4.6 | Anthropic | 1M |
| Claude Haiku 4.5 | Anthropic | 200k |