Add Sonnet 4.5 support (#39127)

Richard Feldman created

Release Notes:

- Added support for Claude Sonnet 4.5 for Bring-Your-Own-Key (BYOK)

Change summary

crates/anthropic/src/anthropic.rs | 30 ++++++++++++++++++
crates/bedrock/src/models.rs      | 53 +++++++++++++++++++++++++++++---
2 files changed, 78 insertions(+), 5 deletions(-)

Detailed changes

crates/anthropic/src/anthropic.rs 🔗

@@ -56,6 +56,13 @@ pub enum Model {
         alias = "claude-sonnet-4-thinking-latest"
     )]
     ClaudeSonnet4Thinking,
+    #[serde(rename = "claude-sonnet-4-5", alias = "claude-sonnet-4-5-latest")]
+    ClaudeSonnet4_5,
+    #[serde(
+        rename = "claude-sonnet-4-5-thinking",
+        alias = "claude-sonnet-4-5-thinking-latest"
+    )]
+    ClaudeSonnet4_5Thinking,
     #[serde(rename = "claude-3-7-sonnet", alias = "claude-3-7-sonnet-latest")]
     Claude3_7Sonnet,
     #[serde(
@@ -114,6 +121,14 @@ impl Model {
             return Ok(Self::ClaudeOpus4);
         }
 
+        if id.starts_with("claude-sonnet-4-5-thinking") {
+            return Ok(Self::ClaudeSonnet4_5Thinking);
+        }
+
+        if id.starts_with("claude-sonnet-4-5") {
+            return Ok(Self::ClaudeSonnet4_5);
+        }
+
         if id.starts_with("claude-sonnet-4-thinking") {
             return Ok(Self::ClaudeSonnet4Thinking);
         }
@@ -161,6 +176,8 @@ impl Model {
             Self::ClaudeOpus4_1Thinking => "claude-opus-4-1-thinking-latest",
             Self::ClaudeSonnet4 => "claude-sonnet-4-latest",
             Self::ClaudeSonnet4Thinking => "claude-sonnet-4-thinking-latest",
+            Self::ClaudeSonnet4_5 => "claude-sonnet-4-5-latest",
+            Self::ClaudeSonnet4_5Thinking => "claude-sonnet-4-5-thinking-latest",
             Self::Claude3_5Sonnet => "claude-3-5-sonnet-latest",
             Self::Claude3_7Sonnet => "claude-3-7-sonnet-latest",
             Self::Claude3_7SonnetThinking => "claude-3-7-sonnet-thinking-latest",
@@ -178,6 +195,7 @@ impl Model {
             Self::ClaudeOpus4 | Self::ClaudeOpus4Thinking => "claude-opus-4-20250514",
             Self::ClaudeOpus4_1 | Self::ClaudeOpus4_1Thinking => "claude-opus-4-1-20250805",
             Self::ClaudeSonnet4 | Self::ClaudeSonnet4Thinking => "claude-sonnet-4-20250514",
+            Self::ClaudeSonnet4_5 | Self::ClaudeSonnet4_5Thinking => "claude-sonnet-4-5-20250929",
             Self::Claude3_5Sonnet => "claude-3-5-sonnet-latest",
             Self::Claude3_7Sonnet | Self::Claude3_7SonnetThinking => "claude-3-7-sonnet-latest",
             Self::Claude3_5Haiku => "claude-3-5-haiku-latest",
@@ -196,6 +214,8 @@ impl Model {
             Self::ClaudeOpus4_1Thinking => "Claude Opus 4.1 Thinking",
             Self::ClaudeSonnet4 => "Claude Sonnet 4",
             Self::ClaudeSonnet4Thinking => "Claude Sonnet 4 Thinking",
+            Self::ClaudeSonnet4_5 => "Claude Sonnet 4.5",
+            Self::ClaudeSonnet4_5Thinking => "Claude Sonnet 4.5 Thinking",
             Self::Claude3_7Sonnet => "Claude 3.7 Sonnet",
             Self::Claude3_5Sonnet => "Claude 3.5 Sonnet",
             Self::Claude3_7SonnetThinking => "Claude 3.7 Sonnet Thinking",
@@ -217,6 +237,8 @@ impl Model {
             | Self::ClaudeOpus4_1Thinking
             | Self::ClaudeSonnet4
             | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5
+            | Self::ClaudeSonnet4_5Thinking
             | Self::Claude3_5Sonnet
             | Self::Claude3_5Haiku
             | Self::Claude3_7Sonnet
@@ -242,6 +264,8 @@ impl Model {
             | Self::ClaudeOpus4_1Thinking
             | Self::ClaudeSonnet4
             | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5
+            | Self::ClaudeSonnet4_5Thinking
             | Self::Claude3_5Sonnet
             | Self::Claude3_5Haiku
             | Self::Claude3_7Sonnet
@@ -261,6 +285,8 @@ impl Model {
             | Self::ClaudeOpus4_1Thinking
             | Self::ClaudeSonnet4
             | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5
+            | Self::ClaudeSonnet4_5Thinking
             | Self::Claude3_5Sonnet
             | Self::Claude3_7Sonnet
             | Self::Claude3_7SonnetThinking
@@ -280,6 +306,8 @@ impl Model {
             | Self::ClaudeOpus4_1Thinking
             | Self::ClaudeSonnet4
             | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5
+            | Self::ClaudeSonnet4_5Thinking
             | Self::Claude3_5Sonnet
             | Self::Claude3_7Sonnet
             | Self::Claude3_7SonnetThinking
@@ -299,6 +327,7 @@ impl Model {
             Self::ClaudeOpus4
             | Self::ClaudeOpus4_1
             | Self::ClaudeSonnet4
+            | Self::ClaudeSonnet4_5
             | Self::Claude3_5Sonnet
             | Self::Claude3_7Sonnet
             | Self::Claude3_5Haiku
@@ -308,6 +337,7 @@ impl Model {
             Self::ClaudeOpus4Thinking
             | Self::ClaudeOpus4_1Thinking
             | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5Thinking
             | Self::Claude3_7SonnetThinking => AnthropicModelMode::Thinking {
                 budget_tokens: Some(4_096),
             },

crates/bedrock/src/models.rs 🔗

@@ -30,6 +30,13 @@ pub enum Model {
         alias = "claude-sonnet-4-thinking-latest"
     )]
     ClaudeSonnet4Thinking,
+    #[serde(rename = "claude-sonnet-4-5", alias = "claude-sonnet-4-5-latest")]
+    ClaudeSonnet4_5,
+    #[serde(
+        rename = "claude-sonnet-4-5-thinking",
+        alias = "claude-sonnet-4-5-thinking-latest"
+    )]
+    ClaudeSonnet4_5Thinking,
     #[serde(rename = "claude-opus-4", alias = "claude-opus-4-latest")]
     ClaudeOpus4,
     #[serde(rename = "claude-opus-4-1", alias = "claude-opus-4-1-latest")]
@@ -144,6 +151,14 @@ impl Model {
             Ok(Self::Claude3_7Sonnet)
         } else if id.starts_with("claude-3-7-sonnet-thinking") {
             Ok(Self::Claude3_7SonnetThinking)
+        } else if id.starts_with("claude-sonnet-4-5-thinking") {
+            Ok(Self::ClaudeSonnet4_5Thinking)
+        } else if id.starts_with("claude-sonnet-4-5") {
+            Ok(Self::ClaudeSonnet4_5)
+        } else if id.starts_with("claude-sonnet-4-thinking") {
+            Ok(Self::ClaudeSonnet4Thinking)
+        } else if id.starts_with("claude-sonnet-4") {
+            Ok(Self::ClaudeSonnet4)
         } else {
             anyhow::bail!("invalid model id {id}");
         }
@@ -153,6 +168,8 @@ impl Model {
         match self {
             Model::ClaudeSonnet4 => "claude-sonnet-4",
             Model::ClaudeSonnet4Thinking => "claude-sonnet-4-thinking",
+            Model::ClaudeSonnet4_5 => "claude-sonnet-4-5",
+            Model::ClaudeSonnet4_5Thinking => "claude-sonnet-4-5-thinking",
             Model::ClaudeOpus4 => "claude-opus-4",
             Model::ClaudeOpus4_1 => "claude-opus-4-1",
             Model::ClaudeOpus4Thinking => "claude-opus-4-thinking",
@@ -214,6 +231,9 @@ impl Model {
             Model::ClaudeSonnet4 | Model::ClaudeSonnet4Thinking => {
                 "anthropic.claude-sonnet-4-20250514-v1:0"
             }
+            Model::ClaudeSonnet4_5 | Model::ClaudeSonnet4_5Thinking => {
+                "anthropic.claude-sonnet-4-5-20250929-v1:0"
+            }
             Model::ClaudeOpus4 | Model::ClaudeOpus4Thinking => {
                 "anthropic.claude-opus-4-20250514-v1:0"
             }
@@ -277,6 +297,8 @@ impl Model {
         match self {
             Self::ClaudeSonnet4 => "Claude Sonnet 4",
             Self::ClaudeSonnet4Thinking => "Claude Sonnet 4 Thinking",
+            Self::ClaudeSonnet4_5 => "Claude Sonnet 4.5",
+            Self::ClaudeSonnet4_5Thinking => "Claude Sonnet 4.5 Thinking",
             Self::ClaudeOpus4 => "Claude Opus 4",
             Self::ClaudeOpus4_1 => "Claude Opus 4.1",
             Self::ClaudeOpus4Thinking => "Claude Opus 4 Thinking",
@@ -346,6 +368,8 @@ impl Model {
             | Self::ClaudeOpus4
             | Self::ClaudeOpus4_1
             | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5
+            | Self::ClaudeSonnet4_5Thinking
             | Self::ClaudeOpus4Thinking
             | Self::ClaudeOpus4_1Thinking => 200_000,
             Self::AmazonNovaPremier => 1_000_000,
@@ -361,6 +385,7 @@ impl Model {
             Self::Claude3Opus | Self::Claude3Sonnet | Self::Claude3_5Haiku => 4_096,
             Self::Claude3_7Sonnet | Self::Claude3_7SonnetThinking => 128_000,
             Self::ClaudeSonnet4 | Self::ClaudeSonnet4Thinking => 64_000,
+            Self::ClaudeSonnet4_5 | Self::ClaudeSonnet4_5Thinking => 64_000,
             Self::ClaudeOpus4
             | Self::ClaudeOpus4Thinking
             | Self::ClaudeOpus4_1
@@ -385,7 +410,9 @@ impl Model {
             | Self::ClaudeOpus4_1
             | Self::ClaudeOpus4_1Thinking
             | Self::ClaudeSonnet4
-            | Self::ClaudeSonnet4Thinking => 1.0,
+            | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5
+            | Self::ClaudeSonnet4_5Thinking => 1.0,
             Self::Custom {
                 default_temperature,
                 ..
@@ -409,6 +436,8 @@ impl Model {
             | Self::ClaudeOpus4_1Thinking
             | Self::ClaudeSonnet4
             | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5
+            | Self::ClaudeSonnet4_5Thinking
             | Self::Claude3_5Haiku => true,
 
             // Amazon Nova models (all support tool use)
@@ -439,6 +468,8 @@ impl Model {
             | Self::Claude3_7SonnetThinking
             | Self::ClaudeSonnet4
             | Self::ClaudeSonnet4Thinking
+            | Self::ClaudeSonnet4_5
+            | Self::ClaudeSonnet4_5Thinking
             | Self::ClaudeOpus4
             | Self::ClaudeOpus4Thinking
             | Self::ClaudeOpus4_1
@@ -488,9 +519,11 @@ impl Model {
             Model::Claude3_7SonnetThinking => BedrockModelMode::Thinking {
                 budget_tokens: Some(4096),
             },
-            Model::ClaudeSonnet4Thinking => BedrockModelMode::Thinking {
-                budget_tokens: Some(4096),
-            },
+            Model::ClaudeSonnet4Thinking | Model::ClaudeSonnet4_5Thinking => {
+                BedrockModelMode::Thinking {
+                    budget_tokens: Some(4096),
+                }
+            }
             Model::ClaudeOpus4Thinking | Model::ClaudeOpus4_1Thinking => {
                 BedrockModelMode::Thinking {
                     budget_tokens: Some(4096),
@@ -542,6 +575,8 @@ impl Model {
                 | Model::Claude3_7SonnetThinking
                 | Model::ClaudeSonnet4
                 | Model::ClaudeSonnet4Thinking
+                | Model::ClaudeSonnet4_5
+                | Model::ClaudeSonnet4_5Thinking
                 | Model::ClaudeOpus4
                 | Model::ClaudeOpus4Thinking
                 | Model::ClaudeOpus4_1
@@ -575,6 +610,8 @@ impl Model {
                 | Model::Claude3_7SonnetThinking
                 | Model::ClaudeSonnet4
                 | Model::ClaudeSonnet4Thinking
+                | Model::ClaudeSonnet4_5
+                | Model::ClaudeSonnet4_5Thinking
                 | Model::Claude3Haiku
                 | Model::Claude3Sonnet
                 | Model::MetaLlama321BInstructV1
@@ -592,7 +629,9 @@ impl Model {
                 | Model::Claude3_7Sonnet
                 | Model::Claude3_7SonnetThinking
                 | Model::ClaudeSonnet4
-                | Model::ClaudeSonnet4Thinking,
+                | Model::ClaudeSonnet4Thinking
+                | Model::ClaudeSonnet4_5
+                | Model::ClaudeSonnet4_5Thinking,
                 "apac",
             ) => Ok(format!("{}.{}", region_group, model_id)),
 
@@ -631,6 +670,10 @@ mod tests {
             Model::ClaudeSonnet4.cross_region_inference_id("eu-west-1")?,
             "eu.anthropic.claude-sonnet-4-20250514-v1:0"
         );
+        assert_eq!(
+            Model::ClaudeSonnet4_5.cross_region_inference_id("eu-west-1")?,
+            "eu.anthropic.claude-sonnet-4-5-20250929-v1:0"
+        );
         assert_eq!(
             Model::Claude3Sonnet.cross_region_inference_id("eu-west-1")?,
             "eu.anthropic.claude-3-sonnet-20240229-v1:0"